aboutsummaryrefslogtreecommitdiff
path: root/final/runtime/tools/check-depends.pl
diff options
context:
space:
mode:
Diffstat (limited to 'final/runtime/tools/check-depends.pl')
-rwxr-xr-xfinal/runtime/tools/check-depends.pl506
1 files changed, 506 insertions, 0 deletions
diff --git a/final/runtime/tools/check-depends.pl b/final/runtime/tools/check-depends.pl
new file mode 100755
index 0000000..47e7e5a
--- /dev/null
+++ b/final/runtime/tools/check-depends.pl
@@ -0,0 +1,506 @@
+#!/usr/bin/env perl
+
+#
+#//===----------------------------------------------------------------------===//
+#//
+#// The LLVM Compiler Infrastructure
+#//
+#// This file is dual licensed under the MIT and the University of Illinois Open
+#// Source Licenses. See LICENSE.txt for details.
+#//
+#//===----------------------------------------------------------------------===//
+#
+
+use strict;
+use warnings;
+
+use FindBin;
+use lib "$FindBin::Bin/lib";
+
+use tools;
+
+our $VERSION = "0.005";
+my $target_os;
+my $target_arch;
+
+# --------------------------------------------------------------------------------------------------
+# Ouput parse error.
+# $tool -- Name of tool.
+# @bulk -- Output of the tool.
+# $n -- Number of line caused parse error.
+sub parse_error($\@$) {
+ my ( $tool, $bulk, $n ) = @_;
+ my @bulk;
+ for ( my $i = 0; $i < @$bulk; ++ $i ) {
+ push( @bulk, ( $i == $n ? ">>> " : " " ) . $bulk->[ $i ] );
+ }; # for $i
+ runtime_error( "Fail to parse $tool output:", @bulk, "(eof)" );
+}; # sub parse_error
+
+
+# --------------------------------------------------------------------------------------------------
+# Linux* OS version of get_deps() parses output of ldd:
+#
+# $ ldd libname.so
+# libc.so.6 => /lib64/libc.so.6 (0x00002b60fedd8000)
+# libdl.so.2 => /lib64/libdl.so.2 (0x00002b60ff12b000)
+# libpthread.so.0 => /lib64/libpthread.so.0 (0x00002b60ff32f000)
+# /lib64/ld-linux-x86-64.so.2 (0x0000003879400000)
+#
+# Note: ldd printd all the dependencies, direct and indirect. (For example, if specified library
+# requires libdl.so, and libdl.so requires /lib/ld-linux.so, ldd prints both libdl.so and
+# /lib/ld-linux.so). If you do not want indirect dependencies, look at readelf tool.
+#
+sub get_deps_ldd($) {
+
+ my $lib = shift ( @_ );
+ my $tool = "ldd";
+ my @bulk;
+ my @deps;
+
+ execute( [ $tool, $lib ], -stdout => \@bulk );
+ debug( @bulk, "(eof)" );
+
+ foreach my $i ( 0 .. @bulk - 1 ) {
+ my $line = $bulk[ $i ];
+ if ( $line !~ m{^\s*(?:([_a-z0-9.+-/]*)\s+=>\s+)?([_a-z0-9.+-/]*)\s+\(0x[0-9a-z]*\)$}i ) {
+ parse_error( $tool, @bulk, $i );
+ }; # if
+ my $dep = ( defined( $1 ) ? $1 : $2 );
+ push( @deps, $dep );
+ }; # foreach $i
+
+ return @deps;
+
+}; # sub get_deps_ldd
+
+
+# --------------------------------------------------------------------------------------------------
+# Another Linux* OS version of get_deps() parses output of readelf:
+#
+# $ readelf -d exports/lin_32e/lib/libomp.so
+#
+# Dynamic segment at offset 0x87008 contains 24 entries:
+# Tag Type Name/Value
+# 0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
+# 0x0000000000000001 (NEEDED) Shared library: [libdl.so.2]
+# 0x0000000000000001 (NEEDED) Shared library: [libpthread.so.0]
+# 0x000000000000000e (SONAME) Library soname: [libomp.so]
+# 0x000000000000000d (FINI) 0x51caa
+# 0x0000000000000004 (HASH) 0x158
+# 0x0000000000000005 (STRTAB) 0x9350
+# ...
+#
+# Note: In contrast to ldd, readlef shows only direct dependencies.
+#
+sub get_deps_readelf($) {
+
+ my $file = shift ( @_ );
+ my $tool;
+ my @bulk;
+ my @deps;
+
+ if($target_arch eq "mic") {
+ $tool = "x86_64-k1om-linux-readelf";
+ } else {
+ $tool = "readelf";
+ }
+
+ # Force the readelf call to be in English. For example, when readelf
+ # is called on a french localization, it will find "Librairie partagees"
+ # instead of shared library
+ $ENV{ LANG } = "C";
+
+ execute( [ $tool, "-d", $file ], -stdout => \@bulk );
+ debug( @bulk, "(eof)" );
+
+ my $i = 0;
+ # Parse header.
+ ( $i < @bulk and $bulk[ $i ] =~ m{^\s*$} )
+ or parse_error( $tool, @bulk, $i );
+ ++ $i;
+ if ( $i == @bulk - 1 and $bulk[ $i ] =~ m{^There is no dynamic section in this file\.\s*$} ) {
+ # This is not dynamic executable => no dependencies.
+ return @deps;
+ }; # if
+ ( $i < @bulk and $bulk[ $i ] =~ m{^Dynamic (?:segment|section) at offset 0x[0-9a-f]+ contains \d+ entries:\s*$} )
+ or parse_error( $tool, @bulk, $i );
+ ++ $i;
+ ( $i < @bulk and $bulk[ $i ] =~ m{^\s*Tag\s+Type\s+Name/Value\s*$} )
+ or parse_error( $tool, @bulk, $i );
+ ++ $i;
+ # Parse body.
+ while ( $i < @bulk ) {
+ my $line = $bulk[ $i ];
+ if ( $line !~ m{^\s*0x[0-9a-f]+\s+\(([_A-Z0-9]+)\)\s+(.*)\s*$}i ) {
+ parse_error( $tool, @bulk, $i );
+ }; # if
+ my ( $type, $value ) = ( $1, $2 );
+ if ( $type eq "NEEDED" ) {
+ if ( $value !~ m{\AShared library: \[(.*)\]\z} ) {
+ parse_error( $tool, @bulk, $i );
+ }; # if
+ my $dep = $1;
+ push( @deps, $dep );
+ }; # if
+ ++ $i;
+ }; # foreach $i
+
+ return @deps;
+
+}; # sub get_deps_readelf
+
+
+# --------------------------------------------------------------------------------------------------
+# OS X* version of get_deps() parses output of otool:
+#
+# $ otool -L libname.dylib
+# exports/mac_32/lib.thin/libomp.dylib:
+# libomp.dylib (compatibility version 5.0.0, current version 5.0.0)
+# /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 88.1.3)
+#
+sub get_deps_otool($) {
+
+ my $file = shift ( @_ );
+ my $name = get_file( $file );
+ my $tool = "otool";
+ my @bulk;
+ my @deps;
+
+ if ( $target_arch eq "32e" ) {
+ # On older (Tiger) systems otool does not recognize 64-bit binaries, so try to locate
+ # otool64.
+ my $path = which( "otool64" );
+ if ( defined ( $path ) ) {
+ $tool = "otool64";
+ }; # if
+ }; # if
+
+ execute( [ $tool, "-L", $file ], -stdout => \@bulk );
+ debug( @bulk, "(eof)" );
+
+ my $i = 0;
+ # Parse the first one or two lines separately.
+ ( $i < @bulk and $bulk[ $i ] =~ m{^\Q$file\E:$} )
+ or parse_error( $tool, @bulk, $i );
+ ++ $i;
+ if ( $name =~ m{\.dylib\z} ) {
+ # Added "@rpath/" enables dynamic load of the library designated at link time.
+ $name = '@rpath/' . $name;
+ # In case of dynamic library otool print the library itself as a dependent library.
+ ( $i < @bulk and $bulk[ $i ] =~ m{^\s+\Q$name\E\s+\(compatibility version.*\)$} )
+ or parse_error( $tool, @bulk, $i );
+ ++ $i;
+ }; # if
+
+ # Then parse the rest.
+ while ( $i < @bulk ) {
+ my $line = $bulk[ $i ];
+ if ( $line !~ m/^\s*(.*)\s+\(compatibility version\s.*\)$/ ) {
+ parse_error( $tool, @bulk, $i );
+ }; # if
+ my ( $dep ) = ( $1 );
+ push( @deps, $dep );
+ ++ $i;
+ }; # while
+
+ return @deps;
+
+}; # sub get_deps_otool
+
+
+# --------------------------------------------------------------------------------------------------
+# Windows* OS version of get_deps() parses output of link:
+#
+# > link -dump -dependents libname.dll
+# Microsoft (R) COFF/PE Dumper Version 8.00.40310.39
+# Copyright (C) Microsoft Corporation. All rights reserved.
+# Dump of file S:\Projects.OMP\users\omalyshe\omp\libomp\exports\win_64\lib\libompmd.dll
+# File Type: DLL
+# Image has the following dependencies:
+# KERNEL32.dll
+# Summary
+# C000 .data
+# 6000 .pdata
+# 18000 .rdata
+# ...
+#
+# > link -dump -directives libname.lib
+# Microsoft (R) COFF/PE Dumper Version 8.00.40310.39
+# Copyright (C) Microsoft Corporation. All rights reserved.
+# Dump of file S:\Projects.OMP\users\omalyshe\omp\libomp\exports\win_32e\lib\libimp5mt.lib
+# File Type: LIBRARY
+# Linker Directives
+# -----------------
+# -defaultlib:"uuid.lib"
+# -defaultlib:"uuid.lib"
+# .....
+# Summary
+# 3250 .bss
+# 3FBC .data
+# 34 .data1
+# ....
+sub get_deps_link($) {
+
+ my ( $lib ) = @_;
+ my $tool = "link";
+ my @bulk;
+ my @deps;
+
+ my $ext = lc( get_ext( $lib ) );
+ if ( $ext !~ m{\A\.(?:lib|dll|exe)\z}i ) {
+ runtime_error( "Incorrect file is specified: `$lib'; only `lib', `dll' or `exe' file expected" );
+ }; # if
+
+ execute(
+ [ $tool, "/dump", ( $ext eq ".lib" ? "/directives" : "/dependents" ), $lib ],
+ -stdout => \@bulk
+ );
+
+ debug( @bulk, "(eof)" );
+
+ my $i = 0;
+ ( $i < @bulk and $bulk[ $i ] =~ m{^Microsoft \(R\) COFF\/PE Dumper Version.*$} ) or parse_error( $tool, @bulk, $i ); ++ $i;
+ ( $i < @bulk and $bulk[ $i ] =~ m{^Copyright \(C\) Microsoft Corporation\..*$} ) or parse_error( $tool, @bulk, $i ); ++ $i;
+ ( $i < @bulk and $bulk[ $i ] =~ m{^\s*$} ) or parse_error( $tool, @bulk, $i ); ++ $i;
+ ( $i < @bulk and $bulk[ $i ] =~ m{^\s*$} ) or parse_error( $tool, @bulk, $i ); ++ $i;
+ ( $i < @bulk and $bulk[ $i ] =~ m{^Dump of file\s\Q$lib\E$} ) or parse_error( $tool, @bulk, $i ); ++ $i;
+ ( $i < @bulk and $bulk[ $i ] =~ m{^\s*$} ) or parse_error( $tool, @bulk, $i ); ++ $i;
+ ( $i < @bulk and $bulk[ $i ] =~ m{^File Type:\s(.*)$} ) or parse_error( $tool, @bulk, $i ); ++ $i;
+ ( $i < @bulk and $bulk[ $i ] =~ m{^\s*$} ) or parse_error( $tool, @bulk, $i ); ++ $i;
+
+ if ( $ext eq ".lib" ) {
+
+ my %deps;
+ while ( $i < @bulk ) {
+ my $line = $bulk[ $i ];
+ if ( 0 ) {
+ } elsif ( $line =~ m{^\s*[-/]defaultlib\:(.*)\s*$}i ) {
+ my $dep = $1;
+ # Normalize library name:
+ $dep = lc( $1 ); # Convert to lower case.
+ $dep =~ s{\A"(.*)"\z}{$1}; # Drop surrounding quotes (if any).
+ $dep =~ s{\.lib\z}{}; # Drop .lib suffix (if any).
+ $deps{ $dep } = 1;
+ } elsif ( $line =~ m{^\s*Linker Directives\s*$} ) {
+ } elsif ( $line =~ m{^\s*-+\s*$} ) {
+ } elsif ( $line =~ m{^\s*/alternatename\:.*$} ) {
+ } elsif ( $line =~ m{^\s*$} ) {
+ } elsif ( $line =~ m{^\s*/FAILIFMISMATCH\:.*$} ) {
+ # This directive is produced only by _MSC_VER=1600
+ } elsif ( $line =~ m{^\s*Summary\s*$} ) {
+ last;
+ } else {
+ parse_error( $tool, @bulk, $i );
+ }; # if
+ ++ $i;
+ } # while
+ @deps = keys( %deps );
+
+ } else {
+
+ ( $i < @bulk and $bulk[ $i ] =~ m{\s*Image has the following dependencies\:$} )
+ or parse_error( $tool, @bulk, $i );
+ ++ $i;
+ while ( $i < @bulk ) {
+ my $line = $bulk[ $i ];
+ if ( 0 ) {
+ } elsif ( $line =~ m{^\s*$} ) {
+ # Ignore empty lines.
+ } elsif ( $line =~ m{^\s*(.*\.dll)$}i ) {
+ my $dep = lc( $1 );
+ push( @deps, $dep );
+ } elsif ( $line =~ m{^\s*Summary$} ) {
+ last;
+ } else {
+ parse_error( $tool, @bulk, $i );
+ }; # if
+ ++ $i;
+ }; # while
+
+ }; # if
+
+ return @deps;
+
+}; # sub get_deps_link
+
+
+# --------------------------------------------------------------------------------------------------
+# Main.
+# --------------------------------------------------------------------------------------------------
+
+# Parse command line.
+my $expected;
+my $bare;
+Getopt::Long::Configure( "permute" );
+get_options(
+ "os=s" => \$target_os,
+ "arch=s" => \$target_arch,
+ "bare" => \$bare,
+ "expected=s" => \$expected,
+);
+my @expected;
+if ( defined( $expected ) ) {
+ if ( $expected ne "none" ) {
+ @expected = sort( split( ",", $expected ) );
+ if ( $target_os eq "win" ) {
+ @expected = map( lc( $_ ), @expected );
+ }; # if
+ }; # if
+}; # if
+if ( @ARGV < 1 ) {
+ cmdline_error( "Specify a library name to check for dependencies" );
+}; # if
+if ( @ARGV > 1 ) {
+ cmdline_error( "Too many arguments" );
+}; # if
+my $lib = shift( @ARGV );
+if ( not -e $lib ){
+ runtime_error( "Specified file does not exist: \"$lib\"" );
+}; # if
+
+# Select appropriate get_deps implementation.
+if ( 0 ) {
+} elsif ( $target_os eq "lin" ) {
+ *get_deps = \*get_deps_readelf;
+} elsif ( $target_os eq "mac" ) {
+ *get_deps = \*get_deps_otool;
+} elsif ( $target_os eq "win" ) {
+ *get_deps = \*get_deps_link;
+} else {
+ runtime_error( "OS \"$target_os\" not supported" );
+}; # if
+
+# Do the work.
+my @deps = sort( get_deps( $lib ) );
+if ( $bare ) {
+ print( map( "$_\n", @deps ) );
+} else {
+ info( "Dependencies:", @deps ? map( " $_", @deps ) : "(none)" );
+}; # if
+if ( defined( $expected ) ) {
+ my %deps = map( ( $_ => 1 ), @deps );
+ foreach my $dep ( @expected ) {
+ delete( $deps{ $dep } );
+ }; # foreach
+ my @unexpected = sort( keys( %deps ) );
+ if ( @unexpected ) {
+ runtime_error( "Unexpected dependencies:", map( " $_", @unexpected ) );
+ }; # if
+}; # if
+
+exit( 0 );
+
+__END__
+
+=pod
+
+=head1 NAME
+
+B<check-depends.pl> -- Check dependencies for a specified library.
+
+=head1 SYNOPSIS
+
+B<check-depends.pl> I<OPTIONS>... I<library>
+
+=head1 DESCRIPTION
+
+C<check-depends.pl> finds direct dependencies for a specified library. List of actual dependencies
+is sorted alphabetically and printed. If list of expected dependencies is specified, the scripts
+checks the library has only allowed dependencies. In case of not expected depndencies the script
+issues error message and exits with non-zero code.
+
+Linux* OS and OS X*: The script finds dependencies only for dymamic libraries. Windows* OS: The script
+finds dependencies for either static or dymamic libraries.
+
+The script uses external tools. On Linux* OS, it runs F<readelf>, on OS X* -- F<otool> (or F<otool64>),
+on Windows* OS -- F<link>.
+
+On Windows* OS dependencies are printed in lower case, case of expected dependencies ignored.
+
+=head1 OPTIONS
+
+=over
+
+=item B<--bare>
+
+Do not use fancy formatting; produce plain, bare output: just a list of libraries,
+a library per line.
+
+=item B<--expected=>I<list>
+
+I<list> is comma-separated list of expected dependencies (or C<none>).
+If C<--expected> option specified, C<check-depends.pl> checks the specified library
+has only expected dependencies.
+
+=item B<--os=>I<str>
+
+Specify target OS (tool to use) manually.
+Useful for cross-build, when host OS is not the same as target OS.
+I<str> should be either C<lin>, C<mac>, or C<win>.
+
+=back
+
+=head2 Standard Options
+
+=over
+
+=item B<--help>
+
+Print short help message and exit.
+
+=item B<--doc>
+
+=item B<--manual>
+
+Print full documentation and exit.
+
+=item B<--quiet>
+
+Do not output informational messages.
+
+=item B<--version>
+
+Print version and exit.
+
+=back
+
+=head1 ARGUMENTS
+
+=over
+
+=item I<library>
+
+A name of library to find or check dependencies.
+
+=back
+
+=head1 EXAMPLES
+
+Just print library dependencies (Windows* OS):
+
+ > check-depends.pl exports/win_32/lib/libompmd.dll
+ check-depends.pl: (i) Dependencies:
+ check-depends.pl: (i) kernel32.dll
+
+Print library dependencies, use bare output (Linux* OS):
+
+ $ check-depends.pl --bare exports/lin_32e/lib/libomp_db.so
+ libc.so.6
+ libdl.so.2
+ libpthread.so.0
+
+Check the library does not have any dependencies (OS X*):
+
+ $ check-depends.pl --expected=none exports/mac_32/lib/libomp.dylib
+ check-depends.pl: (i) Dependencies:
+ check-depends.pl: (i) /usr/lib/libSystem.B.dylib
+ check-depends.pl: (x) Unexpected dependencies:
+ check-depends.pl: (x) /usr/lib/libSystem.B.dylib
+ $ echo $?
+ 2
+
+=cut
+
+# end of file #
+