3.2 检测 Python 库
NOTE : 此示例代码可以在 https://github.com/devcafe/cmake-cookbook/tree/v1.0/chapter-03/recipe-02 中找到,有一个 C 示例。该示例在 CMake 3.5 版(或更高版本) 中是有效的,并且已经在 GNU/Linux、macOS 和 Windows 上进行过测试。
可以使用 Python 工具来分析和操作程序的输出。然而,还有更强大的方法可以将解释语言(如 Python) 与编译语言(如 C 或 C++) 组合在一起使用。一种是扩展 Python,通过编译成共享库的 C 或 C++模块在这些类型上提供新类型和新功能,这是第 9 章的主题。另一种是将 Python 解释器嵌入到 C 或 C++程序中。两种方法都需要下列条件:
- Python 解释器的工作版本
- Python 头文件 Python.h 的可用性
- Python 运行时库 libpython
三个组件所使用的 Python 版本必须相同。我们已经演示了如何找到 Python 解释器;本示例中,我们将展示另外两种方式。
准备工作
我们将一个简单的 Python 代码,嵌入到 C 程序中,可以在 Python 文档页面上找到。源文件称为 hello-embedded-python.c
:
#include <Python.h> int main(int argc, char *argv[]) { Py_SetProgramName(argv[0]); /* optional but recommended */ Py_Initialize(); PyRun_SimpleString("from time import time,ctime\n" "print 'Today is',ctime(time())\n"); Py_Finalize(); return 0; }
此代码将在程序中初始化 Python 解释器的实例,并使用 Python 的 time
模块,打印日期。
NOTE : 嵌入代码可以在 Python 文档页面的 https://docs.python.org/2/extending/embedding.html 和 https://docs.python.org/3/extending/embedding.html 中找到。
具体实施
以下是 CMakeLists.txt
中的步骤:
- 包含 CMake 最低版本、项目名称和所需语言:
cmake_minimum_required(VERSION 3.5 FATAL_ERROR) project(recipe-02 LANGUAGES C)
- 制使用 C99 标准,这不严格要求与 Python 链接,但有时你可能需要对 Python 进行连接:
set(CMAKE_C_STANDARD 99) set(CMAKE_C_EXTENSIONS OFF) set(CMAKE_C_STANDARD_REQUIRED ON)
- 找到 Python 解释器。这是一个
REQUIRED
依赖:find_package(PythonInterp REQUIRED)
- 找到 Python 头文件和库的模块,称为
FindPythonLibs.cmake
:find_package(PythonLibs ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR} EXACT REQUIRED)
- 使用
hello-embedded-python.c
源文件,添加一个可执行目标:add_executable(hello-embedded-python hello-embedded-python.c)
- 可执行文件包含
Python.h
头文件。因此,这个目标的include
目录必须包含 Python 的include
目录,可以通过PYTHON_INCLUDE_DIRS
变量进行指定:target_include_directories(hello-embedded-python PRIVATE ${PYTHON_INCLUDE_DIRS} )
- 最后,将可执行文件链接到 Python 库,通过
PYTHON_LIBRARIES
变量访问:target_link_libraries(hello-embedded-python PRIVATE ${PYTHON_LIBRARIES} )
- 现在,进行构建:
$ mkdir -p build $ cd build $ cmake .. ... -- Found PythonInterp: /usr/bin/python (found version "3.6.5") -- Found PythonLibs: /usr/lib/libpython3.6m.so (found suitable exact version "3.6.5")
- 最后,执行构建,并运行可执行文件:
$ cmake --build . $ ./hello-embedded-python Today is Thu Jun 7 22:26:02 2018
工作原理
FindPythonLibs.cmake
模块将查找 Python 头文件和库的标准位置。由于,我们的项目需要这些依赖项,如果没有找到这些依赖项,将停止配置,并报出错误。
注意,我们显式地要求 CMake 检测安装的 Python 可执行文件。这是为了确保可执行文件、头文件和库都有一个匹配的版本。这对于不同版本,可能在运行时导致崩溃。我们通过 FindPythonInterp.cmake
中定义的 PYTHON_VERSION_MAJOR
和 PYTHON_VERSION_MINOR
来实现:
find_package(PythonInterp REQUIRED) find_package(PythonLibs ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR} EXACT REQUIRED)
使用 EXACT
关键字,限制 CMake 检测特定的版本,在本例中是匹配的相应 Python 版本的包括文件和库。我们可以使用 PYTHON_VERSION_STRING
变量,进行更接近的匹配:
find_package(PythonInterp REQUIRED) find_package(PythonLibs ${PYTHON_VERSION_STRING} EXACT REQUIRED)
更多信息
当 Python 不在标准安装目录中,我们如何确定 Python 头文件和库的位置是正确的?对于 Python 解释器,可以通过 CLI 的 -D
选项传递 PYTHON_LIBRARY
和 PYTHON_INCLUDE_DIR
选项来强制 CMake 查找特定的目录。这些选项指定了以下内容:
- PYTHON_LIBRARY :指向 Python 库的路径
- PYTHON_INCLUDE_DIR :Python.h 所在的路径
这样,就能获得所需的 Python 版本。
TIPS : 有时需要将 -D PYTHON_EXECUTABLE
、 -D PYTHON_LIBRARY
和 -D PYTHON_INCLUDE_DIR
传递给 CMake CLI,以便找到及定位相应的版本的组件。
要将 Python 解释器及其开发组件匹配为完全相同的版本可能非常困难,对于那些将它们安装在非标准位置或系统上安装了多个版本的情况尤其如此。CMake 3.12 版本中增加了新的 Python 检测模块,旨在解决这个棘手的问题。我们 CMakeLists.txt
的检测部分也将简化为:
find_package(Python COMPONENTS Interpreter Development REQUIRED)
我们建议您阅读新模块的文档,地址是: https://cmake.org/cmake/help/v3.12/module/FindPython.html
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论