首页 > 解决方案 > 重新排序链接库如何修复多个定义错误?

问题描述

我遇到了这样一种情况,即不同的链接librdkafkaPulsar 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)

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

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

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

标签: c++linkerlinker-errorsmultiple-definition-error

解决方案


要了解原因,请阅读此(较早的)帖子(更好的)帖子。

举一个具体的例子:

  • 假设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.ofromlibA.ab.ofromlibB.a进入链接,不会出现符号冲突。值得注意的是,不会选择a1.ofrom进入链接)。libB.a

但是如果你用 链接gcc main.o -lB -lA, thenfn()会被多重定义(因为a1.ob.ofromlibB.a都会被选入链接,但是 in 的定义fn()会和ina1.o的定义冲突)。fn()main.o


推荐阅读