CMake构建阶段如何读取Python脚本返回的变量?
解决方案
核心问题是混淆了CMake的配置阶段和构建阶段:execute_process()是在配置阶段执行的,此时elf文件还未生成,必然报错。要实现构建后触发脚本并处理返回值,按以下步骤操作:
1. 构建阶段触发Python脚本并保存返回值
用add_custom_target创建依赖elf目标的自定义任务,在构建阶段执行Python脚本,并将返回值写入临时文件(构建阶段无法直接将值传递给CMake变量)。
修改CMakeLists.txt:
# 假设${elf_target}是生成elf文件的目标 add_custom_target(run_py_script ALL DEPENDS ${elf_target} COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/py_script.py $<TARGET_FILE:${elf_target}> COMMAND ${CMAKE_COMMAND} -E echo "$?" > ${CMAKE_CURRENT_BINARY_DIR}/script_ret_val.txt WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} )
DEPENDS ${elf_target}:确保脚本在elf文件生成后才执行$<TARGET_FILE:${elf_target}>:自动获取生成的elf文件绝对路径,避免路径错误echo "$?":将Python脚本的退出码(shell中$?表示前一命令的返回值)写入临时文件script_ret_val.txt
2. 读取返回值并打印对应消息
由于CMake配置阶段早于构建阶段,要处理构建阶段生成的返回值,有两种实现方式:
方式一:构建完成后立即打印结果
扩展add_custom_target,在写入返回值文件后调用CMake脚本读取并打印:
add_custom_target(run_py_script ALL DEPENDS ${elf_target} COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/py_script.py $<TARGET_FILE:${elf_target}> COMMAND ${CMAKE_COMMAND} -E echo "$?" > ${CMAKE_CURRENT_BINARY_DIR}/script_ret_val.txt COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/check_ret_val.cmake WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} )
创建check_ret_val.cmake脚本:
file(READ script_ret_val.txt ret_val) string(STRIP "${ret_val}" ret_val) # 去除换行符 if(ret_val EQUAL 0) message(STATUS "Python脚本执行结果: Pass.") else() message(STATUS "Python脚本执行结果: Fail.") endif()
方式二:配置阶段读取上次构建结果
如果想在每次CMake配置时显示上次构建的脚本结果,在CMakeLists.txt中添加:
# 检查返回值文件是否存在 if(EXISTS ${CMAKE_CURRENT_BINARY_DIR}/script_ret_val.txt) file(READ ${CMAKE_CURRENT_BINARY_DIR}/script_ret_val.txt ret_val) string(STRIP "${ret_val}" ret_val) if(ret_val EQUAL 0) message(STATUS "上次Python脚本执行结果: Pass.") else() message(STATUS "上次Python脚本执行结果: Fail.") endif() else() message(STATUS "尚未执行Python脚本.") endif()
替换原有错误代码
删除你原来的py_script()函数调用和file.cmake文件,改用上述方案即可解决问题。
关键注意事项
- 始终用
$<TARGET_FILE:${elf_target}>获取elf文件绝对路径,避免相对路径引发的文件找不到问题 - 通过临时文件传递构建阶段的返回值到CMake脚本,这是跨阶段传递数据的可靠方式
- 严格区分配置阶段和构建阶段的执行时机,不要在配置阶段执行依赖构建产物的逻辑
内容的提问来源于stack exchange,提问作者user30740237




