CMake中如何让lib目标自动传递依赖符号给链接它的test目标?
项目结构
project/ lib/ CMakeLists.txt lib.cpp lib.h sublib/ CMakeLists.txt sublib.h sublib.cpp test/ CMakeLists.txt test.cpp # 仅需链接lib,不能同时链接lib和sublib
原模块CMake配置
- project/CMakeLists.txt:
add_subdirectory(lib) add_subdirectory(test)
- project/test/CMakeLists.txt:
add_executable(test test.cpp) add_test(test test) target_link_libraries( test lib)
- project/lib/CMakeLists.txt:
add_subdirectory(sublib) add_library(lib lib.cpp) target_link_libraries( lib sublib)
- project/lib/sublib/CMakeLists.txt:
add_library(sublib sublib.cpp) target_link_libraries( sublib 其他依赖库如thrift)
原错误与需求
lib.cpp中调用了Sublib::process(),但编译test时出现链接错误:
Undefined symbols for architecture x86_64: "Sublib::process()", reference from: Sublib::process() in lib.cpp.o ld: symbol(s) not found for architecture x86_64
需求:让test仅链接lib就能解析所有符号,无需手动添加sublib依赖(存在大量类似test的目标)。
修改后的配置与新错误
按照建议将sublib改为OBJECT库并添加install导出配置:
- project/lib/sublib/CMakeLists.txt修改为:
add_library(sublib OBJECT sublib.cpp) target_link_libraries( sublib other_libs) install(TARGETS sublib EXPORT sublib) message (STATUS "Installed sublib") install(EXPORT sublib FILE sublibConfig.cmake NAMESPACE sublib:: DESTINATION lib/cmake/sublib)
- project/lib/CMakeLists.txt修改为:
add_subdirectory(sublib) find_package(iceberg CONFIG REQUIRED) add_library(lib OBJECT lib.cpp) target_include_directories(lib PUBLIC sublib::sublib) target_link_libraries( lib PRIVATE other_libs PUBLIC sublib::sublib)
执行构建命令cmake --build /.../project/cmake-build-debug --target test -j 14时出现错误:
-- Installed sublib CMake Error at project/lib/CMakeLists.txt:21 (find_package): Could not find a package configuration file provided by "sublib" with any of the following names: sublibConfig.cmake sublib-config.cmake Add the installation prefix of "sublib" to CMAKE_PREFIX_PATH or set "sublib_DIR" to a directory containing one of the above files. If "sublib" provides a separate development package or SDK, be sure it has been installed. -- Configuring incomplete, errors occurred! See also "...project/cmake-build-debug/CMakeFiles/CMakeOutput.log". See also "...project/cmake-build-debug/CMakeFiles/CMakeError.log".
疑问
- 当前配置是否存在错误?
- sublib的两个install命令是否必要?
FILE sublibConfig.cmake的命名是否正确?
解答
1. 配置中的核心错误
你在project/lib/CMakeLists.txt里用了find_package(sublib),但sublib是通过add_subdirectory引入的本地子模块,根本不需要用find_package查找。find_package是用来查找已安装到系统或指定路径的外部库,本地子模块在add_subdirectory之后直接就能用目标名sublib,无需通过包配置导入。
另外,target_include_directories(lib PUBLIC sublib::sublib)这行错误,target_include_directories需要传入路径而非目标别名,规范做法是让sublib通过target_include_directories对外暴露头文件路径,再让lib通过链接sublib自动继承该路径。
2. sublib的install命令是否必要?
如果你的项目不需要把sublib作为独立包安装到系统,仅作为lib的内部依赖,那这两个install命令完全没必要。install导出配置是给外部项目引用该库用的,而你的场景中sublib是lib的子模块,test只需链接lib即可,无需单独安装sublib。
3. FILE sublibConfig.cmake命名是否正确?
命名本身符合CMake规范,CMake会优先查找xxxConfig.cmake或xxx-config.cmake格式的文件,但问题在于你根本不需要生成这个配置文件——sublib是本地子模块,不是外部依赖。
正确修改方案
方案1:保持静态库,自动传递依赖(最简单)
无需改成OBJECT库,只需确保lib链接sublib时使用PUBLIC关键字,让依赖自动传递给链接lib的test:
- project/lib/CMakeLists.txt修改为:
add_subdirectory(sublib) add_library(lib lib.cpp) # 用PUBLIC让lib的依赖自动传递给链接它的目标 target_link_libraries(lib PUBLIC sublib)
- project/lib/sublib/CMakeLists.txt修改为:
add_library(sublib sublib.cpp) target_link_libraries(sublib PRIVATE other_libs) # 用PUBLIC暴露头文件路径,让lib自动继承 target_include_directories(sublib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
这样test仅链接lib,CMake会自动把sublib及其依赖传递过去,解决符号未找到问题。
方案2:使用OBJECT库(若确实需要)
如果一定要用OBJECT库,正确配置如下:
- project/lib/sublib/CMakeLists.txt:
add_library(sublib OBJECT sublib.cpp) target_link_libraries(sublib PRIVATE other_libs) target_include_directories(sublib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) # 不需要install命令
- project/lib/CMakeLists.txt:
add_subdirectory(sublib) find_package(iceberg CONFIG REQUIRED) # 将sublib的OBJECT文件合并到lib中(CMake 3.12+支持直接链接OBJECT目标) add_library(lib OBJECT lib.cpp) target_link_libraries(lib PUBLIC sublib iceberg::iceberg) # 若需要合并OBJECT文件,可改用: # add_library(lib lib.cpp $<TARGET_OBJECTS:sublib>) # target_link_libraries(lib PUBLIC iceberg::iceberg PRIVATE other_libs)
这样test链接lib时,会包含sublib的目标文件,解析所有符号。
内容的提问来源于stack exchange,提问作者user2577547

