CMake项目迁移:如何先构建依赖库再编译子项目?
从Autotools迁移到CMake的大型项目依赖库构建问题
我正在将一个大型项目从Autotools迁移到CMake,项目里有一批被其他代码依赖的库。但项目的部分模块要拆分到独立仓库,这导致引用这些库时没法直接用目标名称,只能通过find_library或包搜索等方式定位。
给定如下项目结构,如何让CMake先构建这些库,让子项目能找到它们?
main |- CMakeLists.txt (顶层) |- myLibs/ |----CMakeLists.txt (目前仅执行 add_subdirectory(libX)) |----lib (make install 的输出目录) |----include (make install 的公共头文件输出目录) |----mylibA |-------CMakeLists.txt |----mylibB |-------CMakeLists.txt |-projCollections/ (程序集合) |----CMakeLists.txt (依赖 mylibA 和 mylibB) |----projA -> 无法直接引用任何 myLibs 库 |------CMakeLists.txt (依赖 mylibA ) |----projB |------CMakeLists.txt (依赖 mylibA 和 mylibB)
我目前想到几种解决方案:
- 使用
execute_process立即对myLibs执行cmake配置和make命令 - 在projCollections上使用
ExternalProject_add - 在myLibs上使用
ExternalProject
ExternalProject看起来可行,但或许我可以暂时允许直接引用,等源码拆分完成后,再修改所有(100+个)CMakeLists.txt文件改用find_library...
当前基础CMake结构
顶层CMakeLists.txt
cmake_minimum_required(VERSION 3.14) project(main) add_subdirectory(myLibs) add_subdirectory(projCollections)
myLibs/CMakeLists.txt
cmake_minimum_required(VERSION 3.14) project(myLibs DESCRIPTION "myLibs") add_subdirectory(mylibA) add_subdirectory(mylibB)
projCollections/CMakeLists.txt
cmake_minimum_required(VERSION 3.14) project(projCollections DESCRIPTION "projCollections") add_subdirectory(projA) add_subdirectory(projB)
projA/CMakeLists.txt
project(projA ) find_library(MYLIBA NAMES mylibA HINTS ${CMAKE_SOURCE_DIR}/myLibs/libs/mylibA.so NO_DEFAULT_PATH) add_executable(projA) target_link_libraries(projA myLibA)
解决方案推荐
方案1:临时允许直接引用(过渡最优)
既然拆分是未来计划,当前阶段最省心的方式就是保留直接引用,避免提前修改大量CMakeLists.txt。只需确保mylibA和mylibB的CMake配置正确导出目标,后续拆分时再替换为find_package或find_library:
- 在
mylibA/CMakeLists.txt和mylibB/CMakeLists.txt中添加安装与导出配置(以mylibA为例):
add_library(mylibA ...) # 配置公共头文件路径,兼容构建和安装两种场景 target_include_directories(mylibA PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<INSTALL_INTERFACE:include> ) # 安装目标文件和头文件 install(TARGETS mylibA EXPORT mylibA-targets LIBRARY DESTINATION lib INCLUDES DESTINATION include ) install(DIRECTORY include/ DESTINATION include) # 导出CMake配置文件,供拆分后find_package使用 install(EXPORT mylibA-targets FILE mylibAConfig.cmake DESTINATION lib/cmake/mylibA )
- 修改
projA/CMakeLists.txt,直接用目标名链接:
project(projA) add_executable(projA ...) # 直接引用目标,CMake自动处理依赖构建顺序 target_link_libraries(projA PRIVATE mylibA)
这种方式完全兼容未来拆分:拆分后只需在projA中替换为find_package(mylibA REQUIRED),其余链接逻辑不变,修改量极小。
方案2:用ExternalProject构建myLibs(模拟拆分后依赖)
如果想提前模拟拆分后的依赖模式,推荐在顶层CMake中用ExternalProject构建myLibs,确保projCollections只能通过安装路径查找库:
- 修改顶层CMakeLists.txt,替换
add_subdirectory(myLibs)为ExternalProject_Add:
cmake_minimum_required(VERSION 3.14) project(main) include(ExternalProject) ExternalProject_Add( myLibs_build SOURCE_DIR ${CMAKE_SOURCE_DIR}/myLibs BINARY_DIR ${CMAKE_BINARY_DIR}/myLibs_build CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/myLibs_install INSTALL_DIR ${CMAKE_BINARY_DIR}/myLibs_install ) # 传递安装路径给projCollections set(MYLIBS_INSTALL_DIR ${CMAKE_BINARY_DIR}/myLibs_install) add_subdirectory(projCollections) # 确保projCollections在myLibs构建完成后再编译 add_dependencies(projCollections myLibs_build)
- 更新
projA/CMakeLists.txt的查找逻辑:
project(projA) find_library(MYLIBA NAMES mylibA HINTS ${MYLIBS_INSTALL_DIR}/lib NO_DEFAULT_PATH) find_path(MYLIBA_INCLUDE_DIR NAMES mylibA.h HINTS ${MYLIBS_INSTALL_DIR}/include NO_DEFAULT_PATH) add_executable(projA ...) target_include_directories(projA PRIVATE ${MYLIBA_INCLUDE_DIR}) target_link_libraries(projA PRIVATE ${MYLIBA})
这种方式完全模拟拆分后的依赖模式,但需要提前配置所有查找逻辑,适合需要提前验证拆分后兼容性的场景。
方案3:execute_process(不推荐)
execute_process会在CMake配置阶段直接执行构建命令,破坏CMake的依赖跟踪机制,容易导致并行构建失败、增量构建失效等问题,除非特殊场景,不建议使用。
内容的提问来源于stack exchange,提问作者Andrew S
相关产品推荐
相关产品推荐

