CMake执行install安装时如何运行自定义命令处理头文件
CMake实现头文件安装时路径替换/目录复制方案
方案一:安装时自动替换include路径,实现头文件目录扁平化
不需要依赖sed等外部命令,用CMake内置的文件操作即可跨平台实现替换,逻辑在安装阶段执行,不会修改外部库原始源码:
- 首先扫描所有需要安装的头文件,过滤掉测试、源码等非必要文件
- 遍历每个头文件,提取模块名,在安装时读取头文件内容,用正则替换include路径后写入目标扁平化路径
示例代码:
# 扫描ccan目录下所有头文件,排除测试目录内容 file(GLOB_RECURSE CCAN_ALL_HEADERS CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/ccan/*/*.h" ) list(FILTER CCAN_ALL_HEADERS EXCLUDE REGEX ".*/test/.*") set(CCAN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include/ccan") foreach(_header_fullpath ${CCAN_ALL_HEADERS}) # 提取相对路径,如 str/str.h file(RELATIVE_PATH _header_rel "${CMAKE_CURRENT_SOURCE_DIR}/ccan" "${_header_fullpath}") # 匹配标准的 模块名/模块名.h 结构 string(REGEX MATCH "^([^/]+)/\\1\\.h$" _is_standard_header "${_header_rel}") if(_is_standard_header) set(_target_name "${CMAKE_MATCH_1}.h") # 安装时执行文本替换 install(CODE " file(READ \"${_header_fullpath}\" _content) # 替换所有 #include <ccan/xxx/xxx.h> 为 #include <ccan/xxx.h> string(REGEX REPLACE \"#include[ \\t]*<ccan/([^/]+)/\\1\\.h>\" \"#include <ccan/\\1.h>\" _content \"\${_content}\" ) file(WRITE \"${CCAN_INSTALL_DIR}/${_target_name}\" \"\${_content}\") ") else() # 非标准命名头文件保留原路径安装 get_filename_component(_header_dir "${_header_rel}" DIRECTORY) install(FILES "${_header_fullpath}" DESTINATION "include/ccan/${_header_dir}") endif() endforeach()
上述正则仅匹配ccan标准模块路径,不会误改系统头、非同名头文件的引用。如果代码里有用双引号包裹的#include "ccan/xxx/xxx.h"格式,把正则里的<>替换为[<"]和[>"]即可兼容。
如果仅在类Unix平台部署,也可以把替换逻辑换成sed命令实现,但不推荐,跨平台兼容性差:
# sed替换方案(仅Linux/macOS可用) install(CODE " execute_process( COMMAND sed -E 's|#include[[:space:]]*<ccan/([^/]+)/\\1\\.h>|#include <ccan/\\1.h>|g' ${_header_fullpath} OUTPUT_FILE \"${CCAN_INSTALL_DIR}/${_target_name}\" ) ")
方案二:原样保留目录结构安装,无需逐个编写install命令
不需要为每个头文件单独写install(FILES),用install(DIRECTORY)命令一条即可完成整个目录的筛选安装,保留原始目录结构,不需要做文本替换,配置最简单:
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/ccan/" DESTINATION include/ccan FILES_MATCHING # 只安装.h头文件 PATTERN "*.h" # 排除不需要的文件和目录 PATTERN "test" EXCLUDE PATTERN "_info" EXCLUDE PATTERN "*.c" EXCLUDE PATTERN "LICENSE" EXCLUDE )
安装后原有目录结构不变,代码里引用头文件仍然使用#include <ccan/xxx/xxx.h>格式即可,没有替换逻辑带来的误改风险。
补充提示
如果不需要执行安装步骤,只是在项目构建阶段内部引用外部库,也可以把替换逻辑提前在CMake配置阶段执行,将替换后的头文件输出到构建目录,再把构建目录加入项目的include搜索路径即可,替换逻辑和上述安装阶段的代码一致。
内容的提问来源于stack exchange,提问作者ZioByte
相关产品推荐
相关产品推荐

