我正在将代码库移至cmake,根据要构建的可执行文件,需要特定库的不同实现。在某些情况下,这是因为生成的可执行文件具有不同的要求/功能,但是在许多情况下,是这样,我们可以引入可以由生产中未使用的单元测试控制的实现。
由于库需要依赖接口而不是实现,因此在某些情况下cmake无法正确构建依赖关系树,从而导致链接步骤失败(此问题here)。
例如,考虑下面的人为例子。存在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无法正确设置链接顺序,因此无法将链接链接到库a中定义的函数的未定义引用。
我知道一些解决方法,但是它们不是最佳的。将库a的实现定义为对象库是可行的,但是扩展性不好,因为这些实现将针对每个可执行文件重新编译。使用链接器--whole-archive
标志也可以使用,但扩展性也不佳,因为它会导致大于所需的可执行文件,因为库中未调用的符号将不会被垃圾回收。
cmake中是否有一种方法可以指示一个库实现了一个接口库,以使链接顺序正确?或者,是否可以更改定义库的方式来解决此问题?