diff --git a/SUMMARY.md b/SUMMARY.md index 10e199d..dc532e7 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -36,7 +36,7 @@ * [3.7 检测Eigen库](content/chapter3/3.7-chinese.md) * [3.8 检测Boost库](content/chapter3/3.8-chinese.md) * [3.9 检测外部库:Ⅰ. 使用pkg-config](content/chapter3/3.9-chinese.md) - * [3.10 检测外部库:Ⅱ. 书写find模块](content/chapter3/3.10-chinese.md) + * [3.10 检测外部库:Ⅱ. 自定义find模块](content/chapter3/3.10-chinese.md) * [第4章 创建和运行测试](content/chapter4/4.0-chinese.md) * [4.1 创建一个简单的单元测试](content/chapter4/4.1-chinese.md) * [4.2 使用Catch2库进行单元测试](content/chapter4/4.2-chinese.md) diff --git a/content/chapter3/3.0-chinese.md b/content/chapter3/3.0-chinese.md index 1008bf6..b755c18 100644 --- a/content/chapter3/3.0-chinese.md +++ b/content/chapter3/3.0-chinese.md @@ -1,6 +1,6 @@ # 第3章 检测外部库和程序 -本章中,我们将介绍以下示例: +本章中主要内容有: * 检测Python解释器 * 检测Python库 @@ -13,13 +13,13 @@ * 检测外部库:Ⅰ. 使用pkg-config * 检测外部库:Ⅱ. 书写find模块 -我们的项目常常会依赖于其他项目和库。本章将演示,如何检测外部库、框架和项目,以及如何链接到这些库。CMake有一组预打包模块,用于检测常用库和程序,例如:Python和Boost。您可以使用`cmake --help-module-list`获得现有模块的列表。但是,不是所有的库和程序都包含在其中,有时必须自己编写检测脚本。本章中,我们将讨论相应的工具,并了解CMake的`find`族命令: +我们的项目常常会依赖于其他项目和库。本章将演示,如何检测外部库、框架和项目,以及如何链接到这些库。CMake有一组预打包模块,用于检测常用库和程序,例如:Python和Boost。可以使用`cmake --help-module-list`获得现有模块的列表。但是,不是所有的库和程序都包含在其中,有时必须自己编写检测脚本。本章将讨论相应的工具,了解CMake的`find`族命令: -* find_file:在相应路径下查找命名文件 -* find_library:查找一个库文件 -* find_package:从外部项目查找和加载设置 -* find_path:查找包含指定文件的目录 -* find_program:找到一个可执行程序 +* **find_file**:在相应路径下查找命名文件 +* **find_library**:查找一个库文件 +* **find_package**:从外部项目查找和加载设置 +* **find_path**:查找包含指定文件的目录 +* **find_program**:找到一个可执行程序 -**NOTE**:*可以使用`--help-command`命令行显示的CMake内置命令的打印文档。* +**NOTE**:*可以使用`--help-command`命令行显示CMake内置命令的打印文档。* diff --git a/content/chapter3/3.1-chinese.md b/content/chapter3/3.1-chinese.md index 946d223..acd4832 100644 --- a/content/chapter3/3.1-chinese.md +++ b/content/chapter3/3.1-chinese.md @@ -2,13 +2,15 @@ **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`命令,这个命令将贯穿本章。 +Python是一种非常流行的语言。许多项目用Python编写的工具,从而将主程序和库打包在一起,或者在配置或构建过程中使用Python脚本。这种情况下,确保运行时对Python解释器的依赖也需要得到满足。本示例将展示如何检测和使用Python解释器。 + +我们将介绍`find_package`命令,这个命令将贯穿本章。 ## 具体实施 我们将逐步建立`CMakeLists.txt`文件: -1. 首先,定义最低的CMake版本和项目名称。注意,对于这个例子,我们不需要任何语言支持: +1. 首先,定义CMake最低版本和项目名称。注意,这里不需要任何语言支持: ```cmake cmake_minimum_required(VERSION 3.5 FATAL_ERROR) @@ -41,12 +43,13 @@ Python是一种非常流行的动态语言。许多项目用Python编写的工 message(STATUS "OUTPUT_VARIABLE is: ${_hello_world}") ``` -5. 现在,可以检查配置步骤的输出: +5. 配置项目: ```shell $ mkdir -p build $ cd build $ cmake .. + -- Found PythonInterp: /usr/bin/python (found version "3.6.5") -- RESULT_VARIABLE is: 0 -- OUTPUT_VARIABLE is: Hello, world! @@ -57,16 +60,16 @@ Python是一种非常流行的动态语言。许多项目用Python编写的工 ## 工作原理 -`find_package`是包装器命令,用于发现和设置包的CMake模块。这些模块包含CMake命令,用于标识系统标准位置中的包。CMake模块文件称为` Find.cmake`,当调用`find_package()`时,模块中的命令将会运行。 +`find_package`是用于发现和设置包的CMake模块的命令。这些模块包含CMake命令,用于标识系统标准位置中的包。CMake模块文件称为` Find.cmake`,当调用`find_package()`时,模块中的命令将会运行。 -除了在系统上实际查找包模块之外,查找模块还会设置了一些有用的变量,反映实际找到了什么,您可以在自己的`CMakeLists.txt`中使用这些变量。对于Python解释器,相关模块为`FindPythonInterp.cmake`附带的设置了一些CMake变量: +除了在系统上实际查找包模块之外,查找模块还会设置了一些有用的变量,反映实际找到了什么,也可以在自己的`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解释器的补丁版本号 +* **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)` @@ -82,15 +85,15 @@ find_package(PythonInterp REQUIRED) ## 更多信息 -有时,软件包没有安装在标准位置时,CMake无法正确定位它们。用户可以使用CLI的`-D`参数传递相应的选项,告诉CMake查看特定的位置。Python解释器可以使用以下配置: +软件包没有安装在标准位置时,CMake无法正确定位它们。用户可以使用CLI的`-D`参数传递相应的选项,告诉CMake查看特定的位置。Python解释器可以使用以下配置: ```shell $ cmake -D PYTHON_EXECUTABLE=/custom/location/python .. ``` -这将正确地指定非标准`/custom/location/pytho`安装目录中的Python可执行文件。 +这将指定非标准`/custom/location/pytho`安装目录中的Python可执行文件。 -**NOTE**:*每个包都是不同的,`Find.cmake`模块试图提供统一的检测接口。当CMake无法找到模块包时,我们建议您阅读相应检测模块的文档,以了解如何正确地使用CMake模块。您可以在终端中直接浏览文档,本例中可使用`cmake --help-module FindPythonInterp`查看。* +**NOTE**:*每个包都是不同的,`Find.cmake`模块试图提供统一的检测接口。当CMake无法找到模块包时,我们建议您阅读相应检测模块的文档,以了解如何正确地使用CMake模块。可以在终端中直接浏览文档,本例中可使用`cmake --help-module FindPythonInterp`查看。* 除了检测包之外,我们还想提到一个便于打印变量的helper模块。本示例中,我们使用了以下方法: @@ -99,7 +102,7 @@ message(STATUS "RESULT_VARIABLE is: ${_status}") message(STATUS "OUTPUT_VARIABLE is: ${_hello_world}") ``` -一种便捷的调试方法是使用以下工具: +使用以下工具进行调试: ```cmake include(CMakePrintHelpers) diff --git a/content/chapter3/3.10-chinese.md b/content/chapter3/3.10-chinese.md index ed94a29..f592f08 100644 --- a/content/chapter3/3.10-chinese.md +++ b/content/chapter3/3.10-chinese.md @@ -1,8 +1,8 @@ -# 3.10 检测外部库:Ⅱ. 书写find模块 +# 3.10 检测外部库:Ⅱ. 自定义find模块 -**NOTE**:*此示例代码可以在 https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-03/recipe-10 中找到,包含C的示例。该示例在CMake 3.5版(或更高版本)中是有效的,并且已经在GNU/Linux、macOS和Windows上进行过测试。* +**NOTE**:*此示例代码可以在 https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-03/recipe-10 中找到,包含一个C的示例。该示例在CMake 3.5版(或更高版本)中是有效的,并且已经在GNU/Linux、macOS和Windows上进行过测试。* -此示例补充了上一节的示例,我们将展示如何编写一个find模块来定位系统上的ZeroMQ消息库,以便能够在非Unix操作系统上检测该库。我们重用服务器-客户端示例代码。 +此示例补充了上一节的示例,我们将展示如何编写一个`find`模块来定位系统上的ZeroMQ消息库,以便能够在非Unix操作系统上检测该库。我们重用服务器-客户端示例代码。 ## 如何实施 @@ -20,13 +20,13 @@ set(CMAKE_C_STANDARD_REQUIRED ON) ``` -2. 我们将当前源目录`CMAKE_CURRENT_SOURCE_DIR`,添加到CMake将查找模块的路径列表`CMAKE_MODULE_PATH`中。这样CMake就可以找到,我们自己书写的`FindZeroMQ.cmake`模块: +2. 将当前源目录`CMAKE_CURRENT_SOURCE_DIR`,添加到CMake将查找模块的路径列表`CMAKE_MODULE_PATH`中。这样CMake就可以找到,我们自定义的`FindZeroMQ.cmake`模块: ```cmake list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}) ``` -3. 我们将稍后讨论` FindZeroMQ.cmake `,现在`FindZeroMQ.cmake`模块是可用的,我们可以通过这个模块来搜索库,这个库也就是我们项目所需的依赖项。由于我们没有使用`QUIET`选项来查找`find_packag`e,所以当找到库时,状态消息将自动打印: +3. 现在`FindZeroMQ.cmake`模块是可用的,可以通过这个模块来搜索项目所需的依赖项。由于我们没有使用`QUIET`选项来查找`find_package`,所以当找到库时,状态消息将自动打印: ```cmake find_package(ZeroMQ REQUIRED) @@ -62,7 +62,7 @@ 此示例的主`CMakeLists.txt`在使用`FindZeroMQ.cmake`时,与前一个示例中使用的`CMakeLists.txt`不同。这个模块使用`find_path`和`find_library` CMake内置命令,搜索ZeroMQ头文件和库,并使用`find_package_handle_standard_args`设置相关变量,就像我们在第3节中做的那样。 -1. 在`FindZeroMQ.cmake`中,首先检查`ZeroMQ_ROOT` CMake变量,用户是否由设置。此变量可用于将ZeroMQ库的检测,并引导到非标准安装目录。用户可能设置了`ZeroMQ_ROOT`作为环境变量,我们也会进行检查了: +1. `FindZeroMQ.cmake`中,检查了`ZeroMQ_ROOT`变量是否设置。此变量可用于将ZeroMQ库的检测,并引导到非标准安装目录。用户可能设置了`ZeroMQ_ROOT`作为环境变量,我们也会进行检查了: ```cmake if(NOT ZeroMQ_ROOT) @@ -70,7 +70,7 @@ endif() ``` -2. 然后,搜索系统上`zmq.h`头文件的位置。这是基于`_ZeroMQ_ROOT`变量和`find_path` CMake命令进行的: +2. 然后,搜索系统上`zmq.h`头文件的位置。这是基于`_ZeroMQ_ROOT`变量和`find_path`命令进行的: ```cmake if(NOT ZeroMQ_ROOT) @@ -82,7 +82,7 @@ find_path(ZeroMQ_INCLUDE_DIRS NAMES zmq.h HINTS ${_ZeroMQ_ROOT}/include) ``` -3. 如果成功找到头文件,则将`ZeroMQ_INCLUDE_DIRS`设置为其位置。我们继续,通过使用字符串操作和正则表达式,寻找相应版本的ZeroMQ库: +3. 如果成功找到头文件,则将`ZeroMQ_INCLUDE_DIRS`设置为其位置。我们继续通过使用字符串操作和正则表达式,寻找相应版本的ZeroMQ库: ```cmake set(_ZeroMQ_H ${ZeroMQ_INCLUDE_DIRS}/zmq.h) @@ -100,7 +100,7 @@ _zmqver_EXTRACT("ZMQ_VERSION_PATCH" ZeroMQ_VERSION_PATCH) ``` -4. 然后,我们为`find_package_handle_standard_arg`s命令准备`ZeroMQ_VERSION`变量: +4. 然后,为`find_package_handle_standard_args`准备`ZeroMQ_VERSION`变量: ```cmake if(ZeroMQ_FIND_VERSION_COUNT GREATER 2) @@ -110,7 +110,7 @@ endif() ``` -5. 我们使用`find_library`命令搜索ZeroMQ库。因为库的命名有所不同,这里我们需要区分Unix的平台和Windows平台: +5. 使用`find_library`命令搜索ZeroMQ库。因为库的命名有所不同,这里我们需要区分Unix的平台和Windows平台: ```cmake if(NOT ${CMAKE_C_PLATFORM_ID} STREQUAL "Windows") @@ -152,11 +152,11 @@ ) ``` -**NOTE**:*刚才描述的`FindZeroMQ.cmake`模块已经在 https://github.com/zeromq/azmq/blob/master/config/FindZeroMQ.cmake 上进行了修改* +**NOTE**:*刚才描述的`FindZeroMQ.cmake`模块已经在 https://github.com/zeromq/azmq/blob/master/config/FindZeroMQ.cmake 上进行了修改。* -## 如何工作 +## 工作原理 -find-module通常遵循特定的模式: +`find-module`通常遵循特定的模式: 1. 检查用户是否为所需的包提供了自定义位置。 @@ -172,7 +172,7 @@ find-module通常遵循特定的模式: 5. 最后,调用`find_package_handle_standard_args`命令。处理`find_package`命令的`REQUIRED`、`QUIET`和版本参数,并设置`ZeroMQ_FOUND`变量。 -**NOTE**:*任何CMake命令的完整文档都可以从命令行获得。例如,`cmake --help-command find_file`将输出`find_file`命令的手册页。对于CMake标准模块的手册页,可以在CLI使用`--help-module`。例如,`cmake --help-module FindPackageHandleStandardArgs`将输出`FindPackageHandleStandardArgs.cmake`的手册页面。* +**NOTE**:*任何CMake命令的完整文档都可以从命令行获得。例如,`cmake --help-command find_file`将输出`find_file`命令的手册页。对于CMake标准模块的手册,可以在CLI使用`--help-module`看到。例如,`cmake --help-module FindPackageHandleStandardArgs`将输出`FindPackageHandleStandardArgs.cmake`的手册页面。* ## 更多信息 @@ -181,7 +181,7 @@ find-module通常遵循特定的模式: 1. 使用由包供应商提供CMake文件` Config.cmake` ,`ConfigVersion.cmake`和`Targets.cmake`,通常会在包的标准安装位置查找。 2. 无论是由CMake还是第三方提供的模块,为所需包使用`find-module`。 3. 使用`pkg-config`,如本节的示例所示。 -4. 如果这些都不可行,那么编写自己的find模块。 +4. 如果这些都不可行,那么编写自己的`find`模块。 这四种可选方案按相关性进行了排序,每种方法也都有其挑战。 @@ -189,10 +189,10 @@ find-module通常遵循特定的模式: 从一开始,`Find-module`就一直是CMake中定位依赖的主流手段。但是,它们中的大多数仍然依赖于设置依赖项使用的变量,比如`Boost_INCLUDE_DIRS`、`PYTHON_INTERPRETER`等等。这种方式很难在第三方要发布自己的包时,确保依赖关系始终被满足。 -使用`pkg-config`的方法可以很好地工作,因为它已经成为Unix的系统的标准。然而,也由于这个原因,它不是一个完全跨平台的方法。此外,如CMake文档所述,在某些情况下,用户可能会意外地覆盖包检测,并导致`pkg-config`提供不正确的信息。 +使用`pkg-config`的方法可以很好地工作,因为它已经成为Unix系统的标准。然而,也由于这个原因,它不是一个完全跨平台的方法。此外,如CMake文档所述,在某些情况下,用户可能会意外地覆盖包检测,并导致`pkg-config`提供不正确的信息。 最后的方法是编写自己的查找模块脚本,就像本示例中那样。这是可行的,并且依赖于`FindPackageHandleStandardArgs.cmake `。然而,编写一个全面的查找模块脚本绝非易事;有需要考虑很多可能性,我们在Unix和Windows平台上,为查找ZeroMQ库文件演示了一个例子。 -所有软件开发人员都非常清楚这些问题和困难,正如CMake邮件列表上讨论所示: https://cmake.org/pipermail/cmake/2018-May/067556.html 。`pkg-config`在Unix包开发人员中是可以接受的,但是它不能很容易地移植到非Unix平台。CMake配置文件功能强大,但并非所有软件开发人员都熟悉CMake语法。公共包规范项目,是统一用于包查找的pkg-config和CMake配置文件方法的最新尝试。您可以在项目的网站上找到更多信息: https://mwoehlke.github.io/cps/ +所有软件开发人员都非常清楚这些问题和困难,正如CMake邮件列表上讨论所示: https://cmake.org/pipermail/cmake/2018-May/067556.html 。`pkg-config`在Unix包开发人员中是可以接受的,但是它不能很容易地移植到非Unix平台。CMake配置文件功能强大,但并非所有软件开发人员都熟悉CMake语法。公共包规范项目是统一用于包查找的`pkg-config`和CMake配置文件方法的最新尝试。您可以在项目的网站上找到更多信息: https://mwoehlke.github.io/cps/ 在第10章中将讨论,如何使用前面讨论中概述的第一种方法,使第三方应用程序,找到自己的包:为项目提供自己的CMake查找文件。 \ No newline at end of file diff --git a/content/chapter3/3.2-chinese.md b/content/chapter3/3.2-chinese.md index 9362f30..e01e911 100644 --- a/content/chapter3/3.2-chinese.md +++ b/content/chapter3/3.2-chinese.md @@ -1,14 +1,14 @@ # 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上进行过测试。* +**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)与编译语言(如C或C++)组合在一起使用。一种是扩展Python,通过编译成共享库的C或C++模块在这些类型上提供新类型和新功能,这是第9章的主题。另一种是将Python解释器嵌入到C或C++程序中。两种方法都需要下列条件: * Python解释器的工作版本 * Python头文件Python.h的可用性 * Python运行时库libpython -三个组件所使用的Python版本必须相同。我们已经演示了,如何找到Python解释器;本示例中,我们将展示另外两种方式。 +三个组件所使用的Python版本必须相同。我们已经演示了如何找到Python解释器;本示例中,我们将展示另外两种方式。 ## 准备工作 @@ -16,6 +16,7 @@ ```c #include + int main(int argc, char *argv[]) { Py_SetProgramName(argv[0]); /* optional but recommended */ Py_Initialize(); @@ -32,16 +33,16 @@ int main(int argc, char *argv[]) { ## 具体实施 -以下是我们的`CMakeLists.txt`中要遵循的步骤: +以下是`CMakeLists.txt`中的步骤: -1. 第一个块包含最低的CMake版本、项目名称和所需语言: +1. 包含CMake最低版本、项目名称和所需语言: ```cmake cmake_minimum_required(VERSION 3.5 FATAL_ERROR) project(recipe-02 LANGUAGES C) ``` -2. 在这个示例中,我们强制使用C99标准。这不严格要求与Python链接,但有时你可能需要对Python进行连接: +2. 制使用C99标准,这不严格要求与Python链接,但有时你可能需要对Python进行连接: ```cmake set(CMAKE_C_STANDARD 99) @@ -55,19 +56,19 @@ int main(int argc, char *argv[]) { find_package(PythonInterp REQUIRED) ``` -4. 找到Python头文件和库。相应的模块称为`FindPythonLibs.cmake`: +4. 找到Python头文件和库的模块,称为`FindPythonLibs.cmake`: ```cmake find_package(PythonLibs ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR} EXACT REQUIRED) ``` -5. 我们添加了一个可执行目标,它使用`hello-embedded-python.c`源文件: +5. 使用`hello-embedded-python.c`源文件,添加一个可执行目标: ```cmake add_executable(hello-embedded-python hello-embedded-python.c) ``` -6. 可执行文件包含`Python.h`头文件。因此,这个目标的include目录必须包含Python的include目录,可以通过`PYTHON_INCLUDE_DIRS`变量进行指定: +6. 可执行文件包含`Python.h`头文件。因此,这个目标的`include`目录必须包含Python的`include`目录,可以通过`PYTHON_INCLUDE_DIRS`变量进行指定: ```cmake target_include_directories(hello-embedded-python @@ -85,7 +86,7 @@ int main(int argc, char *argv[]) { ) ``` -8. 现在,我们准备运行配置步骤: +8. 现在,进行构建: ```shell $ mkdir -p build @@ -97,7 +98,7 @@ int main(int argc, char *argv[]) { -- Found PythonLibs: /usr/lib/libpython3.6m.so (found suitable exact version "3.6.5") ``` -9. 最后,我们执行构建步骤,并运行可执行文件: +9. 最后,执行构建,并运行可执行文件: ```shell $ cmake --build . @@ -128,14 +129,14 @@ 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_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的检测部分也将简化为: +要将Python解释器及其开发组件匹配为完全相同的版本可能非常困难,对于那些将它们安装在非标准位置或系统上安装了多个版本的情况尤其如此。CMake 3.12版本中增加了新的Python检测模块,旨在解决这个棘手的问题。我们`CMakeLists.txt`的检测部分也将简化为: `find_package(Python COMPONENTS Interpreter Development REQUIRED)` diff --git a/content/chapter3/3.3-chinese.md b/content/chapter3/3.3-chinese.md index b8f4103..19c73c1 100644 --- a/content/chapter3/3.3-chinese.md +++ b/content/chapter3/3.3-chinese.md @@ -1,12 +1,12 @@ # 3.3 检测Python模块和包 -**NOTE**:*此示例代码可以在 https://github.com/devcafe/cmake-cookbook/tree/v1.0/chapter-03/recipe-03 中找到,包含C++示例。该示例在CMake 3.5版(或更高版本)中是有效的,并且已经在GNU/Linux、macOS和Windows上进行过测试。* +**NOTE**:*此示例代码可以在 https://github.com/devcafe/cmake-cookbook/tree/v1.0/chapter-03/recipe-03 中找到,包含一个C++示例。该示例在CMake 3.5版(或更高版本)中是有效的,并且已经在GNU/Linux、macOS和Windows上进行过测试。* -在前面的示例中,我们演示了如何检测Python解释器,以及如何编译一个简单的C程序(嵌入Python解释器)。结合Python和编译语言时,这两个是非常简单的任务。通常,您的代码将依赖于特定的Python模块,无论是Python工具、嵌入Python的编译程序,还是扩展Python的库。例如,NumPy在矩阵代数的问题上,在科学界非常流行。依赖于Python模块或包的项目中,确定满足对这些Python模块的依赖非常重要。本示例将展示如何探测用户的环境,以找到特定的Python模块和包。 +前面的示例中,我们演示了如何检测Python解释器,以及如何编译一个简单的C程序(嵌入Python解释器)。通常,代码将依赖于特定的Python模块,无论是Python工具、嵌入Python的程序,还是扩展Python的库。例如,科学界非常流行使用NumPy处理矩阵问题。依赖于Python模块或包的项目中,确定满足对这些Python模块的依赖非常重要。本示例将展示如何探测用户的环境,以找到特定的Python模块和包。 ## 准备工作 -我们将尝试在C++程序中嵌入一个稍微复杂一点的例子。这个示例再次引用Python在线文档( https://docs.python.org/3.5/extending/embedding.html#pureembedded ),并展示了如何通过调用编译后的C++可执行文件,来执行用户定义的Python模块中的函数。 +我们将尝试在C++程序中嵌入一个稍微复杂一点的例子。这个示例再次引用[Python在线文档](https://docs.python.org/3.5/extending/embedding.html#pureembedded),并展示了如何通过调用编译后的C++可执行文件,来执行用户定义的Python模块中的函数。 Python 3示例代码(`Py3-pure-embedding.cpp`)包含以下源代码(请参见https://docs.python.org/2/extending/embedding.html#pure-embedded 与Python 2代码等效): @@ -89,7 +89,7 @@ def print_ones(rows, cols): return(num_elements) ``` -## 如何实施 +## 具体实施 下面的代码中,我们能够使用CMake检查NumPy是否可用。我们需要确保Python解释器、头文件和库在系统上是可用的。然后,将再来确认NumPy的可用性: @@ -110,7 +110,7 @@ def print_ones(rows, cols): find_package(PythonLibs ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR} EXACT REQUIRED) ``` -3. 正确打包的Python模块,知道它们的安装位置和版本。可以通过执行一个最小的Python脚本来探测。可以在`CMakeLists.txt`中执行: +3. 正确打包的Python模块,指定安装位置和版本。可以在`CMakeLists.txt`中执行Python脚本进行探测: ```cmake execute_process( @@ -123,7 +123,7 @@ def print_ones(rows, cols): ) ``` -4. 如果找到NumPy,则`_numpy_status`变量为整数,否则为错误的字符串,而`_numpy_location`将包含NumPy模块的路径。如果找到NumPy,我们将它的位置保存到一个名为NumPy的新变量中。注意,新变量被缓存,这意味着CMake创建了一个持久性变量,用户稍后可以修改该变量: +4. 如果找到NumPy,则`_numpy_status`变量为整数,否则为错误的字符串,而`_numpy_location`将包含NumPy模块的路径。如果找到NumPy,则将它的位置保存到一个名为`NumPy`的新变量中。注意,新变量被缓存,这意味着CMake创建了一个持久性变量,用户稍后可以修改该变量: ```cmake if(NOT _numpy_status) @@ -175,7 +175,7 @@ def print_ones(rows, cols): ) ``` -8. 我们还必须保证`use_numpy.py`在build目录中可用: +8. 我们还必须保证`use_numpy.py`在`build`目录中可用: ```cmake add_custom_command( @@ -215,13 +215,17 @@ def print_ones(rows, cols): Result of call: 6 ``` -## 如何工作 +## 工作原理 -这个例子中有三个新的CMake命令:`execute_process`和`add_custom_command`,以及`find_package_handle_standard_args`,它需要`include(FindPackageHandleStandardArgs)`。 +例子中有三个新的CMake命令,需要`include(FindPackageHandleStandardArgs)`: -`execute_process`命令将作为CMake命令的子进程执行一个或多个命令。最后,子进程返回值将保存到变量作为参数传递给`RESULT_VARIABLE`,而管道标准输出和标准错误的内容将被保存到变量作为参数传递给`OUTPUT_VARIABLE`和`ERROR_VARIABLE`。`execute_process`可以执行任何命令,并使用它们的结果来推断系统的配置。在本例中,首先用它来确保NumPy可用,然后获得相应模块的版本。 +* `execute_process` +* `add_custom_command` +* `find_package_handle_standard_args` -`find_package_handle_standard_args`命令提供了标准工具,用于处理与查找安装系统上的相关程序和库。引用此命令时,可以正确的处理与版本相关的选项(`REQUIRED`和`EXACT`),而无需更多的CMake代码。稍后我们将介绍`QUIET`和`COMPONENTS`选项,其也由CMake命令处理。在本示例中,我们使用了以下方法: +`execute_process`将作为通过子进程执行一个或多个命令。最后,子进程返回值将保存到变量作为参数,传递给`RESULT_VARIABLE`,而管道标准输出和标准错误的内容将被保存到变量作为参数传递给`OUTPUT_VARIABLE`和`ERROR_VARIABLE`。`execute_process`可以执行任何操作,并使用它们的结果来推断系统配置。本例中,用它来确保NumPy可用,然后获得模块版本。 + +`find_package_handle_standard_args`提供了,用于处理与查找相关程序和库的标准工具。引用此命令时,可以正确的处理与版本相关的选项(`REQUIRED`和`EXACT`),而无需更多的CMake代码。稍后将介绍`QUIET`和`COMPONENTS`选项。本示例中,使用了以下方法: ```cmake include(FindPackageHandleStandardArgs) @@ -232,15 +236,15 @@ find_package_handle_standard_args(NumPy ) ``` -所有必需的变量都设置为有效的文件路径(NumPy)后,命令将变量设置后,发送到模块(`NumPy_FOUND`)。它还将版本保存在可传递的版本变量(`_numpy_version`)中,并为用户打印状态消息: +所有必需的变量都设置为有效的文件路径(NumPy)后,发送到模块(`NumPy_FOUND`)。它还将版本保存在可传递的版本变量(`_numpy_version`)中并打印: ```shell -- Found NumPy: /usr/lib/python3.6/site-packages/numpy (found version "1.14.3") ``` -在目前的示例中,我们没有进一步使用这些变量。如果返回`NumPy_FOUND`为FALSE,我们可以停止配置。 +目前的示例中,没有进一步使用这些变量。如果返回`NumPy_FOUND`为`FALSE`,则停止配置。 -最后,我们应该将`use_numpy.py`复制到build目录,将代码段进行注释: +最后,将`use_numpy.py`复制到`build`目录,对代码进行注释: ```cmake add_custom_command( @@ -259,4 +263,4 @@ target_sources(pure-embedding ) ``` -我们也可以使用`file(COPY…)`命令来实现复制。这里,我们选择使用`add_custom_command`,来确保文件在每次更改时都会被复制,而不仅仅是第一次运行配置时。我们将在第5章更详细地讨论`add_custom_command`。还要注意`target_sources`命令,它将依赖项添加到`${CMAKE_CURRENT_BINARY_DIR}/use_numpy.py`;这样做是为了确保构建目标,触发前面的定制命令。 \ No newline at end of file +我们也可以使用`file(COPY…)`命令来实现复制。这里,我们选择使用`add_custom_command`,来确保文件在每次更改时都会被复制,而不仅仅是第一次运行配置时。我们将在第5章更详细地讨论`add_custom_command`。还要注意`target_sources`命令,它将依赖项添加到`${CMAKE_CURRENT_BINARY_DIR}/use_numpy.py`;这样做是为了确保构建目标,能够触发之前的命令。 \ No newline at end of file diff --git a/content/chapter3/3.4-chinese.md b/content/chapter3/3.4-chinese.md index 73b349b..5697a1a 100644 --- a/content/chapter3/3.4-chinese.md +++ b/content/chapter3/3.4-chinese.md @@ -1,8 +1,8 @@ # 3.4 检测BLAS和LAPACK数学库 -**NOTE**:*此示例代码可以在 https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-03/recipe-04 中找到,有C++示例。该示例在CMake 3.5版(或更高版本)中是有效的,并且已经在GNU/Linux、macOS和Windows上进行过测试。* +**NOTE**:*此示例代码可以在 https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-03/recipe-04 中找到,有一个C++示例。该示例在CMake 3.5版(或更高版本)中是有效的,并且已经在GNU/Linux、macOS和Windows上进行过测试。* -许多数据算法严重依赖于矩阵和向量运算。例如:矩阵-向量和矩阵-矩阵乘法,求线性方程组的解,特征值和特征向量的计算或奇异值分解。这些操作在代码库中非常普遍,因为操作的数据量比较大,因此高效的实现有绝对的必要。幸运的是,有特定的库可用:基本线性代数子程序(BLAS)和线性代数包(LAPACK),为许多线性代数操作提供了标准API。供应商有不同的实现,但都共享API。虽然,用于数学库底层实现,实际所用的编程语言会随着时间而变化(Fortran、C、Assembly),但是也都是Fortran调用约定。考虑到调用约定,我们在本示例中的任务要链接到这些库,并展示如何用不同语言编写的库。 +许多数据算法严重依赖于矩阵和向量运算。例如:矩阵-向量和矩阵-矩阵乘法,求线性方程组的解,特征值和特征向量的计算或奇异值分解。这些操作在代码库中非常普遍,因为操作的数据量比较大,因此高效的实现有绝对的必要。幸运的是,有专家库可用:基本线性代数子程序(BLAS)和线性代数包(LAPACK),为许多线性代数操作提供了标准API。供应商有不同的实现,但都共享API。虽然,用于数学库底层实现,实际所用的编程语言会随着时间而变化(Fortran、C、Assembly),但是也都是Fortran调用接口。考虑到调用街扩,本示例中的任务要链接到这些库,并展示如何用不同语言编写的库。 ## 准备工作 @@ -65,9 +65,9 @@ int main(int argc, char** argv) { } ``` -我们使用C++11中引入的随机库来生成-1.0到1.0之间的随机分布。`C_DSCAL`和`C_DGESV`分别是到BLAS和LAPACK库的接口。为了避免名称混淆,以便从不同的编程语言调用这些函数,在下面来进一步讨论CMake模块: +使用C++11的随机库来生成-1.0到1.0之间的随机分布。`C_DSCAL`和`C_DGESV`分别是到BLAS和LAPACK库的接口。为了避免名称混淆,将在下面来进一步讨论CMake模块: -文件`CxxBLAS.hpp`用`extern"C"`封装链接BLAS: +文件`CxxBLAS.hpp`用`extern "C"`封装链接BLAS: ```c++ #pragma once @@ -104,11 +104,11 @@ void C_DSCAL(size_t length, double alpha, double *vec, int inc) { `CxxLAPACK.hpp`和`CxxLAPACK.cpp`为LAPACK调用执行相应的转换。 -## 实施步骤 +## 具体实施 -对应的CMakeLists.txt包含以下构建块: +对应的`CMakeLists.txt`包含以下构建块: -1. 我们定义了最低CMake版本,项目名称和支持的语言: +1. 我们定义了CMake最低版本,项目名称和支持的语言: ```cmake cmake_minimum_required(VERSION 3.5 FATAL_ERROR) @@ -137,14 +137,14 @@ void C_DSCAL(size_t length, double alpha, double *vec, int inc) { ) ``` -4. 然后,让CMake找到BLAS和LAPACK。这些是必要的依赖: +4. 然后,找到BLAS和LAPACK: ```cmake find_package(BLAS REQUIRED) find_package(LAPACK REQUIRED) ``` -5. 接下来,我们添加一个库,其中包含BLAS和LAPACK包装器的源代码,并链接到`LAPACK_LIBRARIES`,其中也包含`BLAS_LIBRARIES`: +5. 接下来,添加一个库,其中包含BLAS和LAPACK包装器的源代码,并链接到`LAPACK_LIBRARIES`,其中也包含`BLAS_LIBRARIES`: ```cmake add_library(math "") @@ -185,7 +185,7 @@ void C_DSCAL(size_t length, double alpha, double *vec, int inc) { ) ``` -8. 在配置步骤中,我们可以关注相关的输出: +8. 配置时,我们可以关注相关的打印输出: ```shell $ mkdir -p build @@ -204,7 +204,7 @@ void C_DSCAL(size_t length, double alpha, double *vec, int inc) { ... ``` -9. 最后,我们构建并测试可执行文件: +9. 最后,构建并测试可执行文件: ```shell $ cmake --build . @@ -216,7 +216,7 @@ void C_DSCAL(size_t length, double alpha, double *vec, int inc) { check is 1.54284e-10 ``` -## 如何工作 +## 工作原理 `FindBLAS.cmake`和`FindLAPACK.cmake`将在标准位置查找BLAS和LAPACK库。对于前者,该模块有`SGEMM`函数的Fortran实现,一般用于单精度矩阵乘积。对于后者,该模块有`CHEEV`函数的Fortran实现,用于计算复杂厄米矩阵的特征值和特征向量。查找在CMake内部,通过编译一个小程序来完成,该程序调用这些函数,并尝试链接到候选库。如果失败,则表示相应库不存于系统上。 @@ -228,4 +228,4 @@ void C_DSCAL(size_t length, double alpha, double *vec, int inc) { ## 更多信息 -许多算法代码比较依赖于矩阵代数运算,使用BLAS和LAPACK API的高性能实现就非常重要了。供应商为不同的体系结构和并行环境提供不同的库,`FindBLAS.cmake`和` FindLAPACK.cmake`可能的无法定位到当前库。如果发生这种情况,您可以通过`-D`选项显式地从CLI对库进行设置。 \ No newline at end of file +许多算法代码比较依赖于矩阵代数运算,使用BLAS和LAPACK API的高性能实现就非常重要了。供应商为不同的体系结构和并行环境提供不同的库,`FindBLAS.cmake`和` FindLAPACK.cmake`可能的无法定位到当前库。如果发生这种情况,可以通过`-D`选项显式地从CLI对库进行设置。 \ No newline at end of file diff --git a/content/chapter3/3.5-chinese.md b/content/chapter3/3.5-chinese.md index 23c02e1..9b7d6ff 100644 --- a/content/chapter3/3.5-chinese.md +++ b/content/chapter3/3.5-chinese.md @@ -1,10 +1,10 @@ # 3.5 检测OpenMP的并行环境 -**NOTE**:*此示例代码可以在 https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-03/recipe-05 中找到,有C++和Fortran示例。该示例在CMake 3.5版(或更高版本)中是有效的,并且已经在GNU/Linux、macOS和Windows上进行过测试。https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-03/recipe-05 中也有一个适用于CMake 3.5的示例。* +**NOTE**:*此示例代码可以在 https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-03/recipe-05 中找到,有一个C++和一个Fortran示例。该示例在CMake 3.5版(或更高版本)中是有效的,并且已经在GNU/Linux、macOS和Windows上进行过测试。https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-03/recipe-05 中也有一个适用于CMake 3.5的示例。* 目前,市面上的计算机几乎都是多核机器,对于性能敏感的程序,我们必须关注这些多核处理器,并在编程模型中使用并发。OpenMP是多核处理器上并行性的标准之一。为了从OpenMP并行化中获得性能收益,通常不需要修改或重写现有程序。一旦确定了代码中的性能关键部分,例如:使用分析工具,程序员就可以通过预处理器指令,指示编译器为这些区域生成可并行的代码。 -在本示例中,我们将展示如何编译一个包含OpenMP指令的程序(前提是使用一个支持OpenMP的编译器)。有许多支持OpenMP的Fortran、C和C++编译器。对于相对较新的CMake版本,为OpenMP提供了非常好的支持。本示例将向展示如何在使用CMake 3.9或更高版本时,使用简单C++和Fortran程序来检测,并链接到OpenMP。 +本示例中,我们将展示如何编译一个包含OpenMP指令的程序(前提是使用一个支持OpenMP的编译器)。有许多支持OpenMP的Fortran、C和C++编译器。对于相对较新的CMake版本,为OpenMP提供了非常好的支持。本示例将展示如何在使用CMake 3.9或更高版本时,使用简单C++和Fortran程序来链接到OpenMP。 **NOTE**:*根据Linux发行版的不同,Clang编译器的默认版本可能不支持OpenMP。使用或非苹果版本的Clang(例如,Conda提供的)或GNU编译器,除非单独安装libomp库(https://iscinumpy.gitlab.io/post/omp-on-high-sierra/ ),否则本节示例将无法在macOS上工作。* @@ -42,7 +42,7 @@ int main(int argc, char *argv[]) } ``` -在Fortran语言中,需要使用`omp_lib`模块并链接到库。在性能关键部分之前的代码注释中,可以再次使用并行指令。例如:F90需要包含以下内容: +在Fortran语言中,需要使用`omp_lib`模块并链接到库。在性能关键部分之前的代码注释中,可以再次使用并行指令。例如:`F90`需要包含以下内容: ```fortran program example @@ -85,7 +85,7 @@ end program 对于C++和Fortran的例子,`CMakeLists.txt`将遵循一个模板,该模板在这两种语言上很相似: -1. 两者都定义了一个最低CMake版本、项目名称和语言(CXX或Fortran;我们将展示C++版本): +1. 两者都定义了CMake最低版本、项目名称和语言(CXX或Fortran;我们将展示C++版本): ```cmake cmake_minimum_required(VERSION 3.9 FATAL_ERROR) @@ -151,7 +151,7 @@ end program ## 工作原理 -我们的示例很简单:编译并链接的代码,运行在多个内核上时,我们会看到加速效果。加速效果并不是`OMP_NUM_THREADS`的倍数,不过本示例中并不关心,因为我们更关注的是如何使用CMake配置需要使用OpenMP的项目。我们发现链接到OpenMP非常简单,这要感谢`FindOpenMP`模块提供的目标: +我们的示例很简单:编译代码,并运行在多个内核上时,我们会看到加速效果。加速效果并不是`OMP_NUM_THREADS`的倍数,不过本示例中并不关心,因为我们更关注的是如何使用CMake配置需要使用OpenMP的项目。我们发现链接到OpenMP非常简单,这要感谢`FindOpenMP`模块提供的目标: ```cmake target_link_libraries(example @@ -174,7 +174,7 @@ cmake_print_properties( ) ``` -所有属性都有`INTERFACE_`前缀,因为这些属性对所需目标,需要是以接口形式提供,并且目标以接口的方式使用OpenMP。 +所有属性都有`INTERFACE_`前缀,因为这些属性对所需目标,需要以接口形式提供,并且目标以接口的方式使用OpenMP。 对于低于3.9的CMake版本,我们有更多的工作量: @@ -194,4 +194,4 @@ set_target_properties(example 对于低于3.5的CMake版本,我们需要为Fortran项目显式定义编译标志。 -在这个示例中,我们讨论了C++和Fortran,相同的参数和方法对于C项目也有效。 \ No newline at end of file +在这个示例中,我们讨论了C++和Fortran。相同的参数和方法对于C项目也有效。 \ No newline at end of file diff --git a/content/chapter3/3.6-chinese.md b/content/chapter3/3.6-chinese.md index f87dc56..52bda5a 100644 --- a/content/chapter3/3.6-chinese.md +++ b/content/chapter3/3.6-chinese.md @@ -1,6 +1,6 @@ # 3.6 检测MPI的并行环境 -**NOTE**:*此示例代码可以在 https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-03/recipe-06 中找到,包含C++和C的示例。该示例在CMake 3.9版(或更高版本)中是有效的,并且已经在GNU/Linux、macOS和Windows上进行过测试。https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-03/recipe-06 中也有一个适用于CMake 3.5的C示例。* +**NOTE**:*此示例代码可以在 https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-03/recipe-06 中找到,包含一个C++和一个C的示例。该示例在CMake 3.9版(或更高版本)中是有效的,并且已经在GNU/Linux、macOS和Windows上进行过测试。https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-03/recipe-06 中也有一个适用于CMake 3.5的C示例。* 消息传递接口(Message Passing Interface, MPI),可以作为OpenMP(共享内存并行方式)的补充,它也是分布式系统上并行程序的实际标准。尽管,最新的MPI实现也允许共享内存并行,但高性能计算中的一种典型方法就是,在计算节点上OpenMP与MPI结合使用。MPI标准的实施包括: @@ -51,9 +51,9 @@ int main(int argc, char **argv) ## 具体实施 -在这个示例中,我们先查找MPI实现:库、头文件、编译器包装器和启动器。为此,我们将用到`FindMPI.cmake`标准cmake模块: +这个示例中,我们先查找MPI实现:库、头文件、编译器包装器和启动器。为此,我们将用到`FindMPI.cmake`标准cmake模块: -1. 首先,我们定义了最低CMake版本、项目名称、支持的语言和语言标准: +1. 首先,定义了CMake最低版本、项目名称、支持的语言和语言标准: ```cmake cmake_minimum_required(VERSION 3.9 FATAL_ERROR) @@ -65,13 +65,13 @@ int main(int argc, char **argv) set(CMAKE_CXX_STANDARD_REQUIRED ON) ``` -2. 然后,调用find_package来定位MPI实现: +2. 然后,调用`find_package`来定位MPI: ```cmake find_package(MPI REQUIRED) ``` -3. 与前面的配置类似,我们定义了可执行文件的的名称和相关源码,并链接到目标: +3. 与前面的配置类似,定义了可执行文件的的名称和相关源码,并链接到目标: ```cmake add_executable(hello-mpi hello-mpi.cpp) @@ -108,7 +108,7 @@ int main(int argc, char **argv) ## 工作原理 -请记住,编译器包装器是对MPI库编译器的封装。底层实现中,将会调用相同的编译器,并使用额外的参数(如成功构建并行程序所需的头文件包含路径和库)来扩充它。 +请记住,编译包装器是对MPI库编译器的封装。底层实现中,将会调用相同的编译器,并使用额外的参数(如成功构建并行程序所需的头文件包含路径和库)来扩充它。 编译和链接源文件时,包装器用了哪些标志?我们可以使用`--showme`选项来查看。要找出编译器的标志,我们可以这样使用: @@ -126,7 +126,7 @@ $ mpicxx --showme:link -pthread -Wl,-rpath -Wl,/usr/lib/openmpi -Wl,--enable-new-dtags -L/usr/lib/openmpi -lmpi_cxx -lmpi ``` -与之前的OpenMP配置类似,我们发现到MPI的链接非常简单,这要归功于FindMPI模块提供的目标: +与之前的OpenMP配置类似,我们发现到MPI的链接非常简单,这要归功于`FindMPI`模块提供的目标: 正如在前面的配方中所讨论的,对于CMake版本低于3.9,需要更多的工作量: @@ -149,5 +149,5 @@ target_link_libraries(hello-mpi ) ``` -本示例中,我们讨论了C++项目,其中的参数和方法对于C或Fortran项目同样有效。 +本示例中,我们讨论了C++项目。其中的参数和方法对于C或Fortran项目同样有效。 diff --git a/content/chapter3/3.7-chinese.md b/content/chapter3/3.7-chinese.md index 2db257d..359a62d 100644 --- a/content/chapter3/3.7-chinese.md +++ b/content/chapter3/3.7-chinese.md @@ -1,8 +1,8 @@ # 3.7 检测Eigen库 -**NOTE**:*此示例代码可以在 https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-03/recipe-07 中找到,包含C++的示例。该示例在CMake 3.9版(或更高版本)中是有效的,并且已经在GNU/Linux、macOS和Windows上进行过测试。https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-03/recipe-06 中也有一个适用于CMake 3.5的C++示例。* +**NOTE**:*此示例代码可以在 https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-03/recipe-07 中找到,包含一个C++的示例。该示例在CMake 3.9版(或更高版本)中是有效的,并且已经在GNU/Linux、macOS和Windows上进行过测试。https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-03/recipe-06 中也有一个适用于CMake 3.5的C++示例。* -BLAS库为矩阵和向量操作提供了标准化接口。不过,这个接口用Fortran语言书写。虽然已经展示了如何使用C++直接使用这些库,但在现代C++程序中,更希望有更高级的接口。 +BLAS库为矩阵和向量操作提供了标准化接口。不过,这个接口用Fortran语言书写。虽然已经展示了如何使用C++直接使用这些库,但在现代C++程序中,希望有更高级的接口。 纯头文件实现的Eigen库,使用模板编程来提供接口。矩阵和向量类型易于使用,会在编译时提供类型检查,以确保没有不兼容的矩阵维度。密集和稀疏矩阵的运算,也可使用表达式模板高效的进行实现,如:矩阵-矩阵乘积,线性系统求解器,和特征值问题。从3.3版开始,Eigen可以链接到BLAS和LAPACK库,这可以将某些操作实现进行卸载,使库的实现更加灵活,从而获得更多的性能收益。 @@ -84,7 +84,7 @@ int main(int argc, char **argv) 这个示例中,我们将用到Eigen和BLAS库,以及OpenMP。使用OpenMP将Eigen并行化,并从BLAS库中卸载部分线性代数实现: -1. 我们首先声明最低CMake版本、项目名称和使用C++11语言标准: +1. 首先声明CMake最低版本、项目名称和使用C++11语言标准: ```cmake cmake_minimum_required(VERSION 3.9 FATAL_ERROR) @@ -108,7 +108,7 @@ int main(int argc, char **argv) find_package(Eigen3 3.3 REQUIRED CONFIG) ``` -4. 如果找到Eigen,我们将打印状态信息。注意,我们使用的是`Eigen3::Eigen`,这是一个`IMPORT`目标,可通过提供的CMake脚本找到这个目标: +4. 如果找到Eigen,我们将打印状态信息。注意,使用的是`Eigen3::Eigen`,这是一个`IMPORT`目标,可通过提供的CMake脚本找到这个目标: ```cmake if(TARGET Eigen3::Eigen) @@ -157,7 +157,7 @@ int main(int argc, char **argv) ) ``` -9. 现在已经准备好配置: +9. 开始配置: ```shell $ mkdir -p build @@ -174,7 +174,7 @@ int main(int argc, char **argv) -- See: http://eigen.tuxfamily.org/dox-devel/TopicUsingBlasLapack.html ``` -10. 最后,编译并测试代码。注意,可执行文件使用四个线程: +10. 最后,编译并测试代码。注意,可执行文件使用四个线程运行: ```shell $ cmake --build . diff --git a/content/chapter3/3.8-chinese.md b/content/chapter3/3.8-chinese.md index 1c70f0b..2d38ce2 100644 --- a/content/chapter3/3.8-chinese.md +++ b/content/chapter3/3.8-chinese.md @@ -1,6 +1,6 @@ # 3.8 检测Boost库 -**NOTE**:*此示例代码可以在 https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-03/recipe-08 中找到,包含C++的示例。该示例在CMake 3.5版(或更高版本)中是有效的,并且已经在GNU/Linux、macOS和Windows上进行过测试。* +**NOTE**:*此示例代码可以在 https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-03/recipe-08 中找到,包含一个C++的示例。该示例在CMake 3.5版(或更高版本)中是有效的,并且已经在GNU/Linux、macOS和Windows上进行过测试。* Boost是一组C++通用库。这些库提供了许多功能,这些功能在现代C++项目中不可或缺,但是还不能通过C++标准使用这些功能。例如,Boost为元编程、处理可选参数和文件系统操作等提供了相应的组件。这些库中有许多特性后来被C++11、C++14和C++17标准所采用,但是对于保持与旧编译器兼容性的代码库来说,许多Boost组件仍然是首选。 @@ -83,7 +83,7 @@ int main(int argc, char *argv[]) Boost由许多不同的库组成,这些库可以独立使用。CMake可将这个库集合,表示为组件的集合。`FindBoost.cmake`模块不仅可以搜索库集合的完整安装,还可以搜索集合中的特定组件及其依赖项(如果有的话)。我们将逐步建立相应的`CMakeLists.txt`: -1. 我们首先声明最低CMake版本、项目名称、语言,并使用C++11标准: +1. 首先,声明CMake最低版本、项目名称、语言,并使用C++11标准: ```cmake cmake_minimum_required(VERSION 3.5 FATAL_ERROR) @@ -95,13 +95,13 @@ Boost由许多不同的库组成,这些库可以独立使用。CMake可将这 set(CMAKE_CXX_STANDARD_REQUIRED ON) ``` -2. 然后,使用`find_package`搜索Boost。若需要对Boost强制性依赖,需要一个参数。这个例子中,只需要文件系统组件,所以我们将它作为参数传递给`find_package`: +2. 然后,使用`find_package`搜索Boost。若需要对Boost强制性依赖,需要一个参数。这个例子中,只需要文件系统组件,所以将它作为参数传递给`find_package`: ```cmake find_package(Boost 1.54 REQUIRED COMPONENTS filesystem) ``` -3. 我们添加可执行目标,编译源文件: +3. 添加可执行目标,编译源文件: ```cmake add_executable(path-info path-info.cpp) diff --git a/content/chapter3/3.9-chinese.md b/content/chapter3/3.9-chinese.md index 6bf5e1a..22fcde3 100644 --- a/content/chapter3/3.9-chinese.md +++ b/content/chapter3/3.9-chinese.md @@ -1,10 +1,10 @@ # 3.9 检测外部库:Ⅰ. 使用pkg-config -**NOTE**:*此示例代码可以在 https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-03/recipe-09 中找到,包含C的示例。该示例在CMake 3.6版(或更高版本)中是有效的,并且已经在GNU/Linux、macOS和Windows上进行过测试。https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-03/recipe-09 中也有一个适用于CMake 3.5的示例。* +**NOTE**:*此示例代码可以在 https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-03/recipe-09 中找到,包含一个C的示例。该示例在CMake 3.6版(或更高版本)中是有效的,并且已经在GNU/Linux、macOS和Windows上进行过测试。https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-03/recipe-09 中也有一个适用于CMake 3.5的示例。* 目前为止,我们已经讨论了两种检测外部依赖关系的方法: -* 使用CMake自带的find-module,但并不是所有的包在CMake的find模块都找得到。 +* 使用CMake自带的`find-module`,但并不是所有的包在CMake的`find`模块都找得到。 * 使用` Config.cmake`, ` ConfigVersion.cmake `和`Targets.cmake`,这些文件由软件包供应商提供,并与软件包一起安装在标准位置的cmake文件夹下。 如果某个依赖项既不提供查找模块,也不提供供应商打包的CMake文件,该怎么办?在这种情况下,我们只有两个选择: @@ -12,7 +12,7 @@ * 依赖`pkg-config`程序,来找到系统上的包。这依赖于包供应商在`.pc`配置文件中,其中有关于发行包的元数据。 * 为依赖项编写自己的`find-package`模块。 -本示例中,将展示如何利用CMake中的`pkg-config`来定位ZeroMQ消息库。下一个示例中,将编写一个find模块,展示如何为ZeroMQ编写属于自己find模块。 +本示例中,将展示如何利用CMake中的`pkg-config`来定位ZeroMQ消息库。下一个示例中,将编写一个find模块,展示如何为ZeroMQ编写属于自己`find`模块。 ## 准备工作 @@ -20,9 +20,9 @@ ## 具体实施 -这是一个C项目,我们将使用C99标准。我们将逐步构建`CMakeLists.txt`文件: +这是一个C项目,我们将使用C99标准,逐步构建`CMakeLists.txt`文件: -1. 我们声明一个C项目,并要求符合C99标准: +1. 声明一个C项目,并要求符合C99标准: ```cmake cmake_minimum_required(VERSION 3.6 FATAL_ERROR) @@ -34,13 +34,13 @@ set(CMAKE_C_STANDARD_REQUIRED ON) ``` -2. 我们使用CMake附带的find-module,查找`pkg-config`。这里在`find_package`中传递了`QUIET`参数。只有在没有找到`pkg-config`时,CMake才会报错: +2. 使用CMake附带的find-module,查找`pkg-config`。这里在`find_package`中传递了`QUIET`参数。只有在没有找到`pkg-config`时,CMake才会报错: ```cmake find_package(PkgConfig REQUIRED QUIET) ``` -3. 找到`pkg-config`时,我们将使用`pkg_search_module`函数,以搜索任何附带包配置`.pc`文件的库或程序。在我们的例子中,我们查找ZeroMQ库: +3. 找到`pkg-config`时,我们将使用`pkg_search_module`函数,以搜索任何附带包配置`.pc`文件的库或程序。该示例中,我们查找ZeroMQ库: ```cmake pkg_search_module( @@ -95,7 +95,7 @@ ... ``` -## 如何工作 +## 工作 当找到`pkg-config`时, CMake需要提供两个函数,来封装这个程序提供的功能: