Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / openmp / runtime / tools / check-depends.pl
blobaca888b331e2b6d9c0dbf1959246e13d6bcde6bf
1 #!/usr/bin/env perl
4 #//===----------------------------------------------------------------------===//
5 #//
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
9 #//
10 #//===----------------------------------------------------------------------===//
13 use strict;
14 use warnings;
16 use FindBin;
17 use lib "$FindBin::Bin/lib";
19 use tools;
21 our $VERSION = "0.005";
22 my $target_os;
23 my $target_arch;
25 # --------------------------------------------------------------------------------------------------
26 # Output parse error.
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 ) = @_;
32 my @bulk;
33 for ( my $i = 0; $i < @$bulk; ++ $i ) {
34 push( @bulk, ( $i == $n ? ">>> " : " " ) . $bulk->[ $i ] );
35 }; # for $i
36 runtime_error( "Fail to parse $tool output:", @bulk, "(eof)" );
37 }; # sub parse_error
40 # --------------------------------------------------------------------------------------------------
41 # Linux* OS version of get_deps() parses output of ldd:
43 # $ ldd libname.so
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.
53 sub get_deps_ldd($) {
55 my $lib = shift ( @_ );
56 my $tool = "ldd";
57 my @bulk;
58 my @deps;
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 );
67 }; # if
68 my $dep = ( defined( $1 ) ? $1 : $2 );
69 push( @deps, $dep );
70 }; # foreach $i
72 return @deps;
74 }; # sub get_deps_ldd
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:
83 # Tag Type Name/Value
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
91 # ...
93 # Note: In contrast to ldd, readelf shows only direct dependencies.
95 sub get_deps_readelf($) {
97 my $file = shift ( @_ );
98 my $tool;
99 my @bulk;
100 my @deps;
102 if($target_arch eq "mic") {
103 $tool = "x86_64-k1om-linux-readelf";
104 } else {
105 $tool = "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
111 $ENV{ LANG } = "C";
113 execute( [ $tool, "-d", $file ], -stdout => \@bulk );
114 debug( @bulk, "(eof)" );
116 my $i = 0;
117 # Parse header.
118 ( $i < @bulk and $bulk[ $i ] =~ m{^\s*$} )
119 or parse_error( $tool, @bulk, $i );
120 ++ $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.
123 return @deps;
124 }; # if
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 );
127 ++ $i;
128 ( $i < @bulk and $bulk[ $i ] =~ m{^\s*Tag\s+Type\s+Name/Value\s*$} )
129 or parse_error( $tool, @bulk, $i );
130 ++ $i;
131 # Parse body.
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 );
136 }; # if
137 my ( $type, $value ) = ( $1, $2 );
138 if ( $type eq "NEEDED" ) {
139 if ( $value !~ m{\AShared library: \[(.*)\]\z} ) {
140 parse_error( $tool, @bulk, $i );
141 }; # if
142 my $dep = $1;
143 push( @deps, $dep );
144 }; # if
145 ++ $i;
146 }; # foreach $i
148 return @deps;
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 );
165 my $tool = "otool";
166 my @bulk;
167 my @deps;
169 if ( $target_arch eq "32e" ) {
170 # On older (Tiger) systems otool does not recognize 64-bit binaries, so try to locate
171 # otool64.
172 my $path = which( "otool64" );
173 if ( defined ( $path ) ) {
174 $tool = "otool64";
175 }; # if
176 }; # if
178 execute( [ $tool, "-L", $file ], -stdout => \@bulk );
179 debug( @bulk, "(eof)" );
181 my $i = 0;
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 );
185 ++ $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 );
192 ++ $i;
193 }; # if
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 );
200 }; # if
201 my ( $dep ) = ( $1 );
202 push( @deps, $dep );
203 ++ $i;
204 }; # while
206 return @deps;
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
218 # File Type: DLL
219 # Image has the following dependencies:
220 # KERNEL32.dll
221 # Summary
222 # C000 .data
223 # 6000 .pdata
224 # 18000 .rdata
225 # ...
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
231 # File Type: LIBRARY
232 # Linker Directives
233 # -----------------
234 # -defaultlib:"uuid.lib"
235 # -defaultlib:"uuid.lib"
236 # .....
237 # Summary
238 # 3250 .bss
239 # 3FBC .data
240 # 34 .data1
241 # ....
242 sub get_deps_link($) {
244 my ( $lib ) = @_;
245 my $tool = "link";
246 my @bulk;
247 my @deps;
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" );
252 }; # if
254 execute(
255 [ $tool, "/dump", ( $ext eq ".lib" ? "/directives" : "/dependents" ), $lib ],
256 -stdout => \@bulk
259 debug( @bulk, "(eof)" );
261 my $i = 0;
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" ) {
273 my %deps;
274 while ( $i < @bulk ) {
275 my $line = $bulk[ $i ];
276 if ( 0 ) {
277 } elsif ( $line =~ m{^\s*[-/]defaultlib\:(.*)\s*$}i ) {
278 my $dep = $1;
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).
283 $deps{ $dep } = 1;
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*$} ) {
291 last;
292 } else {
293 parse_error( $tool, @bulk, $i );
294 }; # if
295 ++ $i;
296 } # while
297 @deps = keys( %deps );
299 } else {
301 ( $i < @bulk and $bulk[ $i ] =~ m{\s*Image has the following dependencies\:$} )
302 or parse_error( $tool, @bulk, $i );
303 ++ $i;
304 while ( $i < @bulk ) {
305 my $line = $bulk[ $i ];
306 if ( 0 ) {
307 } elsif ( $line =~ m{^\s*$} ) {
308 # Ignore empty lines.
309 } elsif ( $line =~ m{^\s*(.*\.dll)$}i ) {
310 my $dep = lc( $1 );
311 push( @deps, $dep );
312 } elsif ( $line =~ m{^\s*Summary$} ) {
313 last;
314 } else {
315 parse_error( $tool, @bulk, $i );
316 }; # if
317 ++ $i;
318 }; # while
320 }; # if
322 return @deps;
324 }; # sub get_deps_link
327 # --------------------------------------------------------------------------------------------------
328 # Main.
329 # --------------------------------------------------------------------------------------------------
331 # Parse command line.
332 my $expected;
333 my $bare;
334 Getopt::Long::Configure( "permute" );
335 get_options(
336 "os=s" => \$target_os,
337 "arch=s" => \$target_arch,
338 "bare" => \$bare,
339 "expected=s" => \$expected,
341 my @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 );
347 }; # if
348 }; # if
349 }; # if
350 if ( @ARGV < 1 ) {
351 cmdline_error( "Specify a library name to check for dependencies" );
352 }; # if
353 if ( @ARGV > 1 ) {
354 cmdline_error( "Too many arguments" );
355 }; # if
356 my $lib = shift( @ARGV );
357 if ( not -e $lib ){
358 runtime_error( "Specified file does not exist: \"$lib\"" );
359 }; # if
361 # Select appropriate get_deps implementation.
362 if ( 0 ) {
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;
369 } else {
370 runtime_error( "OS \"$target_os\" not supported" );
371 }; # if
373 # Do the work.
374 my @deps = sort( get_deps( $lib ) );
375 if ( $bare ) {
376 print( map( "$_\n", @deps ) );
377 } else {
378 info( "Dependencies:", @deps ? map( " $_", @deps ) : "(none)" );
379 }; # if
380 if ( defined( $expected ) ) {
381 my %deps = map( ( $_ => 1 ), @deps );
382 foreach my $dep ( @expected ) {
383 delete( $deps{ $dep } );
384 }; # foreach
385 my @unexpected = sort( keys( %deps ) );
386 if ( @unexpected ) {
387 runtime_error( "Unexpected dependencies:", map( " $_", @unexpected ) );
388 }; # if
389 }; # if
391 exit( 0 );
393 __END__
395 =pod
397 =head1 NAME
399 B<check-depends.pl> -- Check dependencies for a specified library.
401 =head1 SYNOPSIS
403 B<check-depends.pl> I<OPTIONS>... I<library>
405 =head1 DESCRIPTION
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.
420 =head1 OPTIONS
422 =over
424 =item B<--bare>
426 Do not use fancy formatting; produce plain, bare output: just a list of libraries,
427 a library per line.
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.
435 =item B<--os=>I<str>
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>.
441 =back
443 =head2 Standard Options
445 =over
447 =item B<--help>
449 Print short help message and exit.
451 =item B<--doc>
453 =item B<--manual>
455 Print full documentation and exit.
457 =item B<--quiet>
459 Do not output informational messages.
461 =item B<--version>
463 Print version and exit.
465 =back
467 =head1 ARGUMENTS
469 =over
471 =item I<library>
473 A name of library to find or check dependencies.
475 =back
477 =head1 EXAMPLES
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
488 libc.so.6
489 libdl.so.2
490 libpthread.so.0
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
499 $ echo $?
502 =cut
504 # end of file #