【问题标题】:Is it completely safe to remove unused libraries as reported by ldd?删除 ldd 报告的未使用的库是否完全安全?
【发布时间】:2011-08-21 12:20:46
【问题描述】:

我正在清理一个腐烂的源代码树,并尝试让每个可执行文件和每个共享库仅与它们直接使用的库链接。

为了做到这一点,我 ldd -u- r 二进制输出,并从 makefile 中删除报告的库。

例如:

$ ldd -u -r ./libA.so
Unused direct dependencies:
        /usr/local/lib/libB.so
        /usr/local/lib/libC.so
        /lib/tls/libpthread.so.0
$ sed -i'' -e 's/-lB//' -e 's/-lC//' Makefile

当然,libpthread 确实需要(并且无论如何都隐含在-pthread 中),但是ldd 报告的其余库可以安全地删除。

对我的优化有影响吗?完全安全吗?

【问题讨论】:

  • 取决于 libBlibC 是否被另一个库使用,即(直接)使用。你可以看到stackoverflow.com/questions/5664338/…
  • @Kiril:这只适用于静态库。动态库知道它们的依赖关系。
  • @Kiril,你的意思是我在下面的答案中写的吗?如果是这样,那还不错,因为我会在编译失败时发现它,无论如何修复它是一个非常好的主意。

标签: dynamic makefile g++ ld


【解决方案1】:

这是安全的*,除非发生一件事(谢天谢地,在你的控制之下)。

如果应用程序使用dlsym(RTLD_DEFAULT,...) 加载其他符号,它将在当前加载的共享库中搜索适当的符号(函数)。如果其意图是从您要删除的这些库之一中加载符号(并且之前没有 dlopen() 调用),则应用程序将找不到它,并且可能行为不端。 p>

但是请注意,dlsym() 很少使用(您可以通过 ldd 检查它是否使用过),并且在没有事先调用 dlopen() 的情况下使用它的情况更是如此,因此在几乎所有情况下您都可以安全地删除未使用的库。它将显着提高您的应用程序的可移植性。


*“安全”的意思是“如果没有构建时错误,可能会工作”。删除库的构建时影响太容易检测到,无法解释。

【讨论】:

    【解决方案2】:

    我能想到的一个含义是,可能存在仅由可执行文件使用但在库中指定的隐式依赖项。例如。

    $ cat a.cc
    int fa(){return 42;}
    $ gcc -shared a.cc -o liba.so -ltermcap
    $ cat main.cc
    #include <stdio.h>
    #include <stdlib.h>
    #include <termcap.h>
    int main() {
            tgetent(0,getenv("TERM"));
            printf("terminal is %d columns\n",tgetnum("co"));
    }
    $ gcc main.cc -o main # we didn't mention -ltermcap
    /tmp/ccercfhS.o(.text+0x27): In function `main':
    : undefined reference to `tgetent'
    collect2: ld returned 1 exit status
    $ # we mentioned -ltermcap by using -la
    $ # if we'll remove -ltermcap from liba the project won't compile
    $ gcc main.cc -o main -L. -la 
    $ LD_LIBRARY_PATH=. ./main
    terminal is 237 columns
    

    然而,这并不是一个糟糕的错误,因为它总是会被您而不是客户提前检测和修复。

    不管怎样,你应该include what you use 所以最好让main.cc 直接与termcap 链接。

    【讨论】:

      【解决方案3】:

      如果我是你,我会像这样使用 strace 进行一两次测试

      strace -e open myprog >strace.out 2>&1

      然后检查 strace 输出以查看实际打开了哪些库。这意味着任何不返回 -1 的 open() 调用。

      【讨论】:

      • 我看不出它有什么帮助。 lddnm 可以免费给我所有这些信息。
      • 抱歉,ldd 不能。正在运行的应用程序可能会动态加载不依赖链接时间的库。并且 ldd 在执行期间无法知道当前目录是什么,因此无法正确评估使用 $ORIGIN 的 RPATH 之类的东西。如果没有别的,只需 grep 输出不等于 -1 的打开并确保它们看起来正确。 Strace 对于最终肯定检查一切是否正确非常有用。
      • 好的,所以lddack ldopen。 strace 的缺点是仅检查您在此特定单元测试中使用的代码。
      • 使用代码覆盖率工具确保您的单元测试是详尽无遗的。不要发布未经彻底单元测试的代码
      • 微软没有听从你的建议,一位团队负责人告诉我,他不一定能达到 100% 的覆盖率。但是,您对现有项目做了什么?如果项目很好,我们会在构建过程中检查ld -u -rack ldopen 给出与strace 相同的结果,更便宜,更准确,所以我认为没有理由使用strace
      【解决方案4】:

      对我来说,似乎还有一个额外的含义,即 ldd 会将它找不到的所有库显示为未使用(它们可能在构建时就已经存在,所以这里没有错误)。

      所以,依赖ldd -u的结果是不安全的!

      (在 Ubuntu Ubuntu 18.04.2 下使用 ldd 2.27 和 Devuan ascii 下的 ldd 2.24 测试)

      【讨论】:

        猜你喜欢
        • 2023-03-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-07
        • 1970-01-01
        • 2010-10-30
        • 1970-01-01
        相关资源
        最近更新 更多