3.1 检测Python解释器

NOTE:此示例代码可以在 https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-03/recipe-01 中找到。该示例在CMake 3.5版(或更高版本)中是有效的,并且已经在GNU/Linux、macOS和Windows上进行过测试。

Python是一种非常流行的语言。许多项目用Python编写的工具,从而将主程序和库打包在一起,或者在配置或构建过程中使用Python脚本。这种情况下,确保运行时对Python解释器的依赖也需要得到满足。本示例将展示如何检测和使用Python解释器。

我们将介绍find_package命令,这个命令将贯穿本章。

具体实施

我们将逐步建立CMakeLists.txt文件:

  1. 首先,定义CMake最低版本和项目名称。注意,这里不需要任何语言支持:

    1. cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
    2. project(recipe-01 LANGUAGES NONE)
  2. 然后,使用find_package命令找到Python解释器:

    1. find_package(PythonInterp REQUIRED)
  3. 然后,执行Python命令并捕获它的输出和返回值:

    1. execute_process(
    2. COMMAND
    3. ${PYTHON_EXECUTABLE} "-c" "print('Hello, world!')"
    4. RESULT_VARIABLE _status
    5. OUTPUT_VARIABLE _hello_world
    6. ERROR_QUIET
    7. OUTPUT_STRIP_TRAILING_WHITESPACE
    8. )
  4. 最后,打印Python命令的返回值和输出:

    1. message(STATUS "RESULT_VARIABLE is: ${_status}")
    2. message(STATUS "OUTPUT_VARIABLE is: ${_hello_world}")
  5. 配置项目:

    1. $ mkdir -p build
    2. $ cd build
    3. $ cmake ..
    4. -- Found PythonInterp: /usr/bin/python (found version "3.6.5")
    5. -- RESULT_VARIABLE is: 0
    6. -- OUTPUT_VARIABLE is: Hello, world!
    7. -- Configuring done
    8. -- Generating done
    9. -- Build files have been written to: /home/user/cmake-cookbook/chapter-03/recipe-01/example/build

工作原理

find_package是用于发现和设置包的CMake模块的命令。这些模块包含CMake命令,用于标识系统标准位置中的包。CMake模块文件称为Find<name>.cmake,当调用find_package(<name>)时,模块中的命令将会运行。

除了在系统上实际查找包模块之外,查找模块还会设置了一些有用的变量,反映实际找到了什么,也可以在自己的CMakeLists.txt中使用这些变量。对于Python解释器,相关模块为FindPythonInterp.cmake附带的设置了一些CMake变量:

  • PYTHONINTERP_FOUND:是否找到解释器
  • PYTHON_EXECUTABLE:Python解释器到可执行文件的路径
  • PYTHON_VERSION_STRING:Python解释器的完整版本信息
  • PYTHON_VERSION_MAJOR:Python解释器的主要版本号
  • PYTHON_VERSION_MINOR :Python解释器的次要版本号
  • PYTHON_VERSION_PATCH:Python解释器的补丁版本号

可以强制CMake,查找特定版本的包。例如,要求Python解释器的版本大于或等于2.7:find_package(PythonInterp 2.7)

可以强制满足依赖关系:

  1. find_package(PythonInterp REQUIRED)

如果在查找位置中没有找到适合Python解释器的可执行文件,CMake将中止配置。

TIPS:CMake有很多查找软件包的模块。我们建议在CMake在线文档中查询Find<package>.cmake模块,并在使用它们之前详细阅读它们的文档。find_package命令的文档可以参考 https://cmake.org/cmake/help/v3.5/command/find_ackage.html 。在线文档的一个很好的替代方法是浏览 https://github.com/Kitware/CMake/tree/master/Modules 中的CMake模块源代码——它们记录了模块使用的变量,以及模块可以在CMakeLists.txt中使用的变量。

更多信息

软件包没有安装在标准位置时,CMake无法正确定位它们。用户可以使用CLI的-D参数传递相应的选项,告诉CMake查看特定的位置。Python解释器可以使用以下配置:

  1. $ cmake -D PYTHON_EXECUTABLE=/custom/location/python ..

这将指定非标准/custom/location/pytho安装目录中的Python可执行文件。

NOTE:每个包都是不同的,Find<package>.cmake模块试图提供统一的检测接口。当CMake无法找到模块包时,我们建议您阅读相应检测模块的文档,以了解如何正确地使用CMake模块。可以在终端中直接浏览文档,本例中可使用cmake --help-module FindPythonInterp查看。

除了检测包之外,我们还想提到一个便于打印变量的helper模块。本示例中,我们使用了以下方法:

  1. message(STATUS "RESULT_VARIABLE is: ${_status}")
  2. message(STATUS "OUTPUT_VARIABLE is: ${_hello_world}")

使用以下工具进行调试:

  1. include(CMakePrintHelpers)
  2. cmake_print_variables(_status _hello_world)

将产生以下输出:

  1. -- _status="0" ; _hello_world="Hello, world!"

有关打印属性和变量的更多信息,请参考 https://cmake.org/cmake/help/v3.5/module/CMakePrintHelpers.html