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

标签 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

最后一行将打印出一些 undefined symbol 错误。如果这是 Solaris,链接器将检查其他会隐式满足依赖关系的库并提供提示:

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

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

在实际情况下,我们的构建中有几百个库,加上它们和可执行文件所依赖的所有外部库。将 -zdefs 添加到构建后,我得到了大约 10,000 多个 undefined reference ;手动识别缺少哪些依赖项会很烦人。

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

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

在 Linux 方面,我不确定我能做些什么来加快这个过程。

欢迎提出任何建议。

最佳答案

我找到了一种使用 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
...

它并不完美,仍然有可能不止一个库满足依赖性,或者链接到某个静态库并且看起来满足依赖性,而实际上它应该链接到另一个库。但是,我有办法弄清楚那部分。

关于linux - 如何在链接时自动发现隐式依赖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26270768/

相关文章:

linux - 在 Docker 中部署交叉编译工具链

linux - PowerDNS 仅适用于本地

linux - 如何知道 udev 或 mdev 是否​​启用

linux - 以非 root 用户身份访问 Bluez 库

C++ - LNK2019 未解析的外部符号 - 似乎找不到我缺少的东西

ubuntu - 在 Ubuntu 上链接 libusb 不起作用

c++ - 在 MSVC++2010 中使用静态链接在调试配置中编译 DLL 时出现链接器错误

java - UnsatisfiedLinkError -- Play !依赖关系

android - 在项目 'app' 中,已解决的 Google Play 服务库依赖项依赖于另一个

python 循环导入再次(也就是这个设计有什么问题)