在这种情况下,为什么一个定义规则(ODR)不被g++所接受?.

Why one definition rule (ODR) is not honoured by g++ in this case ? .

本文关键字:g++ 不被 ODR 定义 为什么 这种情况下 一个 规则      更新时间:2023-10-16

正如您所看到的,在链接时testfn符号有多个定义,但是链接器接受第一个出现的定义(按链接顺序),而忽略其他库中的其他出现的定义。这可能就是链接器的工作方式。

但是有没有办法强制链接器在看到不同链接库中的多个符号时标记错误?或者有其他选项来捕获这些重复的定义吗?


test1.h内容:

#ifndef TEST1
#define TEST1
void testfn();
#endif

test1.cpp内容

#include "test1.h"
#include <iostream>
using namespace std;
void testfn()
{
cout << "file1" << endl;
}

test.h:

#ifndef TEST
#define TEST
void testfn();
#endif

test.cpp:

#include "test.h"
#include <iostream>
using namespace std;
void testfn()
{
cout << "file" << endl;
}

main.cpp内容:

#include "test.h"
#include "test1.h"
int main()
{
testfn();
return 0;
}

创建共享库。

 g++ -fPIC -shared libtest1.so test1.cpp
 g++ -fPIC -shared libtest.so test.cpp

创建可执行文件,库顺序为#1

g++ -o main main.cpp -ltest -ltest1

创建可执行文件,库顺序为#2

g++ -o main1 main.cpp -ltest1 -ltest

main

输出
./main
file

main1输出

 ./main1
file1

首先,它尊重ODR,只从库中取出一个方法。这就是共享库的工作方式。

如果你想看到编译器抱怨这个,把它们链接在一起,不需要库步骤。

g++ -o main1 main.cpp test1.cpp test.cpp

所以你的问题变成了,"我如何判断我有两个库,它们都包含具有相同名称的标识符?"请记住,这通常不是问题,有时是故意这样做的。我建议运行库工具(我不熟悉g++工具集)来获得库列表,并运行它们的DIFF。

我看不出有什么办法能让GNU抱怨跨共享库的多个符号定义。但是,如果涉及到普通的静态库存档,则可以使用--whole-archive/--no-whole-archive选项集来获得所需的内容:

例如,在构建libtest.alibtest1.a而不是共享库版本之后,使用以下链接命令没有出现错误:

$ g++  -o main main.cpp   -ltest1 -ltest  -L.
$ ./main
file1
$ g++  -o main main.cpp   -ltest -ltest1  -L.
$ ./main
file

,但是在下列情况下会出现错误:

$ g++  -o main main.cpp -Wl,--whole-archive -ltest1 -ltest -Wl,--no-whole-archive -L.
./libtest.a(test.o): In function `testfn()':
test.cpp:(.text+0x0): multiple definition of `testfn()'
./libtest1.a(test1.o):test1.cpp:(.text+0x0): first defined here
collect2: ld returned 1 exit status

我不确定你是否想要在发布版本中使用--whole-archive -可能只是作为可能的名称冲突的完整性检查(我认为使用--whole-archive通常会毫无理由地增加二进制文件的大小)。

而且,如前所述,这似乎对共享库没有影响。