重新排序链接库如何修复多个定义错误?

Ján*_*tal 5 c++ linker linker-errors multiple-definition-error

我遇到过这样的情况:librdkafkaPulsar C++ 客户端的链接顺序不同确实很重要,因为它们都包含各自的 LZ4 压缩版本。由于 LZ4 函数的多个定义(librdkafka 和 Pulsar 的这些函数的名称相同),链接失败。我检查了静态库,但我找不到任何可疑的东西,为什么它按一个顺序工作而按另一个顺序却不工作。因为很难为这些大库提供最小的工作示例,所以我尝试重现相同的情况,并且我能够做到这一点。我创建了一个小项目,其中链接顺序很重要。

libA.hpp:

#pragma once

void NotClashingFunctionA();
void ClashingFunction();
Run Code Online (Sandbox Code Playgroud)

libA.cpp:

#include "libB.hpp"

#include <iostream>

void NotClashingFunctionA() {
    std::cout << "Not clashing function A\n";
}

void ClashingFunction() {
    std::cout << "Clashing function A\n";
}
Run Code Online (Sandbox Code Playgroud)

libB.hpp:

#pragma once

void NotClashingFunctionB();
Run Code Online (Sandbox Code Playgroud)

libB.cpp:

#include "libB.hpp"

#include <iostream>

void NotClashingFunctionB() {
    std::cout << "Not clashing function B\n";
}
Run Code Online (Sandbox Code Playgroud)

libBSub.hpp:

#pragma once

void ClashingFunction();
Run Code Online (Sandbox Code Playgroud)

libBSub.cpp:

#include "libBSub.hpp"

#include <iostream>

void ClashingFunction() {
    std::cout << "Clashing function B\n";
}
Run Code Online (Sandbox Code Playgroud)

主要.cpp:

#include "libA.hpp"
#include "libB.hpp"
#include "libBSub.hpp"

int main() {
    NotClashingFunctionA();
    NotClashingFunctionB();
    ClashingFunction();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

从日志中我可以清楚地看到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
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

我删除了常见的前缀以使日志更具可读性。

正如您所看到的,两者之间的唯一区别是链接顺序AB。我不知道为什么它按A B顺序运行,而不是B A按顺序运行。

如果你不能详细解释它,也非常感谢帮助关键字,因为我完全不知道为什么会发生。

Emp*_*ian 1

要了解原因,请阅读这篇(较早的)文章这篇(更好的)文章。

举一个具体的例子:

  • 假设main.o定义main()fn()、 以及引用a()b()
  • libA.a包含a.o其中定义a()
  • libB.a包含b.owhich 定义b()包含a1.owhich 定义a()fn()

现在,如果使用 链接gcc main.o -lA -lB,则链接会成功(a.ofromlibA.ab.ofromlibB.a会被选入链接,不会出现符号冲突。值得注意的是,a1.ofromlibB.a不会被选入链接)。

但如果用 链接gcc main.o -lB -lA,则将fn()多重定义(因为 和a1.ofromb.o都会libB.a被选入链接,但fn()in的定义将与ina1.o的定义冲突)。fn()main.o