0

I'm working on a 20 year old project with some ... interesting problems, among them: there's some shared objects with circular dependencies.

I'm attempting to map out the relationships between all the libraries, but it would be rather helpful if there's an existing tool capable of searching a list of libraries to see what can satisfy the missing dependencies.

For reference, they got around the problem by doing something like the following:

# True list of dependencies:
A: B
B: A
C: A

# Dependencies used in practice:
A:
B: A
C: A B
4

1 回答 1

0

I haven't tested the following code, since I've just attempted to re-write this from memory, but the one I wrote to solve this earlier (it looks roughly like this one) works fine:

#!/usr/bin/env perl

using IPC::Open3;

my $queryFile = $ARGV[0];
shift;

my %missingSymbols = getSymbols( "nm -Aau", $queryFile );

my %symtbl;

foreach $lib ( @ARGV ) {
  my %temp = getSymbols( "nm -Aa --defined-only", $lib );

  foreach $key ( keys( %temp ) ) {
    $symtbl{$key} =   (defined($symtbl{$key}) ? "${symtbl{$key}} " : "")
                    . $temp{$key};
  }
}

my %dependencies;
foreach $symbol ( keys( %missingSymbols  ) ) {
  if( defined( $symtbl{$symbol} ) ) {
    foreach $lib ( split( / +/, $symtbl{$symbol} ) ) {
      if( !defined( $dependencies{$lib} ) ) {
        $dependencies{$lib} = 1;
      }
    }
  }
}

if( scalar( keys( %dependencies ) ) > 0 ) {
  print( "$queryFile depends on one or more of the following libs:\n\n" );

  print join( "\n", sort( keys( %dependencies ) ) ) . "\n\n";
} else {
  print( "Unable to resolve dependencies for $queryFile.\n\n" );
}

# Done.

sub getSymbols {
  my $cmd   = shift;
  my $fname = shift;

  checkFileType( $fname );

  open3( IN, OUT, ERR, "$cmd $fname" );

  my %symhash;
  close( IN );
  # If you leave ERR open and nm prints to STDERR, reads from
  # OUT can block.  You could make reads from both handles be
  # non-blocking so you could examine STDERR if needed, but I
  # don't need to.
  close( ERR );

  while( <OUT> ) {
    chomp;
    if( m/^(?:[^:]*:)+[a-zA-Z0-9]*\s*[a-zA-Z] ([^\s]+)$/ ) {
      my $temp = defined( $symhash{$1} ) ? "${symhash{$1}} " : "";
      $symhash{$1} = $temp . $fname;
    }
  }
  close( OUT );

  return %symhash;
}

sub checkFileType {
  my $fname = shift;

  die "$fname does not exist\n" if( ! -e $fname );
  die "Not an ELF or archive file\n" if( `file $fname` !~ m/ELF| ar archive/ );
}
于 2012-04-21T07:59:48.017 回答