CMake调用Python脚本时无法找到已安装的Python模块问题咨询
本地环境
$ uname -a Darwin Mac-mini.local 20.6.0 Darwin Kernel Version 20.6.0: Wed Jun 23 00:26:31 PDT 2021; root:xnu-7195.141.2~5/RELEASE_X86_64 x86_64 $ python3 --version Python 3.9.7 $ cmake --version cmake version 3.21.2 CMake suite maintained and supported by Kitware (kitware.com/cmake). $ xcode-select --version xcode-select version 2384.
Xcode版本:12.5.1 (12E507)
问题描述
现有一个大型项目使用cmake管理构建流程,部分依赖需要通过Python脚本下载,依赖需走ssh/sftp连接检索,所以脚本用到paramiko库。
直接在命令行运行该脚本完全正常,可以找到所有Python模块并完成全部依赖下载。但在CMakeLists.txt中通过cmake命令调用同一份脚本时,会报错无法加载paramiko库。两次操作是在同一个命令行环境中先后执行的,先直接跑脚本,再执行cmake .. -G Xcode。
CMake中的相关配置如下:
add_custom_target(DependenciesDownload ALL ./download.py <some arguments> BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/poroduct/libproduct.${PRODUCT_EXTENSION}" WORKING_DIRECTORY "${PROJECT_SRC_ROOT}/scriptPath" COMMENT "Unzips dependency from SMB network drive or sftp address" )
尝试过显式调用Python版本:python3 ./download.py <some arguments>和env python3 ./download.py <some arguments>,结果完全一致。
备注
之前在另一台MacOS设备上遇到过相同问题,后来莫名恢复正常,不清楚当时执行了什么修复操作,现在无法复现修复流程,求解决方案。
解决方案
该问题的核心原因是CMake(尤其是Xcode生成器)执行自定义构建目标时,会重置运行环境,不会完全继承当前终端的环境变量,导致两种场景下调用的Python实例、Python模块搜索路径不一致。
具体解决步骤
- 使用CMake内置能力获取确定的Python解释器路径
不要直接写python3或者env python3,改用CMake的find_package获取当前环境下可用的Python3解释器绝对路径,修改CMake配置如下:
# 放在add_custom_target之前 find_package(Python3 REQUIRED COMPONENTS Interpreter) add_custom_target(DependenciesDownload ALL ${Python3_EXECUTABLE} ./download.py <some arguments> BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/product/libproduct.${PRODUCT_EXTENSION}" WORKING_DIRECTORY "${PROJECT_SRC_ROOT}/scriptPath" COMMENT "Unzips dependency from SMB network drive or sftp address" )
该方法可以保证CMake调用的Python解释器和你当前终端用的是同一个,避免调用到没有安装paramiko的系统默认Python。
- 排查路径差异
如果问题仍然存在,先在download.py开头加入以下代码,分别在终端直接运行、CMake构建时运行,对比输出确认差异:
import sys print("Python解释器路径:", sys.executable) print("Python模块搜索路径:", sys.path)
再在终端执行以下命令,确认paramiko的安装路径:python3 -c "import paramiko; print(paramiko.__file__)"
- 手动指定PYTHONPATH环境变量
如果确认两种场景用的Python解释器一致,只是CMake环境下的模块搜索路径缺少paramiko的安装目录,可以在CMake配置中手动传入环境变量:
add_custom_target(DependenciesDownload ALL ${CMAKE_COMMAND} -E env PYTHONPATH=<替换为上一步查到的paramiko所在的site-packages目录路径> ${Python3_EXECUTABLE} ./download.py <some arguments> BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/product/libproduct.${PRODUCT_EXTENSION}" WORKING_DIRECTORY "${PROJECT_SRC_ROOT}/scriptPath" COMMENT "Unzips dependency from SMB network drive or sftp address" )
- Xcode构建特殊处理
如果是用Xcode GUI构建项目,Xcode默认会使用独立的沙箱环境,不会继承终端环境变量,可以在Xcode对应Scheme的Run/Build配置中手动添加PYTHONPATH环境变量,值为paramiko所在的site-packages目录路径。
内容的提问来源于stack exchange,提问作者Marek R

