了解 g++ 链接器失败

Understand g++ linker failure

给定一个静态库,您可以使用它进行检查

$nm libgtest.a

为什么下面的构建会找不到符号?

g++ -ISomePathToGTest -lgtest SomeUnitTests.cpp

许多未定义的引用之一如下所示:

SomeUnitTests.cpp:(.text+0x28): undefined reference to `testing::InitGoogleTest(int*, char**)'

但是我从上面的 'nm' 命令中得到了这些行:

000000000000ffca T _ZN7testing14InitGoogleTestEPiPPc
000000000000ffca T _ZN7testing14InitGoogleTestEPiPPw

其中,根据 nm 手册,'T' 表示该系统位于我正在检查的库的文本部分。我确定它不会从其他任何地方选择这个库,而是找到我正在使用该构建命令使用的这个库。

像这样为 SomeUnitTests.cpp 构建对象:

g++ -c -ISomePathToGTest SomeUnitTests.cpp

用 nm 检查它只显示下面这个条目,用于在 InitGoogleTest 上搜索:

U _ZN7testing14InitGoogleTestEPiPPc

所以,他们应该匹配吧?但是,关注链接器如何匹配符号而不是我正在使用 gtest,为什么会失败?

为清楚起见,简化您的命令行:

g++ -ISomePathToGTest -lgtest SomeUnitTests.cpp

调用 g++ 工具驱动程序来执行以下操作:

  1. 调用GNU C++编译器cc1plus编译SomeUnitTests.cpp为 一个临时的汇编语言文件,命令行基本上像:

    cc1plus -ISomePathToGTest SomeUnitTests.cpp -o /tmp/aaaa.s

  2. 调用GNU assembler as to assemble aaaa.s to 一个临时目标文件,命令行基本上像:

    as -ISomePathToGTest -o /tmp/bbbb.o /tmp/aaaa.s

  3. 调用 GNU linker ld to link bbbb.o with the specified 和默认库,命令行基本上像:

    ld -L/default/library/search/paths... -lgtest /tmp/bbbb.o -lstdc++ -lother -ldefault -llibraries...

在 linker 命令行中,目标文件和指定库的排序 反映相应的源文件和指定的库在你的 原始命令行:因为目标文件和库的排序 很重要 对 linker,g++ 的工作假设你知道这个,那个 命令行表达你想要的顺序。

目标文件和库的顺序对 linker 很重要,因为 它将搜索库以查找某个符号的定义 foo 如果 并且仅当它已经看到的某个目标文件(或库)使 对 foo 的未定义引用;如果它在库中找到定义 那么它将不会在以后的库中搜索它的其他定义。

这样做的结果是必须在 所有对象之后提及库 引用它的文件或未定义的引用将确保。在 link您的命令行 libgtest 未被 linker 检查 根本没有,因为到目前为止还没有看到目标文件,也没有 要解析的未定义符号。当目标文件 /tmp/bbbb.o 是 随后检查,其未定义的引用只能 在随后的默认库中获取定义,保留所有引用 libgest 的符号未解析。

现在您知道为什么将 -lgtest 移动到末尾的问题的答案了 命令行 "changes the linking order"。这是因为 你就是这样 请求:您请求的不是库对象文件(失败),而是对象文件库(成功)。

这里是the linker's commandline manual-l namespec 的文档是相关项目。