如何使用CMake创建自定义目标,配置shell脚本并依赖C++可执行文件
解决方案
问题根源
你原来直接调用的configure_file是CMake配置阶段(即执行cmake ..生成构建文件的阶段)就会执行的命令,不会等到构建阶段(执行make的阶段)运行,所以无法依赖构建产物myExe,也无法做到仅执行make foo-target时才触发配置。
调整步骤
1. 调整模板文件(可选,推荐)
将tool/myscript.sh重命名为tool/myscript.sh.in,区分模板文件和生成后的可执行脚本,避免路径冲突。如果不想重命名,后续步骤中指定输入路径为源码目录下的原始文件即可。
2. 修改tool/CMakeLists.txt内容
直接删除原来的配置阶段configure_file调用,改用构建阶段的自定义命令实现按需生成:
set(CONFIG_INI_ABS_PATH "${PROJECT_SOURCE_DIR}/foo/config.ini") add_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/myscript.sh" # 依赖模板文件和myExe目标:模板修改或者myExe重新编译时,自动重新生成脚本 DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/myscript.sh.in" myExe # 用sed替换模板中的占位符,生成最终脚本 COMMAND sed -e "s|@CONFIG_INI_ABS_PATH@|${CONFIG_INI_ABS_PATH}|g" -e "s|@EXE_ABS_PATH@|$<TARGET_FILE:myExe>|g" "${CMAKE_CURRENT_SOURCE_DIR}/myscript.sh.in" > "${CMAKE_CURRENT_BINARY_DIR}/myscript.sh" # 给生成的脚本加执行权限 COMMAND chmod +x "${CMAKE_CURRENT_BINARY_DIR}/myscript.sh" VERBATIM ) add_custom_target(foo-target DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/myscript.sh" )
如果需要跨Windows平台兼容,不用sed的话,可以新增一个tool/configure_script.cmake辅助脚本:
configure_file(${INPUT_FILE} ${OUTPUT_FILE} @ONLY USE_SOURCE_PERMISSIONS)
再把add_custom_command替换为以下写法即可:
add_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/myscript.sh" DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/myscript.sh.in" myExe "${CMAKE_CURRENT_SOURCE_DIR}/configure_script.cmake" COMMAND ${CMAKE_COMMAND} -D CONFIG_INI_ABS_PATH=${CONFIG_INI_ABS_PATH} -D EXE_ABS_PATH=$<TARGET_FILE:myExe> -D INPUT_FILE="${CMAKE_CURRENT_SOURCE_DIR}/myscript.sh.in" -D OUTPUT_FILE="${CMAKE_CURRENT_BINARY_DIR}/myscript.sh" -P "${CMAKE_CURRENT_SOURCE_DIR}/configure_script.cmake" VERBATIM )
3. 调整子目录加载顺序
确保你项目根目录的CMakeLists.txt中,add_subdirectory(cpp)的顺序在add_subdirectory(tool)之前,否则CMake会找不到myExe目标。
效果说明
- 直接执行
make等默认构建命令时,不会生成myscript.sh,也不会触发相关依赖编译 - 执行
make foo-target时,会先自动编译更新myExe,再生成替换好路径的myscript.sh到构建目录的tool/路径下 - 后续如果修改了模板文件或者重新编译了
myExe,再次执行make foo-target会自动重新生成脚本
内容的提问来源于stack exchange,提问作者TomateVerde
相关产品推荐
相关产品推荐

