Skip to content

Commit

Permalink
update chapter 3
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaoweiChen committed Oct 3, 2019
1 parent 39f9069 commit 7d5cc0c
Show file tree
Hide file tree
Showing 12 changed files with 124 additions and 116 deletions.
2 changes: 1 addition & 1 deletion SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
16 changes: 8 additions & 8 deletions content/chapter3/3.0-chinese.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# 第3章 检测外部库和程序

本章中,我们将介绍以下示例:
本章中主要内容有:

* 检测Python解释器
* 检测Python库
Expand All @@ -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内置命令的打印文档*

33 changes: 18 additions & 15 deletions content/chapter3/3.1-chinese.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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!
Expand All @@ -57,16 +60,16 @@ Python是一种非常流行的动态语言。许多项目用Python编写的工

## 工作原理

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

除了在系统上实际查找包模块之外,查找模块还会设置了一些有用的变量,反映实际找到了什么,您可以在自己的`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)`

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

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

Expand All @@ -99,7 +102,7 @@ message(STATUS "RESULT_VARIABLE is: ${_status}")
message(STATUS "OUTPUT_VARIABLE is: ${_hello_world}")
```

一种便捷的调试方法是使用以下工具:
使用以下工具进行调试:

```cmake
include(CMakePrintHelpers)
Expand Down
34 changes: 17 additions & 17 deletions content/chapter3/3.10-chinese.md
Original file line number Diff line number Diff line change
@@ -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操作系统上检测该库。我们重用服务器-客户端示例代码。

## 如何实施

Expand All @@ -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)
Expand Down Expand Up @@ -62,15 +62,15 @@

此示例的主`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)
set(ZeroMQ_ROOT "$ENV{ZeroMQ_ROOT}")
endif()
```

2. 然后,搜索系统上`zmq.h`头文件的位置。这是基于`_ZeroMQ_ROOT`变量和`find_path` CMake命令进行的:
2. 然后,搜索系统上`zmq.h`头文件的位置。这是基于`_ZeroMQ_ROOT`变量和`find_path`命令进行的:

```cmake
if(NOT ZeroMQ_ROOT)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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")
Expand Down Expand Up @@ -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. 检查用户是否为所需的包提供了自定义位置。

Expand All @@ -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`的手册页面。*

## 更多信息

Expand All @@ -181,18 +181,18 @@ find-module通常遵循特定的模式:
1. 使用由包供应商提供CMake文件` <package>Config.cmake``<package>ConfigVersion.cmake``<package>Targets.cmake`,通常会在包的标准安装位置查找。
2. 无论是由CMake还是第三方提供的模块,为所需包使用`find-module`
3. 使用`pkg-config`,如本节的示例所示。
4. 如果这些都不可行,那么编写自己的find模块
4. 如果这些都不可行,那么编写自己的`find`模块

这四种可选方案按相关性进行了排序,每种方法也都有其挑战。

目前,并不是所有的包供应商都提供CMake的Find文件,不过正变得越来越普遍。因为导出CMake目标,使得第三方代码很容易使用它所依赖的库和/或程序附加的依赖。

从一开始,`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查找文件。
Loading

0 comments on commit 7d5cc0c

Please sign in to comment.