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

How can reordering the linked libraries fix multiple definitions error?

我遇到了 linking librdkafka and the Pulsar C++ client does matter, because both of them include their version of LZ4 compression. The linking fails because of multiple definitions of LZ4 functions (both librdkafka and Pulsar have the same names for those functions). I checked the static libraries, but I couldn't find anything suspicious, why it works in one order and doesn't in the another. Because it is hard to provide a minimal working example with those big libraries, I tried to reproduce the same situation, and I was able to do so. I created a small project 的不同顺序,其中 linking 顺序很重要。

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";
}

main.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 只是 link 没问题:

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没能link:

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)

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

如您所见,两者之间的唯一区别是 linking 顺序 AB。我不知道为什么它按 A B 顺序工作,而不是 B A 顺序。

如果您无法详细解释,也非常感谢帮助关键字,因为我完全不知道为什么会这样。

要了解为什么,请阅读这个(更早)post or this(更好)一个。

举个具体的例子:

  • 假设 main.o 定义 main()fn(),并引用 a()b()
  • libA.a 包含 a.o 定义 a()
  • libB.a 包含定义 b()b.o 以及定义 a()fn().

现在,如果您 link 和 gcc main.o -lA -lB,link 将成功(a.o 来自 libA.ab.o 来自 libB.a将被选入link,不会出现符号冲突。值得注意的是,libB.a中的a1.o不会被选入而不是 link).

但是如果你 link 和 gcc main.o -lB -lA,那么 fn() 将被 多重定义 (因为 a1.o 和 [ libB.a中的=19=]会被选入link中,但a1.o中定义的fn()会与fn()中的定义冲突main.o).