强制链接器失败并出现多重定义错误,即使包括 --whole-archive
Force a linker to fail with a multiple definition error, even if including --whole-archive
此示例由多个文件组成:
// baz.cxx
int wat = 0;
int counter = ++wat;
// foo.cxx (empty)
// bar.cxx (empty)
// main.cxx
#include <iostream>
extern int wat;
int main() {
std::cout << wat << 'n';
}
// makefile
run : main.cxx foo.so bar.so
g++ -std=c++11 $^ -o $@
baz.a : baz.cxx
g++ -std=c++11 -c $^ -o baz.o -fPIC
ar rcs $@ baz.o
%.so : %.cxx baz.a
g++ -std=c++11 $< -Wl,--whole-archive baz.a -Wl,--no-whole-archive -o $@ -shared -fPIC
按原样,如果您只是运行make && LD_LIBRARY_PATH=. ./run
,则编译、构建、链接、运行和输出的所有内容2
。这是因为foo.so
和bar.so
都提供wat
,并且counter
的初始化运行两次。
在这种情况下,有没有办法以某种方式强制run
无法与多重定义错误链接,同时仍然确保foo.so
和bar.so
都有wat
的定义?
您可以使用链接器脚本libfoo.so
和libbar.so
静态部分,这会产生符号冲突(并将实际的 DSO 安装在一些不明显的地方,以便-lfoo
和-lbar
不会拾取它们(。
像这样:
-
libfoo.so
INPUT(conflict.o) INPUT(./foo.so)
-
libbar.so
INPUT(conflict.o) INPUT(./bar.so)
-
conflict.cxx
int conflict;
这导致:
g++ -std=c++11 main.cxx -o run -L. -lfoo -lbar
conflict.o:(.bss+0x0): multiple definition of `conflict'
conflict.o:(.bss+0x0): first defined here
collect2: error: ld returned 1 exit status
这只会检测链接编辑器的同一运行中的冲突。 您仍然可以使用-lfoo
和-lbar
链接两个不同的 DSO,并将这两个链接到应用程序中,而不会从链接编辑器出错。
ABI 注释解决了类似的问题,但我认为这些注释需要特定的ld
更改。
如果运行时检查是可以接受的,则可以具有由需要冲突的每个 DSO 定义的弱符号列表,并实现一个 ELF 构造函数,如果定义了多个 ELF 构造函数,该构造函数将中止该过程。 我不知道有什么东西可以在静态链接时与 GNU 工具链实现同样可靠的东西。 也许这值得针对binutils的RFE错误。
我认为解决问题的唯一正确方法是将解决方案的内容移动到某个共享库bar.a
从而解决钻石继承问题......但我认为这超出了这个问题的范围。
我唯一能为您考虑的就是创建在链接最终可执行文件之前执行的"自定义"验证器。像这样:
nm *.so | # get all symbols
grep " [B|T] " | # only exported ones
egrep -v "__bss_start|_end|_fini|_init" | # filter out some commons, probably to be extended
awk '{print $3}' | # get only symbol name
sort | uniq -c | # sort and count
egrep -v "^[ ]+1 " # get only those that have multiple definitions
这将打印多次定义的库中的所有强(导出(符号。您可以轻松地将其包装在一个脚本中,如果输出不为空并显示有意义的消息,则返回错误状态代码。
修补的生成文件的实验版本如下所示:
run: main.cxx foo.so bar.so
! nm foo.so bar.so | grep " [B|T] " | egrep -v "__bss_start|_end|_fini|_init" | awk '{print $3}' | sort | uniq -c | egrep -v "^[ ]+1 "
g++ -std=c++11 $^ -o $@
(注意!
以反转最终 grep 的退出代码,该代码搜索任何不以 bare 1 开头的uniq -c
输出(
我知道它确实是黑客,丑陋且不可移植的解决方案,但我认为它在像您这样的极端情况下可能具有一定的价值。
- 如何修复此错误:未定义对"距离(浮点数,浮点数,浮点数,浮点数,浮点数)"的引用
- 我的项目不会像"undefined reference to `grpc::g_core_codegen_interface'"那样使用未定义的引用错误进行编译
- 在没有定义返回类型的函数中返回布尔值,并将结果保存在无错误的char编译中-为什么
- 使用命名空间时出现多个定义错误
- C++错误C2600:无法定义编译器生成的特殊成员函数(必须首先在类中声明)
- 对C宏的未定义引用,但在定义它时会出现重新定义错误
- 编写代码时C++出现错误:错误 1 错误 C2601:'circle':本地函数定义是非法的
- 在运算符重载定义中使用成员函数(const错误)
- 尝试调用 .h 文件中定义的变量时出现变量未定义错误
- 在C++中使用内联方法时出现未定义的符号错误
- 已定义函数时出现 G++ "未定义的引用"错误
- C++ G++ 编译器 - 错误:隐式声明的定义
- 链接 cmake 时出现未定义的引用错误
- 在头文件和 cpp 文件中使用一次 #pragma 时出现结构重定义错误
- 错误:未定义对'oboe::AudioStreamBuilder::openStream(oboe::AudioStream**)'的引用
- 链接阶段出现多重定义错误
- 已经以性格错误定义了
- vim ctag导致了对乐趣的错误定义
- C++ 隐式声明的编译器错误定义
- 编译器错误-定义问题.C++