当系统上存在多个 Python 解释器时,CMake 的 FindPythonInterp 模块需要指定额外的参数才能找到正确的(或者说想要的) Python 解释器。
搜索路径
如果要使用非 /usr/local, /usr 目录下的 Python 解释器,则需要修改 cmake 的搜索路径 CMAKE_PREFIX_PATH
(默认为空):
set(CMAKE_PREFIX_PATH "/opt/runsisi/python3")
或:
list(APPEND CMAKE_PREFIX_PATH "/opt/runsisi/python3")
CMAKE_PREFIX_PATH
指定的路径比默认的 /usr/local, /usr 具有更高的优先级,如果 CMAKE_PREFIX_PATH
指定的路径下没有搜索到,则会继续搜索默认路径。
可以为 CMAKE_PREFIX_PATH
增加多个搜索路径(以分号分隔,在前的具有更高的优先级):
set(CMAKE_PREFIX_PATH "/opt/runsisi/python3;/home/runsisi;/usr;/opt/rh/python")
或:
list(APPEND CMAKE_PREFIX_PATH "/home/runsisi;/opt/runsisi/python3;/opt/rh/python;/usr/local")
默认版本
默认情况下,FindPythonInterp
会调用 find_program
命令逐个搜索 python python3.7 .. python3.0 python2.7 .. python2.0 python1.6 python1.5,而实际上第一个名字 python 在 Ubuntu18.04 和 CentOS7.x 上都是指向 python2.7,因此 FindPythonInterp
总是找到 Python2.7。
可用通过定义 Python_ADDITIONAL_VERSIONS
指定优先搜索的版本,此时 FindPythonInterp
会先搜索 Python_ADDITIONAL_VERSIONS
指定的版本,然后才是上面提到的那一大串,pybind11 就是这样处理的,因此在同时装有 Python2 和 Python3 的环境上,会优先选择 Python3:
set(Python_ADDITIONAL_VERSIONS 3.7 3.6 3.5 3.4)
指定版本
显然上面的查找逻辑有点傻,FindPythonInterp
还支持一些额外的变量以控制它的行为:
$ cmake .. -DPythonInterp_FIND_VERSION=3 -DPythonInterp_FIND_VERSION_MAJOR=3
$ cmake .. -DPythonInterp_FIND_VERSION=3.6 -DPythonInterp_FIND_VERSION_MAJOR=3
$ cmake .. -DPythonInterp_FIND_VERSION=3.7.4 -DPythonInterp_FIND_VERSION_MAJOR=3
$ cmake .. -DPythonInterp_FIND_VERSION=2 -DPythonInterp_FIND_VERSION_MAJOR=2
$ cmake .. -DPythonInterp_FIND_VERSION=2.7 -DPythonInterp_FIND_VERSION_MAJOR=2
$ cmake .. -DPythonInterp_FIND_VERSION=2.7.15 -DPythonInterp_FIND_VERSION_MAJOR=2
注意:如果要像上面一样尝试使用不同的变量组合,在每次执行 cmake 之前需要删除上一次 cmake 执行生成的中间文件。
PythonInterp_FIND_VERSION
屏蔽 cmake 默认搜索逻辑,并指定要求的最小版本号;
PythonInterp_FIND_VERSION_MAJOR
指定 Python 主版本号,当前就 1, 2 或者 3,不过这里有 bug,如果指定一个 find_program
找不到的版本号,此时会继续找 python,从而总是会找到 Python2;
PythonInterp_FIND_VERSION_MAJOR
在 1 的情况下,会搜索 1.6 1.5 版本,在 2 的情况下,会搜索 2.7 .. 2.0 版本,而在 3 的情况下,会搜索 3.7 .. 3.0 版本;
如果在不同的路径下有两个版本号都满足要求,此时可以通过控制 CMAKE_PREFIX_PATH
的顺序选择合适的版本;
如果在相同路径下有两个版本号都满足要求,但想要指定一个更低的版本,则 FindPythonInterp
无法实现,因为它总是先从最大的次版本号开始往下搜索,不过此时可以通过打开 PythonInterp_FIND_VERSION_EXACT
(默认关闭)来确认是否找了想要的版本:
$ cmake .. -DPythonInterp_FIND_VERSION=3.6.1 -DPythonInterp_FIND_VERSION_MAJOR=3 -DPythonInterp_FIND_VERSION_EXACT=ON
确认版本
cmake 生成的 CmakeCache.txt 文件中可以找到 Python 相关的定义:
//Path to a program.
PYTHON_EXECUTABLE:FILEPATH=/opt/runsisi/python3/bin/python3
//Path to a library.
PYTHON_LIBRARY:FILEPATH=/opt/runsisi/python3/lib/libpython3.6d.so
//No help, variable specified on the command line.
PythonInterp_FIND_VERSION:UNINITIALIZED=3.6
//No help, variable specified on the command line.
PythonInterp_FIND_VERSION_MAJOR:UNINITIALIZED=3
注意事项
CMAKE_PREFIX_PATH
可以通过环境变量导出或在 CMakeList.txt 文件或命令行上以变量的形式定义,如果通过环境变量导出,对于 FindPythonInterp
模块而言,在 PATH
上加上搜索路径与在 CMAKE_PREFIX_PATH
上加上搜索路径效果是一致的(因为内部的实现逻辑是查找 python 可执行程序并获取到相关信息),显然此时 Linux 下多个路径的分隔符就不能是分号了,而必须是冒号,而 Windows 下仍然是分号。
新版本的 CMake(3.12+)推荐使用新的 FindPython3
,FindPython2
或者 FindPython
模块,这里提到的变量定义并不适用于这些模块。
最后修改于 2019-08-28