首页 > 解决方案 > 使用具有多个实现的接口库时的链接器错误

问题描述

我正在将代码库移动到 cmake,具体取决于构建哪个可执行文件,需要特定库的不同实现。在某些情况下,这是因为生成的可执行文件具有不同的要求/功能,但在许多情况下,我们可以引入可以由未在生产中使用的单元测试控制的实现。

由于库需要依赖于接口而不是实现,因此在某些情况下,cmake 无法正确构建依赖关系树,从而导致链接步骤失败(此处描述的问题)。

例如,考虑以下人为的示例。存在 2 个库 a 和 b,其中 b 依赖于 a,a 有两个实现。我在以下位置定义了目标CMakeLists.txt

add_library(lib-a-intf INTERFACE)
target_include_directories(lib-a-intf INTERFACE lib-a)

add_library(lib-a-impl-a impl-a/impl-a.cpp)
target_link_libraries(lib-a-impl-a PUBLIC lib-a-intf)

add_library(lib-a-impl-b impl-b/impl-b.cpp)
target_link_libraries(lib-a-impl-b PUBLIC lib-a-intf)

add_library(lib-b lib-b.cpp)
target_link_libraries(lib-b PRIVATE lib-a-intf)
target_include_directories(lib-b PUBLIC lib-b)

然后可执行文件根据其要求提取所需的版本

add_executable(main main.cpp)
target_link_libraries(main lib-a-impl-b lib-b)

由于 cmake 无法正确设置链接顺序,因此无法将 do 链接到库 a 中定义的函数的未定义引用。

我知道一些解决方法,但它们不是最佳的。将库 a 实现定义为对象库可以工作,但不能很好地扩展,因为这些实现将为每个可执行文件重新编译。使用链接器--whole-archive标志也有效,但也不能很好地扩展,因为它会导致大于必要的可执行文件,因为库 a 中未调用的符号不会被垃圾收集。

cmake 中有没有办法表明一个库实现了一个接口库,使得链接顺序是正确的?或者,有没有办法改变库的定义方式来解决这个问题?

标签: cmakeld

解决方案


推荐阅读