7

有没有办法(在 Linux 中)确定我必须将 C/C++ 程序链接到哪些库?我不想错过一个库,即使在程序启动时未检测到未定义符号的情况下也是如此。另外,我当然想避免不必要的依赖。

我一般地提出了这个问题,但这里有一个具体的、非平凡的例子:直到最近,我认为我需要链接到libpython用于使用 Boost.Python 开发的 Python 模块。然而,事实并非如此:用 Boost.Python 编写一个模块;它甚至可能使用来自 Python C API 的函数,而不仅仅是 Boost.Python。链接libboost_python就足够了!这一点都不明显——至少我没有发现它被记录在案,并且有一些 Boost.Python 模块不必要地链接到libpython。此外,这很难检测到,因为libboost_python.so没有将libpython列为报告的依赖项ldd. (我相信 Python 库在这种情况下是动态加载的。)

[稍后添加:这与 Boost.Python 无关。此外,如果使用低级 Python C API,则可以编译 Python 模块并且不与libpython链接,并且可以正常工作。但是,请参阅下面的评论和答案,说明仍然应该链接到libpython。]

那么,我怎么能系统地发现不必要的链接而不是使用试错法呢?什么是好的一般程序,不仅适用于这个例子?

[稍后添加:这是我从对我的问题的评论中学到的。当我发布这个问题时,以下事实对我来说并不清楚,所以我现在把它们拼出来,为了将来访问这个讨论的人的利益,即使这些事情对有帮助的评论者来说是显而易见的。(谢谢!)

解析符号在 Linux 中以传递的方式工作(正如用户 MvG 和 millimoose 所指出的那样)。假设程序A需要从libBlibC解析符号。进一步假设AlibB相关联,而libBlibC相关联。然后A可以加载并执行,即使它不直接引用libC

然而,正如评论者指出的那样,依赖这种传递性是不好的做法。对于用 C/C++ 编写的 Python 模块,这意味着应该链接到libpython。对于一般情况,目标应该是确定链接和执行所需的最小库列表(正如我最初的问题以某种方式暗示的那样),而是真正为链接器提供必要的库,以便可以直接解析所有符号。

总结 Salgar 的回答,这些信息通常只能从所使用的库的文档中获得。此外,GCC 链接器标志-Wl,--as-needed对于识别真正不需要的库很有用。]

4

3 回答 3

5

没有办法神奇地知道要包含哪些库,就像没有办法神奇地知道要包含哪些头文件一样。

可能有 10 个不同的库,它们都有同名的函数,都做着完全不同的事情。由您决定要使用哪一个。

通常情况并非如此,但它提供了一个示范点。

通常,如果您使用的是 boost 库或其他类似的库,它们的文档会让您知道需要链接哪个库。

如上所述,您可以过度包含并使用标志 --as-needed,但很多人会遇到问题,因为通常当您链接库时,它会在启动时被拉入,并且该库中的所有全局变量被初始化。是否需要这些全局变量对于链接器来说可能是一件令人困惑的事情。

简而言之,答案通常是阅读文档。或者编译代码并查看您得到哪些链接器错误,然后从那里开始找出您需要哪些库。

于 2013-04-04T11:07:37.757 回答
0

没有任何 /trivial/ 方法,但您可以使用 CMake 或 AutoConf 等构建管理工具让自己更轻松。

于 2013-06-01T06:33:23.743 回答
0

构建 Boost 时,您可以选择构建已编译库的静态或动态版本。自从我构建 boost 以来已经有一段时间了,但如果我记得如果你只是简单地构建它,它就可以构建两种口味。

这包括在:

关于 boost.python,这里记录了静态或动态库链接之间的选项:

动态库是最安全和最通用的选择:

  • 使用给定工具集构建的所有扩展模块都使用库代码的单个副本。3 该库包含一个类型转换注册表。因为一个注册表在所有扩展模块之间共享,所以在一个动态加载的扩展模块中向 Python 公开的类的实例可以传递给在另一个此类模块中公开的函数。

在以下任何情况下使用静态 Boost.Python 库可能是合适的:

  • 您正在扩展python,并且动态加载的扩展模块中公开的类型不需要被任何其他 Boost.Python 扩展模块使用,并且您不在乎核心库代码是否在它们之间重复。

  • 您正在将 python 嵌入到您的应用程序中,并且:

    • 您的目标是 MacOS 或 AIX 以外的 Unix 变体操作系统,其中动态加载的扩展模块可以“看到”作为可执行文件一部分的 Boost.Python 库符号。

    • 或者,您已经将一些 Boost.Python 扩展模块静态链接到您的应用程序中,并且您不在乎是否有任何动态加载的 Boost.Python 扩展模块能够使用您的静态链接扩展模块公开的类型(反之亦然) )。

所以,当然,这并不能解释你如何知道一般意义上的链接。只是一种特定的情况。

我认为,对于 boost.python 的工作原理以及人们在链接方面评论的不同体验的困惑,至少当你从这个角度来看时,可能会更有意义。

于 2013-06-01T07:16:13.457 回答