CMake多模块项目.so共享库与头文件跨模块引用配置问题
当前CMake配置的核心问题是没有为Foo库声明对外暴露的头文件搜索路径:CMake中target_link_libraries默认只会传递链接依赖,不会自动推导被链接库的头文件位置,因此Bar模块编译时不会自动添加Foo模块的头文件所在目录,最终导致#include <Foo/foo.h>找不到文件。
以下修改方案完全满足模块隔离要求:所有模块的编译配置收敛在自身目录的CMakeLists.txt中,依赖方不需要硬编码被依赖模块的内部路径,符合大型多模块项目的CMake最佳实践。
1. 修改Foo模块的CMakeLists.txt(src/Foo/CMakeLists.txt)
给Foo目标添加公开头文件搜索路径,使用PUBLIC关键字标记的属性会自动传递给所有链接Foo的目标:
add_library(Foo SHARED foo.cpp) # 声明头文件搜索路径:当前目录的上一级即src/目录,加入搜索路径后即可直接通过<Foo/foo.h>引用头文件 # PUBLIC表示:该路径既用于Foo自身编译,也会传递给所有链接Foo的下游目标 target_include_directories(Foo PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/.. )
说明:
${CMAKE_CURRENT_SOURCE_DIR}是CMake内置变量,指向当前正在处理的CMakeLists.txt所在目录,也就是src/Foo/,取上一级后得到src/目录,该目录下刚好存在Foo/foo.h的层级结构,完全匹配要求的include写法。
2. 简化Bar模块的CMakeLists.txt(src/Bar/CMakeLists.txt)
原有配置中add_dependencies(Bar Foo)是多余的:target_link_libraries已经会自动建立目标间的依赖顺序,不需要手动声明。由于Bar的头文件中直接引入了Foo的头文件,建议将链接属性设为PUBLIC,保证后续如果有其他目标依赖Bar时,也能自动拿到Foo的头文件路径:
add_library(Bar SHARED bar.cpp) target_link_libraries(Bar PUBLIC Foo)
3. 重新构建验证
清空原有构建缓存后重新执行构建流程即可:
rm -rf build && mkdir build && cd build cmake .. make
如果需要将编译好的库安装到系统目录供外部项目使用,还需要在Foo模块的CMakeLists.txt中添加头文件安装规则,避免安装后外部项目找不到头文件:
# 安装Foo模块的头文件到系统include目录 install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DESTINATION include FILES_MATCHING PATTERN "*.h")
顶层CMakeLists.txt中不建议硬编码CMAKE_CXX_COMPILER路径,不同环境下g++安装位置可能存在差异,编译器路径建议在执行cmake时通过参数传入:cmake -DCMAKE_CXX_COMPILER=/usr/bin/g++ ..,避免配置文件和环境强绑定。
内容的提问来源于stack exchange,提问作者drjrm3

