Windows下CMake execute_process执行内联Python脚本失败解决
问题详情
在Windows 10的cmd.exe环境中运行CMake 3.26时,出现Python解释器定位失败的错误:
CMake Error at <project_path>/cmake/share/cmake-3.26/Modules/FindPython/Support.cmake:2175 (list): list GET given empty list Call Stack (most recent call first): <project_path>/cmake/share/cmake-3.26/Modules/FindPython.cmake:606 (include) CMakeLists.txt:30 (find_package)
深入排查发现,问题出在FindPython/Support.cmake中的execute_process调用:当执行带\n换行的内联Python脚本时,虽然返回码_${_PYTHON_PREFIX}_RESULT为0(无错误),但输出变量_${_PYTHON_PREFIX}_LIBPATHS为空。
用独立测试脚本验证:
include(CMakePrintHelpers) set(_PYTHON_PREFIX "Python") execute_process (COMMAND "<abspath>" -c "import sys\nsys.stdout.write('one')" RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT COMMAND_ECHO STDOUT OUTPUT_VARIABLE _${_PYTHON_PREFIX}_LIBPATHS ERROR_VARIABLE _${_PYTHON_PREFIX}_ERR) cmake_print_variables(_${_PYTHON_PREFIX}_LIBPATHS) cmake_print_variables(_${_PYTHON_PREFIX}_RESULT) cmake_print_variables(_${_PYTHON_PREFIX}_ERR)
运行cmake -P test.cmake后,_Python_LIBPATHS为空,返回码0且无错误;但把脚本中的\n换成;合并为单行后,输出能正常获取到"one"。
原因分析
Windows的cmd.exe对命令行参数中的换行符\n处理逻辑和POSIX类终端(如Bash、PowerShell)不同,CMake传递的\n没有被正确解析为Python脚本的换行,导致Python执行的脚本内容不符合预期,最终没有输出结果。
解决方法
1. 修改FindPython模块的脚本格式
找到cmake/share/cmake-3.26/Modules/FindPython/Support.cmake中对应的execute_process调用,把内联Python脚本里的\n替换为;,将多行脚本合并为单行。比如:
原代码:
"import sys\nsys.stdout.write('one')"
修改为:
"import sys;sys.stdout.write('one')"
这样cmd能正确传递单行脚本给Python执行,获取到预期输出。
2. 用临时文件传递Python脚本
绕过cmd的换行解析问题,先把Python脚本写入临时文件,再让Python执行该文件。修改对应的execute_process代码:
# 写入临时脚本文件 file(WRITE "${CMAKE_BINARY_DIR}/temp_py_script.py" "import sys\nsys.stdout.write('one')") # 执行临时脚本 execute_process(COMMAND "<abspath>" "${CMAKE_BINARY_DIR}/temp_py_script.py" RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT OUTPUT_VARIABLE _${_PYTHON_PREFIX}_LIBPATHS ERROR_VARIABLE _${_PYTHON_PREFIX}_ERR) # 清理临时文件 file(REMOVE "${CMAKE_BINARY_DIR}/temp_py_script.py")
这种方式兼容性更强,不受终端环境的换行解析限制。
3. 升级CMake版本
该问题在CMake 3.27及后续版本中已被修复,直接升级到最新稳定版CMake,即可无需修改代码解决问题。
4. 切换终端环境
放弃使用cmd.exe,改用PowerShell或Git Bash这类支持POSIX风格命令行解析的终端,CMake传递的\n能被正确识别为脚本换行,脚本可正常执行。
内容的提问来源于stack exchange,提问作者RFairey

