了解 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++
工具驱动程序来执行以下操作:
调用GNU C++编译器cc1plus
编译SomeUnitTests.cpp
为
一个临时的汇编语言文件,命令行基本上像:
cc1plus -ISomePathToGTest SomeUnitTests.cpp -o /tmp/aaaa.s
调用GNU assembler as
to assemble aaaa.s
to
一个临时目标文件,命令行基本上像:
as -ISomePathToGTest -o /tmp/bbbb.o /tmp/aaaa.s
调用 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
的文档是相关项目。
给定一个静态库,您可以使用它进行检查
$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++
工具驱动程序来执行以下操作:
调用GNU C++编译器
cc1plus
编译SomeUnitTests.cpp
为 一个临时的汇编语言文件,命令行基本上像:cc1plus -ISomePathToGTest SomeUnitTests.cpp -o /tmp/aaaa.s
调用GNU assembler
as
to assembleaaaa.s
to 一个临时目标文件,命令行基本上像:as -ISomePathToGTest -o /tmp/bbbb.o /tmp/aaaa.s
调用 GNU linker
ld
to linkbbbb.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
的文档是相关项目。