c++ - 重新排序链接库如何修复多个定义错误?
问题描述
我遇到了这样一种情况,即不同的链接librdkafka和Pulsar C++ 客户端的顺序确实很重要,因为它们都包含它们的 LZ4 压缩版本。由于 LZ4 函数的多个定义(librdkafka 和 Pulsar 对这些函数具有相同的名称),链接失败。我检查了静态库,但我找不到任何可疑的东西,为什么它以一种顺序工作而不能在另一种顺序中工作。因为很难为那些大型库提供一个最小的工作示例,所以我尝试重现相同的情况,并且我能够做到。我创建了一个链接顺序很重要的小项目。
libA.hpp:
#pragma once
void NotClashingFunctionA();
void ClashingFunction();
libA.cpp:
#include "libB.hpp"
#include <iostream>
void NotClashingFunctionA() {
std::cout << "Not clashing function A\n";
}
void ClashingFunction() {
std::cout << "Clashing function A\n";
}
libB.hpp:
#pragma once
void NotClashingFunctionB();
libB.cpp:
#include "libB.hpp"
#include <iostream>
void NotClashingFunctionB() {
std::cout << "Not clashing function B\n";
}
libBSub.hpp:
#pragma once
void ClashingFunction();
libBSub.cpp:
#include "libBSub.hpp"
#include <iostream>
void ClashingFunction() {
std::cout << "Clashing function B\n";
}
主.cpp:
#include "libA.hpp"
#include "libB.hpp"
#include "libBSub.hpp"
int main() {
NotClashingFunctionA();
NotClashingFunctionB();
ClashingFunction();
return 0;
}
CMakeLists.txt:
project(clashing)
add_library(A STATIC libA.cpp)
add_library(B STATIC libB.cpp libBSub.cpp)
add_executable(working main.cpp)
target_link_libraries(working A B)
add_executable(failing main.cpp)
target_link_libraries(failing B A)
从日志中我可以清楚地看到working
链接很好:
clang++ -g -rdynamic CMakeFiles/working.dir/main.cpp.o -o working libA.a libB.a
make[3]: Leaving directory 'build'
[100%] Built target working
但failing
无法链接:
clang++ -g -rdynamic CMakeFiles/failing.dir/main.cpp.o -o failing libB.a libA.a
ld: libA.a(libA.cpp.o): in function `ClashingFunction()':
libA.cpp:9: multiple definition of `ClashingFunction()'; libB.a(libBSub.cpp.o):libBSub.cpp:5: first defined here
clang-12: error: linker command failed with exit code 1 (use -v to see invocation)
我删除了通用前缀以使日志更具可读性。
如您所见,两者之间的唯一区别是链接顺序A
和B
. 我不知道为什么它按A B
顺序工作,而不是B A
按顺序工作。
如果您不能详细解释,也非常感谢帮助关键字,因为我完全不知道为什么会这样。
解决方案
举一个具体的例子:
- 假设
main.o
定义main()
、fn()
和 引用a()
和b()
。 libA.a
包含a.o
定义a()
libB.a
包含b.o
哪些定义b()
,以及哪些a1.o
定义a()
和fn()
。
现在,如果您使用 链接gcc main.o -lA -lB
,则链接将成功(将选择a.o
fromlibA.a
和b.o
fromlibB.a
进入链接,不会出现符号冲突。值得注意的是,不会选择a1.o
from进入链接)。libB.a
但是如果你用 链接gcc main.o -lB -lA
, thenfn()
会被多重定义(因为a1.o
和b.o
fromlibB.a
都会被选入链接,但是 in 的定义fn()
会和ina1.o
的定义冲突)。fn()
main.o
推荐阅读
- javascript - 如何在“for循环”控制的绘图功能中控制html5画布中的帧速率
- html - 使用 .htaccess 文件时出现内部错误,但为什么呢?
- angular - 在 Intellij/Webstorm 中显示 es-lint html 错误
- numpy - numpy - 有没有办法在 arr[1, [0, 2, 0, 2, 0]] += 1 处引起多个增量
- python - 使用 Tkinter 移动自定义标题栏窗口,而不从左上角移动
- php - 具有指定条件的过滤器数组
- javascript - 我很难从软件中的网页访问数据
- unit-testing - 使用 stack 和 hpack 运行自定义测试
- node.js - 如何在 Multer 中更改文件的原始名称
- php - 如何在 SQLite 中使用管理员编辑器?