【问题标题】:How does the C++ linker know which .lib contains which functions?C++ 链接器如何知道哪个 .lib 包含哪些函数?
【发布时间】:2011-07-08 06:42:22
【问题描述】:

例如在 Boost 中。我将 MSVC++2010 中的 include 目录设置为 Boost 根目录,并在我的源代码中有一个 #include <boost/regex.hpp>。我将 library 目录设置为 boost\stage\lib,但其中有数百个文件 - 每个 Boost 库都有几个文件,这些文件用于 boost::regex:

libboost_regex-vc100-s-1_46.lib libboost_regex-vc100-mt-gd-1_46.lib libboost_regex-vc100-mt-1_46.lib libboost_regex-vc100-mt-s-1_46.lib libboost_regex-vc100-mt-s.lib libboost_regex-vc100-s.lib libboost_regex-vc100-mt.lib libboost_regex-vc100-mt-gd.lib

MSVC 如何知道所有 lib 文件中的哪一个是正确的?如果它扫描所有这些以查找正确的函数签名,这是否意味着从两个不同的源(未相互链接)编译的 2 个不同的 lib 恰好定义了具有相同名称和参数的函数不能在一个 lib 文件夹中?

它如何知道在所有这些不同的正则表达式 .lib 中哪个是正确的?然后,每个文件名中带有1_46 的文件似乎与没有的文件相同,我可以安全地删除两者之一吗?

【问题讨论】:

  • 我敢打赌,如果您查看 regex.hpp 内部,您会发现数十个 #pragma library 语句(或类似语句。我忘记了确切的语法)

标签: c++ boost linker


【解决方案1】:

boost 库使用一些黑魔法从头文件和编译器选项中选择要链接的库。我真的不知道所有血淋淋的细节,但您可以查看 boost/config/auto_link.hpp 标头以获取更多信息。

特别是,这似乎是难题的重要组成部分:

#  pragma comment(lib, BOOST_LIB_PREFIX BOOST_STRINGIZE(BOOST_LIB_NAME) "-" BOOST_LIB_TOOLSET BOOST_LIB_THREAD_OPT BOOST_LIB_RT_OPT "-" BOOST_LIB_VERSION ".lib")

【讨论】:

  • 嗯,很好。我只是想知道为什么他们不会在名称中包含他们的“地址类型”(32/64 位)。在两个版本中编译一个模块仍然是一些手动工作,因为库路径不能是两个版本的默认路径(boost\stage\lib)。
【解决方案2】:

大多数lib 文件都有一个目录。链接器在查找符号时会搜索此表。如果未找到该符号,则它会移动到下一个库,依此类推,直到搜索完所有库。

一些链接器可能会决定从所有库中构建目录。该表将包含符号名称和与之关联的库。这加快了对符号的搜索。

搜索顺序取决于链接器的制造商。对此没有标准或要求。链接器可以按照命令行中指定的先到先得进行搜索; 指定的最后一个库或其他方法。检查标准的文档。

同时在网上搜索name mangling。这是编译器用来解决符号命名冲突的一种技术。

最后,链接器可以包含库中的所有函数,即使只使用一个函数。一些链接器只包含函数的代码。取决于链接器的制造商。例如,在解析puts 时,链接器是否包含整个 I/O 库,还是仅包含必要的函数?包含整个库会加快构建时间,但会使可执行文件变得庞大。只包含必要的代码会减慢构建过程,但会缩小可执行文件的大小。

通常,链接阶段是翻译过程中较快的部分之一。如果您担心构建时间,请在一天结束时开始构建,或者在构建开始后去散步。 ;-)

【讨论】:

  • 这解释了链接器的一般工作原理,但它没有回答问题。 Boost 在没有程序员指定的情况下神奇地与 正确的 lib 文件链接,但是如何?
【解决方案3】:

两个包含相同功能的库不是问题。链接器只查看它被告知要查看的库。如果其中两个包含相同的函数,它会给出一个错误消息(这实际上是相当普遍的,通常是由于与标准库的静态和动态链接之间的冲突)。

您可以通过多种方式告诉链接器查看哪些库 -- 在链接器命令行(可能由 IDE 生成)和通过#pragma comment(lib, "libname.lib") 是最常见的两种方式。

【讨论】:

  • 几乎是真的杰瑞。在两个链接的库中拥有两个同名函数是完全有效的。我这样做是为了拥有自己的 malloc、free、...但是(一个很大的但是)你必须确保否决库中第二个定义的所有外部符号。一旦链接器解析了一个符号名称,它就不会再寻找该符号的第二次出现。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-03
  • 1970-01-01
相关资源
最近更新 更多