如何在链接时自动发现隐式依赖项

时间:2014-10-09 05:10:32

标签: linux linker dependencies shared-libraries solaris

我正在调整旧版本,其中许多共享库不会链接到他们实际依赖的库。在我想要解决的问题中,已经存在一些循环依赖关系,但是如果我能够解决所有非循环依赖关系,它会变得更加简单。目前,链接可执行文件时解析了未解析的符号 - 这就是他们设法[不知不觉]引入循环依赖的方式。

这是一个简短的bash脚本,我把它放在一起测试一些想法:

 #!/bin/bash

 mkdir -p objs

 for ((ii=0; ii<3; ii++)); do
   echo 'void FUNC(){}' | g++ -xc++ -DFUNC=f${ii} -fpic - -c -o objs/t${ii}.o
   g++ -fpic -shared objs/t${ii}.o -o libtest${ii}.so
 done

 # In the real-world case, libjoined.so isn't a trivial library.
 # Currently, it causes things to implicitly link against other
 # libraries libblah.so needs (like boost libraries)
 echo | g++ -xc++ -shared -fpic -L. -Wl,-R. -ltest{0,1,2} - -o libjoined.so

 g++ -xc++ -fpic - -c -o objs/b.o <<'EOF'
 extern void f0();
 extern void f1();
 extern void f2();

 void blah() { f0(); f1(); f2(); }
 EOF

 g++ -fpic -shared objs/b.o -L. -Wl,-R. -ljoined -o libblah.so -Wl,-zdefs

最后一行最终会打印出一些未定义的符号错误。如果这是Solaris,则链接器将检查否则将隐式满足依赖性的其他库并提供提示:

 Undefined         first referenced
  symbol               in file
 void f1()             objs/b.o  (symbol belongs to implicit dependency ./libtest1.so)

...但我没有看到与GNU ld类似的行为。

在现实世界中,我们的构建中有几百个库以及它们和可执行文件所依赖的所有外部库。将-zdefs添加到构建版本后,我将获得大约10,000个未定义的引用;识别哪些依赖项是手工丢失会相当烦人。

我需要一种快速识别缺失依赖关系的方法。

在solaris方面,我可能会尝试创建一个类似libjoined.so的库,它只链接到我们所有的库(最初没有-zdefs构建所有库),然后编写一个脚本来提取从日志链接命令并使用-zdefs重新运行命令并链接到其他库并将提示转储到文本文件或其他内容。

在linux方面,我不确定如何加快这一过程。

欢迎任何建议。

1 个答案:

答案 0 :(得分:0)

我找到了一种方法ld -r -p

我无法复制代码,但我会给出一个模型。我不能保证以下会运行,但它应该给你一个好的概念:

#!/usr/bin/perl

use warnings;
use strict;

my %symbols;
my %libs_missing_stuff;

foreach my $arg ( @ARGV) {
  # loop over libraries and make a map of the form:
  #   $symbols{$symbol} = $arg
  my @tmp = (`nm -Aa --defined-only ${arg}` =~ m{(\S+)$}g);
  foreach my $symbol ( @tmp ) {
    $symbols{$symbol} = $arg;
  }
}

foreach my $arg ( @ARGV ) {
# This is ultimately what I needed
  my @tmp = (`ldd -r -p $arg 2>&1` =~ m{symbol not found: (\S+)}g);
#             ^~~~~~~~^
  foreach my $missing_symbol ( @tmp ) {
    if( defined( $symbols{$missing_symbol} ) ) {
      $libs_missing_stuff{$arg}{$symbols{$missing_symbol}} = 1;
    }
  }
}

# loop over %libs_missing_stuff and print it out

输出如下所示:

somelib : lib1 lib2 lib3
someotherlib : lib3 lib6 lib8
...

它并不完美,并且仍有潜力不止一个库满足依赖关系,或链接到某个静态库并且出现以满足实际上的依赖关系它应链接到其他库。但是,我有办法找出那部分。