#!/usr/bin/perl # @(#) $Id: acsMakeCheckUnresolvedSymbols,v 1.10 2012/01/13 18:54:47 tstaig Exp $ #----------------------------------------------------------------------- # ALMA - Atacama Large Millimeter Array # Copyright (c) NRAO, 2007 (Patrick P. Murphy) # (in the framework of the ALMA collaboration). # All rights reserved. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # #----------------------------------------------------------------------- # # NAME # CheckUnresolvedSymbols # # DESCRIPTION # Checks the specified shared library for unresolved symbols # This script will take the argument on the command line, assume it # is a shared library of ELF format objects, and check it for # unresolved symbols. If there are any found, it exits with an error # status and an appropriate error message. # # An alternative usage is obtained via the -l flag; this invokes ldd # against the relevant library to highlight any shared libraries that # cannot be found. # # USAGE # See the "$usage = ..." section below. # # AUTHOR # Pat Murphy # # ENVIRONMENT # # CAUTION # The approach here is like cracking an egg with a sledgehammer. It # is HIGHLY empirical. While using the "ld" command on a .so and # checking its return status seems to work now on the test cases we # tried, it may not work in the future. # # EXAMPLES # To be inserted. # # SEE ALSO # Manual pages for "ld" and "readelf" and "ldd" # # BUGS # Probably present. Squish them as you find them. # # DEPENDENCIES # Just standard perl stuff. #----------------------------------------------------------------------- use File::Basename; use Getopt::Std; $myname = basename($0, ".pl"); # Who am I? #---------------customization, local variables, setup, usage ----------- # $usage = "Usage: $myname library.$SHLIB_EXT [opts]\n\n" . "Options:\n\n" . " -h show this message\n" . " -l Use 'ldd' to only show 'not found' libraries\n" . " -o {file} Output to {file} instead of CheckUnresolvedSymbols-DELETEME.out\n" . " -n Do not print headers or summary in output\n" . " -q Ultra Quiet mode, only use status return\n" . " -s Save (do not delete) output file\n" . " -v Debug mode (more verbose output, cancels -q)\n" . " -w Warn about unresolved modules, but exit with success."; # Options! Options! Must have options! getopts('hlno:qsvw') || die($usage); if ($opt_h) { printf $usage; exit; } # Need to get arguments here from ARGV if ($#ARGV <= -1) { printf STDERR "$myname: No libraries to check!\n\n$usage"; exit(1); } # Try to run "ld" on the thang... $mylib = $ARGV[0]; if ( ! -r $mylib ) { printf STDERR "$myname: Cannot read $mylib\n"; exit(2); } else { # the OR here is due to SWIG libraries if($mylib =~ /lib(\w+).$SHLIB_EXT/ || $mylib =~ /(\w+).$SHLIB_EXT/) { $stem = $1; } else { printf STDERR "Failure in identifying the stem of $mylib\n"; } } if ( ! -w "." ) { printf STDERR "$myname: Current directory is not writable\n"; exit(3); } if (!$opt_o) { $opt_o = "CheckUnresolvedSymbols-$stem-$>-DELETEME.out"; } if ($opt_q && $opt_v) { printf STDERR "$myname warning: -v overrides -q\n"; undef($opt_q); } printf "$myname debug: output is $opt_o\n" if ($opt_v); $ush = $ENV{"SHELL"}; $cmd = "ld $mylib -o $opt_o 2>&1"; if ($opt_l) { $cmd = "ldd $mylib 2>&1"; } if ($ush =~ /csh/) { # Ick ick! Note that a google search for # 'tcsh version of "2>&1"' finds the FAQ # "csh programming considered harmful". # This circumvention may not work. If # not, then put in an error here instead. $cmd = "bash -c 'ld $mylib -o $opt_o 2>&1' "; if ($opt_l) { $cmd = "bash -c 'ldd $mylib 2>&1' "; } # printf STDERR "$myname: your shell is csh or tcsh; This script cannot\n"; # printf STDERR "$myname: run under c-style shells. Please read or \n"; # printf STDERR "$myname: google the unix-faq/shell/csh-whynot FAQ to\n"; # printf STDERR "$myname: find out why this is (cf. redirection).\n"; # exit(4); } printf "$myname debug: command is $cmd\n" if ($opt_v); $first = 1; $nundef = 0; $mystat = 0; if (!open(ROLF, "$cmd |")) { # Open a pipe to the command printf STDERR "$myname: cannot run $cmd on $mylib: $!\n"; exit(5); } elsif ($opt_v) { printf "$myname debug: checking $mylib\n"; } while () { chomp; # trim any newline if ($opt_l) { next unless /(lib.*) =\> not found$/; $und = $1; printf "$myname debug: ldd found $und\n" if ($opt_v); if ($first) { if (!($opt_n || $opt_q)) { printf STDERR "$myname: 'not found' library/ies detected in $mylib\n"; printf STDERR "$myname: - List follows:\n"; } $first--; } } else { next if /entry symbol _start/; # Always ignore this next unless /undefined reference to \`([^\']*)\'/; $und = $1; printf "$myname debug: found $und:\n" if ($opt_v); if ($first) { if (!($opt_n || $opt_q)) { printf STDERR "$myname: Undefined symbol(s) detected in $mylib\n"; printf STDERR "$myname: - List follows:\n"; } $first--; } } # see if we have it already; unlikely if ($undefs{$und}) { printf "$myname debug: Skipping $und, already found\n" if ($opt_v); } else { printf STDERR "$myname: $und\n" unless ($opt_q); $mystat = 3; $nundef++; $undefs{$und} = $mylib; } } $stat = 0; # Just close it; see older CVS versions for the check-close version; it didn't # work as expected. close(ROLF); # Clean up. # Report on findings. if ($nundef > 0) { if (!($opt_n || $opt_q)) { if ($opt_l) { if ($nundef == 1) { printf STDERR "$myname: Total of one 'not found'in $mylib\n"; } else { printf STDERR "$myname: Total of $nundef 'not found' in $mylib\n"; } } else { if ($nundef == 1) { printf STDERR "$myname: Total of one undefined symbol in $mylib\n"; } else { printf STDERR "$myname: Total of $nundef undefined symbols in $mylib\n"; } } } if (!$opt_s && !$opt_l) { if (( -f $opt_o) && (! $opt_q) ) { # See below; this should not happen. printf STDERR "$myname: found unexpected $opt_o, deleting it...\n"; unlink($opt_o); } } if (!$opt_w) { if ($opt_l) { printf STDERR "$myname: ###### FAIL for ldd on $mylib\n"; } else { printf STDERR "$myname: ###### FAIL for ld on $mylib\n"; } } } else { if ($opt_l) { printf "$myname debug: no 'not found' libraries referenced in $mylib.\n" if ($opt_v); } else { printf "$myname debug: no undefined symbols detected in $mylib.\n" if ($opt_v); } if (!$opt_s && !$opt_l) { # See if we have to clean up. # NOTE: no undefined symbols usually means the # CheckUnresolvedSymbols-DELETEME.out or $opt_o file # got created. It seems not to be created otherwise. if ( -f $opt_o) { printf STDERR "$myname: found $opt_o, deleting it...\n" if ($opt_v); unlink($opt_o); } else { printf STDERR "$myname: no $opt_o to delete? Weird!\n"; } } } if ($opt_w) { exit(0); } else { exit($mystat); # will be 0 or 3. }