多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
# 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`: ```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`中的步骤: 1. 包含CMake最低版本、项目名称和所需语言: ```cmake cmake_minimum_required(VERSION 3.5 FATAL_ERROR) project(recipe-02 LANGUAGES C) ``` 2. 制使用C99标准,这不严格要求与Python链接,但有时你可能需要对Python进行连接: ```cmake set(CMAKE_C_STANDARD 99) set(CMAKE_C_EXTENSIONS OFF) set(CMAKE_C_STANDARD_REQUIRED ON) ``` 3. 找到Python解释器。这是一个`REQUIRED`依赖: ```cmake find_package(PythonInterp REQUIRED) ``` 4. 找到Python头文件和库的模块,称为`FindPythonLibs.cmake`: ```cmake find_package(PythonLibs ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR} EXACT REQUIRED) ``` 5. 使用`hello-embedded-python.c`源文件,添加一个可执行目标: ```cmake add_executable(hello-embedded-python hello-embedded-python.c) ``` 6. 可执行文件包含`Python.h`头文件。因此,这个目标的`include`目录必须包含Python的`include`目录,可以通过`PYTHON_INCLUDE_DIRS`变量进行指定: ```cmake target_include_directories(hello-embedded-python PRIVATE ${PYTHON_INCLUDE_DIRS} ) ``` 7. 最后,将可执行文件链接到Python库,通过`PYTHON_LIBRARIES`变量访问: ```cmake target_link_libraries(hello-embedded-python PRIVATE ${PYTHON_LIBRARIES} ) ``` 8. 现在,进行构建: ```shell $ 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") ``` 9. 最后,执行构建,并运行可执行文件: ```shell $ 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`来实现: ```cmake find_package(PythonInterp REQUIRED) find_package(PythonLibs ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR} EXACT REQUIRED) ``` 使用`EXACT`关键字,限制CMake检测特定的版本,在本例中是匹配的相应Python版本的包括文件和库。我们可以使用`PYTHON_VERSION_STRING`变量,进行更接近的匹配: ```cmake 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