4 #//===----------------------------------------------------------------------===//
6 #// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
7 #// See https://llvm.org/LICENSE.txt for license information.
8 #// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
10 #//===----------------------------------------------------------------------===//
17 use lib
"$FindBin::Bin/lib";
21 our $VERSION = "0.005";
25 # --------------------------------------------------------------------------------------------------
27 # $tool -- Name of tool.
28 # @bulk -- Output of the tool.
29 # $n -- Number of line caused parse error.
30 sub parse_error
($\@
$) {
31 my ( $tool, $bulk, $n ) = @_;
33 for ( my $i = 0; $i < @
$bulk; ++ $i ) {
34 push( @bulk, ( $i == $n ?
">>> " : " " ) . $bulk->[ $i ] );
36 runtime_error
( "Fail to parse $tool output:", @bulk, "(eof)" );
40 # --------------------------------------------------------------------------------------------------
41 # Linux* OS version of get_deps() parses output of ldd:
44 # libc.so.6 => /lib64/libc.so.6 (0x00002b60fedd8000)
45 # libdl.so.2 => /lib64/libdl.so.2 (0x00002b60ff12b000)
46 # libpthread.so.0 => /lib64/libpthread.so.0 (0x00002b60ff32f000)
47 # /lib64/ld-linux-x86-64.so.2 (0x0000003879400000)
49 # Note: ldd printd all the dependencies, direct and indirect. (For example, if specified library
50 # requires libdl.so, and libdl.so requires /lib/ld-linux.so, ldd prints both libdl.so and
51 # /lib/ld-linux.so). If you do not want indirect dependencies, look at readelf tool.
55 my $lib = shift ( @_ );
60 execute
( [ $tool, $lib ], -stdout
=> \
@bulk );
61 debug
( @bulk, "(eof)" );
63 foreach my $i ( 0 .. @bulk - 1 ) {
64 my $line = $bulk[ $i ];
65 if ( $line !~ m{^\s*(?:([_a-z0-9.+-/]*)\s+=>\s+)?([_a-z0-9.+-/]*)\s+\(0x[0-9a-z]*\)$}i ) {
66 parse_error
( $tool, @bulk, $i );
68 my $dep = ( defined( $1 ) ?
$1 : $2 );
77 # --------------------------------------------------------------------------------------------------
78 # Another Linux* OS version of get_deps() parses output of readelf:
80 # $ readelf -d exports/lin_32e/lib/libomp.so
82 # Dynamic segment at offset 0x87008 contains 24 entries:
84 # 0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
85 # 0x0000000000000001 (NEEDED) Shared library: [libdl.so.2]
86 # 0x0000000000000001 (NEEDED) Shared library: [libpthread.so.0]
87 # 0x000000000000000e (SONAME) Library soname: [libomp.so]
88 # 0x000000000000000d (FINI) 0x51caa
89 # 0x0000000000000004 (HASH) 0x158
90 # 0x0000000000000005 (STRTAB) 0x9350
93 # Note: In contrast to ldd, readelf shows only direct dependencies.
95 sub get_deps_readelf
($) {
97 my $file = shift ( @_ );
102 if($target_arch eq "mic") {
103 $tool = "x86_64-k1om-linux-readelf";
108 # Force the readelf call to be in English. For example, when readelf
109 # is called on a french localization, it will find "Librairie partagees"
110 # instead of shared library
113 execute
( [ $tool, "-d", $file ], -stdout
=> \
@bulk );
114 debug
( @bulk, "(eof)" );
118 ( $i < @bulk and $bulk[ $i ] =~ m{^\s*$} )
119 or parse_error
( $tool, @bulk, $i );
121 if ( $i == @bulk - 1 and $bulk[ $i ] =~ m{^There is no dynamic section in this file\.\s*$} ) {
122 # This is not dynamic executable => no dependencies.
125 ( $i < @bulk and $bulk[ $i ] =~ m{^Dynamic (?:segment|section) at offset 0x[0-9a-f]+ contains \d+ entries:\s*$} )
126 or parse_error
( $tool, @bulk, $i );
128 ( $i < @bulk and $bulk[ $i ] =~ m{^\s*Tag\s+Type\s+Name/Value\s*$} )
129 or parse_error
( $tool, @bulk, $i );
132 while ( $i < @bulk ) {
133 my $line = $bulk[ $i ];
134 if ( $line !~ m{^\s*0x[0-9a-f]+\s+\(?([_A-Z0-9]+)\)?\s+(.*)\s*$}i ) {
135 parse_error
( $tool, @bulk, $i );
137 my ( $type, $value ) = ( $1, $2 );
138 if ( $type eq "NEEDED" ) {
139 if ( $value !~ m{\AShared library: \[(.*)\]\z} ) {
140 parse_error
( $tool, @bulk, $i );
150 }; # sub get_deps_readelf
153 # --------------------------------------------------------------------------------------------------
154 # OS X* version of get_deps() parses output of otool:
156 # $ otool -L libname.dylib
157 # exports/mac_32/lib.thin/libomp.dylib:
158 # libomp.dylib (compatibility version 5.0.0, current version 5.0.0)
159 # /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 88.1.3)
161 sub get_deps_otool
($) {
163 my $file = shift ( @_ );
164 my $name = get_file
( $file );
169 if ( $target_arch eq "32e" ) {
170 # On older (Tiger) systems otool does not recognize 64-bit binaries, so try to locate
172 my $path = which
( "otool64" );
173 if ( defined ( $path ) ) {
178 execute
( [ $tool, "-L", $file ], -stdout
=> \
@bulk );
179 debug
( @bulk, "(eof)" );
182 # Parse the first one or two lines separately.
183 ( $i < @bulk and $bulk[ $i ] =~ m{^\Q$file\E:$} )
184 or parse_error
( $tool, @bulk, $i );
186 if ( $name =~ m{\.dylib\z} ) {
187 # Added "@rpath/" enables dynamic load of the library designated at link time.
188 $name = '@rpath/' . $name;
189 # In case of dynamic library otool print the library itself as a dependent library.
190 ( $i < @bulk and $bulk[ $i ] =~ m{^\s+\Q$name\E\s+\(compatibility version.*\)$} )
191 or parse_error
( $tool, @bulk, $i );
195 # Then parse the rest.
196 while ( $i < @bulk ) {
197 my $line = $bulk[ $i ];
198 if ( $line !~ m/^\s*(.*)\s+\(compatibility version\s.*\)$/ ) {
199 parse_error
( $tool, @bulk, $i );
201 my ( $dep ) = ( $1 );
208 }; # sub get_deps_otool
211 # --------------------------------------------------------------------------------------------------
212 # Windows* OS version of get_deps() parses output of link:
214 # > link -dump -dependents libname.dll
215 # Microsoft (R) COFF/PE Dumper Version 8.00.40310.39
216 # Copyright (C) Microsoft Corporation. All rights reserved.
217 # Dump of file S:\Projects.OMP\users\omalyshe\omp\libomp\exports\win_64\lib\libompmd.dll
219 # Image has the following dependencies:
227 # > link -dump -directives libname.lib
228 # Microsoft (R) COFF/PE Dumper Version 8.00.40310.39
229 # Copyright (C) Microsoft Corporation. All rights reserved.
230 # Dump of file S:\Projects.OMP\users\omalyshe\omp\libomp\exports\win_32e\lib\libimp5mt.lib
234 # -defaultlib:"uuid.lib"
235 # -defaultlib:"uuid.lib"
242 sub get_deps_link
($) {
249 my $ext = lc( get_ext
( $lib ) );
250 if ( $ext !~ m{\A\.(?:lib|dll|exe)\z}i ) {
251 runtime_error
( "Incorrect file is specified: `$lib'; only `lib', `dll' or `exe' file expected" );
255 [ $tool, "/dump", ( $ext eq ".lib" ?
"/directives" : "/dependents" ), $lib ],
259 debug
( @bulk, "(eof)" );
262 ( $i < @bulk and $bulk[ $i ] =~ m{^Microsoft \(R\) COFF\/PE Dumper Version.*$} ) or parse_error
( $tool, @bulk, $i ); ++ $i;
263 ( $i < @bulk and $bulk[ $i ] =~ m{^Copyright \(C\) Microsoft Corporation\..*$} ) or parse_error
( $tool, @bulk, $i ); ++ $i;
264 ( $i < @bulk and $bulk[ $i ] =~ m{^\s*$} ) or parse_error
( $tool, @bulk, $i ); ++ $i;
265 ( $i < @bulk and $bulk[ $i ] =~ m{^\s*$} ) or parse_error
( $tool, @bulk, $i ); ++ $i;
266 ( $i < @bulk and $bulk[ $i ] =~ m{^Dump of file\s\Q$lib\E$} ) or parse_error
( $tool, @bulk, $i ); ++ $i;
267 ( $i < @bulk and $bulk[ $i ] =~ m{^\s*$} ) or parse_error
( $tool, @bulk, $i ); ++ $i;
268 ( $i < @bulk and $bulk[ $i ] =~ m{^File Type:\s(.*)$} ) or parse_error
( $tool, @bulk, $i ); ++ $i;
269 ( $i < @bulk and $bulk[ $i ] =~ m{^\s*$} ) or parse_error
( $tool, @bulk, $i ); ++ $i;
271 if ( $ext eq ".lib" ) {
274 while ( $i < @bulk ) {
275 my $line = $bulk[ $i ];
277 } elsif ( $line =~ m{^\s*[-/]defaultlib\:(.*)\s*$}i ) {
279 # Normalize library name:
280 $dep = lc( $1 ); # Convert to lower case.
281 $dep =~ s{\A"(.*)"\z}{$1}; # Drop surrounding quotes (if any).
282 $dep =~ s{\.lib\z}{}; # Drop .lib suffix (if any).
284 } elsif ( $line =~ m{^\s*Linker Directives\s*$} ) {
285 } elsif ( $line =~ m{^\s*-+\s*$} ) {
286 } elsif ( $line =~ m{^\s*/alternatename\:.*$} ) {
287 } elsif ( $line =~ m{^\s*$} ) {
288 } elsif ( $line =~ m{^\s*/FAILIFMISMATCH\:.*$} ) {
289 # This directive is produced only by _MSC_VER=1600
290 } elsif ( $line =~ m{^\s*Summary\s*$} ) {
293 parse_error
( $tool, @bulk, $i );
297 @deps = keys( %deps );
301 ( $i < @bulk and $bulk[ $i ] =~ m{\s*Image has the following dependencies\:$} )
302 or parse_error
( $tool, @bulk, $i );
304 while ( $i < @bulk ) {
305 my $line = $bulk[ $i ];
307 } elsif ( $line =~ m{^\s*$} ) {
308 # Ignore empty lines.
309 } elsif ( $line =~ m{^\s*(.*\.dll)$}i ) {
312 } elsif ( $line =~ m{^\s*Summary$} ) {
315 parse_error
( $tool, @bulk, $i );
324 }; # sub get_deps_link
327 # --------------------------------------------------------------------------------------------------
329 # --------------------------------------------------------------------------------------------------
331 # Parse command line.
334 Getopt
::Long
::Configure
( "permute" );
336 "os=s" => \
$target_os,
337 "arch=s" => \
$target_arch,
339 "expected=s" => \
$expected,
342 if ( defined( $expected ) ) {
343 if ( $expected ne "none" ) {
344 @expected = sort( split( ",", $expected ) );
345 if ( $target_os eq "win" ) {
346 @expected = map( lc( $_ ), @expected );
351 cmdline_error
( "Specify a library name to check for dependencies" );
354 cmdline_error
( "Too many arguments" );
356 my $lib = shift( @ARGV );
358 runtime_error
( "Specified file does not exist: \"$lib\"" );
361 # Select appropriate get_deps implementation.
363 } elsif ( $target_os eq "lin" ) {
364 *get_deps
= \
*get_deps_readelf
;
365 } elsif ( $target_os eq "mac" ) {
366 *get_deps
= \
*get_deps_otool
;
367 } elsif ( $target_os eq "win" ) {
368 *get_deps
= \
*get_deps_link
;
370 runtime_error
( "OS \"$target_os\" not supported" );
374 my @deps = sort( get_deps
( $lib ) );
376 print( map( "$_\n", @deps ) );
378 info
( "Dependencies:", @deps ?
map( " $_", @deps ) : "(none)" );
380 if ( defined( $expected ) ) {
381 my %deps = map( ( $_ => 1 ), @deps );
382 foreach my $dep ( @expected ) {
383 delete( $deps{ $dep } );
385 my @unexpected = sort( keys( %deps ) );
387 runtime_error
( "Unexpected dependencies:", map( " $_", @unexpected ) );
399 B<check-depends.pl> -- Check dependencies for a specified library.
403 B<check-depends.pl> I<OPTIONS>... I<library>
407 C<check-depends.pl> finds direct dependencies for a specified library. List of actual dependencies
408 is sorted alphabetically and printed. If list of expected dependencies is specified, the scripts
409 checks the library has only allowed dependencies. In case of not expected dependencies. the script
410 issues error message and exits with non-zero code.
412 Linux* OS and OS X*: The script finds dependencies only for dynamic libraries. Windows* OS: The script
413 finds dependencies for either static or dynamic libraries.
415 The script uses external tools. On Linux* OS, it runs F<readelf>, on OS X* -- F<otool> (or F<otool64>),
416 on Windows* OS -- F<link>.
418 On Windows* OS dependencies are printed in lower case, case of expected dependencies ignored.
426 Do not use fancy formatting; produce plain, bare output: just a list of libraries,
429 =item B<--expected=>I<list>
431 I<list> is comma-separated list of expected dependencies (or C<none>).
432 If C<--expected> option specified, C<check-depends.pl> checks the specified library
433 has only expected dependencies.
437 Specify target OS (tool to use) manually.
438 Useful for cross-build, when host OS is not the same as target OS.
439 I<str> should be either C<lin>, C<mac>, or C<win>.
443 =head2 Standard Options
449 Print short help message and exit.
455 Print full documentation and exit.
459 Do not output informational messages.
463 Print version and exit.
473 A name of library to find or check dependencies.
479 Just print library dependencies (Windows* OS):
481 > check-depends.pl exports/win_32/lib/libompmd.dll
482 check-depends.pl: (i) Dependencies:
483 check-depends.pl: (i) kernel32.dll
485 Print library dependencies, use bare output (Linux* OS):
487 $ check-depends.pl --bare exports/lin_32e/lib/libomp_db.so
492 Check the library does not have any dependencies (OS X*):
494 $ check-depends.pl --expected=none exports/mac_32/lib/libomp.dylib
495 check-depends.pl: (i) Dependencies:
496 check-depends.pl: (i) /usr/lib/libSystem.B.dylib
497 check-depends.pl: (x) Unexpected dependencies:
498 check-depends.pl: (x) /usr/lib/libSystem.B.dylib