使用g ++,当两个编译单元" a1.o"和" a2.o"两者都定义并使用相同的弱符号,链接器将静默地解析为符号的第一次出现,无论它在何处使用。因此,应用程序的行为将取决于链接器命令行上的目标文件的顺序。可以做些什么来确保这些符号在本地解析到每个编译单元?
例如,作为一个极简主义的例子,如果我有以下源文件:
a1.cpp:
#include <iostream>
struct A
{
void foo() {std::cerr << __FILE__ << std::endl;}
};
void bar1() {A a; a.foo();}
a2.cpp:
#include <iostream>
struct A
{
void foo() {std::cerr << __FILE__ << std::endl;}
};
void bar2() {A a; a.foo();}
main.cpp中:
void bar1();
void bar2();
int main()
{
bar1();
bar2();
}
并使用以下命令编译它们:
for i in a1 a2 main ; do g++ -c -o $i.o $i.cpp ; done
输出将取决于链接器命令行上a1.o和a2.o的相对位置:
g++ -o main main.o a{1,2}.o ; ./main
a1.cpp
a1.cpp
g++ -o main main.o a{2,1}.o ; ./main
a2.cpp
a2.cpp
我希望得到与使用&#39; -fno-weak&#39;相同的结果。命令行选项:
for i in a1 a2 main ; do g++ -fno-weak -c -o $i.o $i.cpp ; done
g++ -o main main.o a{1,2}.o ; ./main
a1.cpp
a2.cpp
但是&#39; -fno-weak&#39;似乎导致其他并发症。有什么替代方案(除了不内联和修复碰撞)?
对于那些想知道什么是典型用例的人:在编写模拟组件时,有时候只有标头实现很方便。不同的测试夹具最终具有相同组件类型的不同模拟实现,当所有夹具链接到单个测试运行器时,这成为一个问题。
答案 0 :(得分:4)
你问:
有哪些替代方案(除了不内联和修复碰撞)?
使用本地namespace
或匿名namespace
。
a1.cpp:
#include <iostream>
namespace A1_namespace
{
struct A
{
void foo() {std::cerr << __FILE__ << std::endl;}
};
}
using namespace A1_namespace;
void bar1() {A a; a.foo();}
或
#include <iostream>
namespace
{
struct A
{
void foo() {std::cerr << __FILE__ << std::endl;}
};
}
void bar1() {A a; a.foo();}
对a2.cpp进行类似的更改。