无顶层CMakeLists.txt时,如何链接依赖lib1的lib2两个CMake项目
假设有两个CMake库:lib1和lib2,其中lib2依赖lib1。如何在不将它们纳入同一个总CMake项目的前提下实现链接?即仅保留两个CMakeLists.txt(分别对应lib1和lib2),且不存在用于关联它们的顶层CMakeLists.txt。
项目结构如下:
cmake_agnostic_root/ |-- lib1/ | |-- src/ | |-- include/ | |-- CMakeLists.txt |-- lib2/ | |-- src/ | |-- include/ | |-- CMakeLists.txt |-- (此层级不得有CMakeLists.txt)
我认为只需在lib2的CMakeLists.txt中配置即可引入lib1。我已尝试以下方法但均未成功:
- add_subdirectory:
在lib2的CMakeLists.txt中添加如下代码:
add_subdirectory(../lib1 lib1)
但lib2仍无法找到lib1的头文件。
- ExternalProject:
在lib2的CMakeLists.txt中添加如下代码:
include(ExternalProject) ExternalProject_Add( lib1 SOURCE_DIR ../lib1 )
我可能误用了该命令,因为示例中它多用于下载Git仓库,但我需要使用与lib2同级的本地lib1文件夹。
我哪里出错了?
补充说明:我希望在lib2目录下调用cmake时,能触发lib1的构建并将其用于lib2的构建。
为什么add_subdirectory没生效?
用add_subdirectory的思路没问题,但你漏了头文件路径配置和库链接的关键步骤,而且得先确保lib1的CMakeLists.txt配置正确。
首先给lib1的CMakeLists.txt补全必要配置,让它能导出头文件和目标:
cmake_minimum_required(VERSION 3.10) project(lib1) # 编译lib1库 add_library(lib1 STATIC src/lib1.cpp) # 把lib1的include目录设为PUBLIC,这样依赖它的项目会自动继承这个路径 target_include_directories(lib1 PUBLIC include)
然后修改lib2的CMakeLists.txt,添加add_subdirectory后,显式链接lib1:
cmake_minimum_required(VERSION 3.10) project(lib2) # 添加lib1的源码目录,第二个参数是指定lib1的构建输出目录,避免和lib2的构建文件混在一起 add_subdirectory(../lib1 lib1_build) # 编译lib2库 add_library(lib2 STATIC src/lib2.cpp) # 链接lib1,因为lib1用了PUBLIC的include目录,这里会自动把lib1的头文件路径传给lib2 target_link_libraries(lib2 PRIVATE lib1)
这样在lib2目录下运行cmake构建时,会自动触发lib1的编译,lib2也能正常找到lib1的头文件并完成链接。
关于ExternalProject的误用
ExternalProject确实支持本地目录,但它的逻辑是在构建阶段才去编译外部项目,而CMake的配置阶段没法获取到外部项目的产物信息,所以你直接加了ExternalProject_Add后,lib2还是找不到头文件和库。
如果一定要用这个方案,得手动指定lib1的安装路径,再手动引入头文件和库:
cmake_minimum_required(VERSION 3.10) project(lib2) include(ExternalProject) ExternalProject_Add( lib1 SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../lib1 BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/lib1_build # 指定lib1的安装目录,方便后续引用 CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}/lib1_install ) # 让lib2等lib1编译完成再构建 add_dependencies(lib2 lib1) # 编译lib2 add_library(lib2 STATIC src/lib2.cpp) # 手动引入lib1的头文件路径 target_include_directories(lib2 PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/lib1_install/include) # 手动链接lib1的库文件(注意库文件名要和实际生成的一致) target_link_libraries(lib2 PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/lib1_install/lib/lib1.a)
这种方式比add_subdirectory麻烦很多,所以优先推荐第一种方案。
内容的提问来源于stack exchange,提问作者Divelix

