在这种情况下,为什么一个定义规则(ODR)不被g++所接受?.
Why one definition rule (ODR) is not honoured by g++ in this case ? .
正如您所看到的,在链接时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.a
和libtest1.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
通常会毫无理由地增加二进制文件的大小)。
而且,如前所述,这似乎对共享库没有影响。
相关文章:
- 构造函数采用 Base&不被调用
- 叮叮当当:什么可能导致NOLINT评论不被尊重?
- 为什么"using System;"不被视为不良做法?
- 为什么矢量子项不被修改?
- 野牛/yacc 解析器在不被空格分隔时跳过 grammer - "unexpected $end"
- 为什么数组中对象的析构函数在被另一个对象替换时不被调用?
- 'cmake'不被识别为内部或外部命令 - 北极星
- 为什么注入的类名有时不被视为类模板中的模板名?
- Const Int 宣布与 stoi 不被视为 const
- 如何保护 MSI 不被修改
- 在模板实例化期间,文本值不被视为常量表达式
- 为什么(常量字符*)ptr 不被视为左值
- GLEW/SFML程序未在MinGW中编译 - "GLChar"不被认可
- 为什么这个嵌套的 lambda 不被认为是 constexpr?
- 如何在不被卡住的情况下加入一系列(true)的链条(真)?C
- 为什么具有非 const 复制构造函数的类不被视为可构造复制的类?
- exe文件不被识别为内部或外部命令,可操作的程序或批处理文件在C++
- 等待文件存在并且不被其他人占用
- 受保护的枚举不被视为类型,为什么?
- 就SFINAE而言,访问不存在的成员不被视为"error"吗?