Skip to content

Commit

Permalink
update chapter 10
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaoweiChen committed Oct 19, 2019
1 parent 1d55f3d commit 05acd0b
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 80 deletions.
53 changes: 27 additions & 26 deletions content/chapter10/10.1-chinese.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@
.
├── CMakeLists.txt
├── src
├── CMakeLists.txt
├── hello-world.cpp
├── Message.cpp
└── Message.hpp
├── CMakeLists.txt
├── hello-world.cpp
├── Message.cpp
└── Message.hpp
└── tests
└── CMakeLists.txt
└── CMakeLists.txt
```

我们已经看到,有三个CMakeLists.txt,一个是主CMakeLists.txt,另一个是位于src目录下的,还有一个是位于test目录下的
我们已经看到,有三个`CMakeLists.txt`,一个是主`CMakeLists.txt`,另一个是位于`src`目录下的,还有一个是位于`test`目录下的

` Message.hpp`头文件包含以下内容:

Expand Down Expand Up @@ -100,7 +100,7 @@ int main()

## 具体实施

我们先来看一下主CMakeLists.txt:
我们先来看一下主`CMakeLists.txt`:

1. 声明CMake最低版本,并定义一个C++11项目。请注意,我们已经为我们的项目设置了一个版本,在`project`中使用`VERSION`进行指定:

Expand Down Expand Up @@ -172,7 +172,7 @@ int main()
endforeach()
```

7. 主CMakeLists.txt文件中的最后一个指令添加`src`子目录,启用测试,并添加`tests`子目录:
7. `CMakeLists.txt`文件中的最后一个指令添加`src`子目录,启用测试,并添加`tests`子目录:

```cmake
add_subdirectory(src)
Expand Down Expand Up @@ -304,7 +304,7 @@ int main()
)
```

`tests`目录中的CMakeLists.txt文件包含简单的指令,以确保“Hello, World”可执行文件能够正确运行:
`tests`目录中的`CMakeLists.txt`文件包含简单的指令,以确保“Hello, World”可执行文件能够正确运行:

```cmake
add_test(
Expand All @@ -327,15 +327,15 @@ GNU/Linux构建目录的内容如下:
```shell
build
├── bin
└── hello-world_wDSO
└── hello-world_wDSO
├── CMakeCache.txt
├── CMakeFiles
├── cmake_install.cmake
├── CTestTestfile.cmake
├── install_manifest.txt
├── lib64
├── libmessage.so -> libmessage.so.1
└── libmessage.so.1
├── libmessage.so -> libmessage.so.1
└── libmessage.so.1
├── Makefile
├── src
├── Testing
Expand All @@ -347,13 +347,13 @@ build
```shell
$HOME/Software/recipe-01/
├── bin
└── hello-world_wDSO
└── hello-world_wDSO
├── include
└── message
└── Message.hpp
└── message
└── Message.hpp
└── lib64
├── libmessage.so -> libmessage.so.1
└── libmessage.so.1
├── libmessage.so -> libmessage.so.1
└── libmessage.so.1
```

这意味着安装指令中给出的位置,是相对于用户给定的`CMAKE_INSTALL_PREFIX`路径。
Expand All @@ -370,11 +370,11 @@ $HOME/Software/recipe-01/

对于项目的安装来说,什么是好的布局呢?如果只有自己使用该项目,那就无所谓好或坏的布局。然而,一旦向外部发布产品,和他人共用该项目,就应该在安装项目时提供一个合理的布局。幸运的是,我们可以遵循一些标准,CMake可以帮助我们做到这一点。实际上,`GNUInstallDirs.cmake `模块所做的就是定义这样一组变量,这些变量是安装不同类型文件的子目录的名称。在例子中,使用了以下内容:

* CMAKE_INSTALL_BINDIR:这将用于定义用户可执行文件所在的子目录,即所选安装目录下的`bin`目录。
* CMAKE_INSTALL_LIBDIR:这将扩展到目标代码库(即静态库和动态库)所在的子目录。在64位系统上,它是`lib64`,而在32位系统上,它只是`lib`
* CMAKE_INSTALL_INCLUDEDIR:最后,我们使用这个变量为C头文件获取正确的子目录,该变量为`include`
* ***CMAKE_INSTALL_BINDIR**:这将用于定义用户可执行文件所在的子目录,即所选安装目录下的`bin`目录。
* **CMAKE_INSTALL_LIBDIR**:这将扩展到目标代码库(即静态库和动态库)所在的子目录。在64位系统上,它是`lib64`,而在32位系统上,它只是`lib`
* **CMAKE_INSTALL_INCLUDEDIR**:最后,我们使用这个变量为C头文件获取正确的子目录,该变量为`include`

然而,用户可能希望覆盖这些选项。我们允许在主CMakeLists.txt文件中使用以下方式覆盖选项:
然而,用户可能希望覆盖这些选项。我们允许在主`CMakeLists.txt`文件中使用以下方式覆盖选项:

```cmake
# Offer the user the choice
Expand All @@ -396,7 +396,7 @@ PATH "Installation directory for header files")
让我们更仔细地看看在动态库目标上设置的属性,需要设置以下内容:

* `POSITION_INDEPENDENT_CODE 1`:设置生成位置无关代码所需的编译器标志。有关更多信息,请参考https://en.wikipedia.org/wiki/position-independentent_code
* `SOVERSION ${PROJECT_VERSION_MAJOR}` : 这是动态库提供的应用程序编程接口(API)版本。在、设置语义版本之后,将其设置为与项目的主版本一致。CMake目标也有一个版本属性,可以用来指定目标的构建版本。注意,`SOVERSION``VERSION`有所不同:随着时间的推移,提供相同API的多个构建版本。本例中,我们不关心这种的粒度控制:仅使用`SOVERSION`属性设置API版本就足够了,CMake将为我们将`VERSION`设置为相同的值。相关详细信息,请参考官方文档:https://cmake.org/cmake/help/latest/prop_tgt/SOVERSION.html
* `SOVERSION ${PROJECT_VERSION_MAJOR}` : 这是动态库提供的应用程序编程接口(API)版本。在设置语义版本之后,将其设置为与项目的主版本一致。CMake目标也有一个版本属性,可以用来指定目标的构建版本。注意,`SOVERSION``VERSION`有所不同:随着时间的推移,提供相同API的多个构建版本。本例中,我们不关心这种的粒度控制:仅使用`SOVERSION`属性设置API版本就足够了,CMake将为我们将`VERSION`设置为相同的值。相关详细信息,请参考官方文档:https://cmake.org/cmake/help/latest/prop_tgt/SOVERSION.html
* `OUTPUT_NAME "message"`:这告诉CMake库的名称`message`,而不是目标` message-shared `的名称,` libmessage.so.1 `将在构建时生成。从前面给出的构建目录和安装目录的也可以看出,` libmessage.so`的符号链接也将生成。
* `DEBUG_POSTFIX "_d" `:这告诉CMake,如果我们以Debug配置构建项目,则将`_d`后缀添加到生成的动态库。
* `PUBLIC_HEADER "Message.hpp"`:我们使用这个属性来设置头文件列表(本例中只有一个头文件),声明提供的API函数。这主要用于macOS上的动态库目标,也可以用于其他操作系统和目标。有关详细信息,请参见官方文档:https://cmake.org/cmake/help/v3.6/prop_tgt/PUBLIC_HEADER.html
Expand Down Expand Up @@ -512,7 +512,8 @@ libmessage.so.1 => /home/roberto/Software/ch10r01/bin/../lib64/libmessage.so.1 (

我们使用了带有目标参数的CMake安装命令,因为我们需要安装构建目标。而该命令还有另外4个参数:

* `FILES``PROGRAMS`,分别用于安装文件或程序。安装后,并设置安装文件适当的权限。对于文件,对所有者具有读和写权限,对组以及其他用户和组具有读权限。对于程序,将授予执行权限。注意,`PROGRAMS`要与非构建目标的可执行程序一起使用。参见: https://cmake.org/cmake/help/v3.6/command/install.html#installing-files
* `DIRECTORY`,用于安装目录。当只给出一个目录名时,它通常被理解为相对于当前源目录。可以对目录的安装粒度进行控制。请参考在线文档: https://cmake.org/cmake/help/v3.6/command/install.html#installing-directories
* `SCRIPT`,可以使用它在CMake脚本中定义自定义安装规则。参见: https://cmake.org/cmake/help/v3.6/command/install.html#custom-installation-logic
* `EXPORT`,我们将此参数的讨论推迟到第3节,该参数用于导出目标。
* **FILES****PROGRAMS**,分别用于安装文件或程序。安装后,并设置安装文件适当的权限。对于文件,对所有者具有读和写权限,对组以及其他用户和组具有读权限。对于程序,将授予执行权限。注意,`PROGRAMS`要与非构建目标的可执行程序一起使用。参见: https://cmake.org/cmake/help/v3.6/command/install.html#installing-files
* **DIRECTORY**,用于安装目录。当只给出一个目录名时,它通常被理解为相对于当前源目录。可以对目录的安装粒度进行控制。请参考在线文档: https://cmake.org/cmake/help/v3.6/command/install.html#installing-directories
* **SCRIPT**,可以使用它在CMake脚本中定义自定义安装规则。参见: https://cmake.org/cmake/help/v3.6/command/install.html#custom-installation-logic
* **EXPORT**,我们将此参数的讨论推迟到第3节,该参数用于导出目标。

8 changes: 4 additions & 4 deletions content/chapter10/10.2-chinese.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ std::string getUUID();
## 具体实施
除了项目的名称外,主CMakeLists.txt文件没有改变。首先,看看`src`子目录中的CMakeLists.txt文件,所有工作实际上都在这里进行。我们将重点展示对之前示例的修改之处:
除了项目的名称外,主`CMakeLists.txt`文件没有改变。首先,看看`src`子目录中的`CMakeLists.txt`文件,所有工作实际上都在这里进行。我们将重点展示对之前示例的修改之处:
1. 为消息传递库声明`SHARED`库目标及其源。注意,编译定义和链接库没有改变:
Expand Down Expand Up @@ -139,7 +139,7 @@ std::string getUUID();
)
```

3. 我们还设置了` message-static `目标的属性。这些将在下一节讨论:
3. 还设置了` message-static `目标的属性:

```cmake
set_target_properties(message-static
Expand All @@ -152,7 +152,7 @@ std::string getUUID();
)
```

4. 除了链接到消息动态库目标的`hello-world_wDSO`可执行目标之外,我们还定义了另一个可执行目标`hello-world_wAR`,这个链接指向静态库:
4. 除了链接到消息动态库目标的`hello-world_wDSO`可执行目标之外,还定义了另一个可执行目标`hello-world_wAR`,这个链接指向静态库:

```cmake
add_executable(hello-world_wAR hello-world.cpp)
Expand Down Expand Up @@ -189,7 +189,7 @@ std::string getUUID();

## 工作原理

此示例演示了,如何设置动态库的符号可见性。最好的方式是在默认情况下隐藏所有符号,显式地只公开那些需要使用的符号。这需要分为两步实现。首先,需要指示编译器隐藏符号。当然,不同的编译器将有不同的可用选项,并且直接在CMakeLists.txt中设置这些选项并不是是跨平台的。CMake通过在动态库目标上设置两个属性,提供了一种健壮的跨平台方法来设置符号的可见性:
此示例演示了,如何设置动态库的符号可见性。最好的方式是在默认情况下隐藏所有符号,显式地只公开那些需要使用的符号。这需要分为两步实现。首先,需要指示编译器隐藏符号。当然,不同的编译器将有不同的可用选项,并且直接在`CMakeLists.txt`中设置这些选项并不是是跨平台的。CMake通过在动态库目标上设置两个属性,提供了一种健壮的跨平台方法来设置符号的可见性:

* `CXX_VISIBILITY_PRESET hidden`:这将隐藏所有符号,除非显式地标记了其他符号。当使用GNU编译器时,这将为目标添加`-fvisibility=hidden`标志。
* `VISIBILITY_INLINES_HIDDEN 1`:这将隐藏内联函数的符号。如果使用GNU编译器,这对应于` -fvisibility-inlines-hidden `
Expand Down
62 changes: 31 additions & 31 deletions content/chapter10/10.3-chinese.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,25 @@
```shell
.
├── cmake
└── messageConfig.cmake.in
└── messageConfig.cmake.in
├── CMakeLists.txt
├── src
├── CMakeLists.txt
├── hello- world.cpp
├── Message.cpp
└── Message.hpp
├── CMakeLists.txt
├── hello- world.cpp
├── Message.cpp
└── Message.hpp
└── tests
├── CMakeLists.txt
└── use_target
├── CMakeLists.txt
└── use_message.cpp
├── CMakeLists.txt
└── use_target
├── CMakeLists.txt
└── use_message.cpp
```

注意,cmake子目录中添加了一个`messageConfig.cmake.in`。这个文件将包含导出的目标,还添加了一个测试来检查项目的安装和导出是否按预期工作。

## 具体实施

同样,主CMakeLists.txt文件相对于前一个示例来说没有变化。移动到包含我们的源代码的子目录`src`中:
同样,`CMakeLists.txt`文件相对于前一个示例来说没有变化。移动到包含我们的源代码的子目录`src`中:

1. 需要找到UUID库,可以重用之前示例中的代码:

Expand Down Expand Up @@ -160,7 +160,7 @@
)
```

2. 自动生成的导出目标文件称为` messageTargets.cmake`,需要显式地指定它的安装规则。这个文件的目标是`INSTALL_CMAKEDIR`在主CMakeLists.txt文件中定义:
2. 自动生成的导出目标文件称为` messageTargets.cmake`,需要显式地指定它的安装规则。这个文件的目标是`INSTALL_CMAKEDIR`在主`CMakeLists.txt`文件中定义:

```cmake
install(
Expand Down Expand Up @@ -263,26 +263,26 @@ $ cmake --build . --target install
```shell
$HOME/Software/recipe-03/
├── bin
├── hello-world_wAR
└── hello-world_wDSO
├── hello-world_wAR
└── hello-world_wDSO
├── include
└── message
├── messageExport.h
└── Message.hpp
└── message
├── messageExport.h
└── Message.hpp
├── lib64
├── libmessage_s.a
├── libmessage.so -> libmessage.so.1
└── libmessage.so.1
├── libmessage_s.a
├── libmessage.so -> libmessage.so.1
└── libmessage.so.1
└── share
└── cmake
└── recipe-03
├── messageConfig.cmake
├── messageConfigVersion.cmake
├── messageTargets.cmake
└── messageTargets-release.cmake
└── cmake
└── recipe-03
├── messageConfig.cmake
├── messageConfigVersion.cmake
├── messageTargets.cmake
└── messageTargets-release.cmake
```

出现了一个`share`子目录,其中包含我们要求CMake自动生成的所有文件。现在开始,消息库的用户可以在他们自己的CMakeLists.txt文件中找到消息库,只要他们设置`message_DIR `的CMake变量,指向安装树中的`share/cmake/message`目录:
出现了一个`share`子目录,其中包含我们要求CMake自动生成的所有文件。现在开始,消息库的用户可以在他们自己的`CMakeLists.txt`文件中找到消息库,只要他们设置`message_DIR `的CMake变量,指向安装树中的`share/cmake/message`目录:

```cmake
find_package(message 1 CONFIG REQUIRED)
Expand All @@ -301,7 +301,7 @@ find_package(message 1 CONFIG REQUIRED)

2. 描述目标的安装规则,包括生成文件的名称。

3. 描述CMake生成的导出文件的安装规则`messageTargets.cmake`文件将安装到`INSTALL_CMAKEDIR`。目标导出文件的安装规则的名称空间选项,将把给定字符串前置到目标的名称中,这有助于避免来自不同项目的目标之间的名称冲突。`INSTALL_CMAKEDIR`变量是在主CMakeLists.txt文件中设置的:
3. 描述CMake生成的导出文件的安装规则`messageTargets.cmake`文件将安装到`INSTALL_CMAKEDIR`。目标导出文件的安装规则的名称空间选项,将把给定字符串前置到目标的名称中,这有助于避免来自不同项目的目标之间的名称冲突。`INSTALL_CMAKEDIR`变量是在主`CMakeLists.txt`文件中设置的:

```cmake
if(WIN32 AND NOT CYGWIN)
Expand All @@ -312,15 +312,15 @@ find_package(message 1 CONFIG REQUIRED)
set(INSTALL_CMAKEDIR ${DEF_INSTALL_CMAKEDIR} CACHE PATH "Installation directory for CMake files")
```

CMakeLists.txt的最后一部分生成配置文件。包括` CMakePackageConfigHelpers.cmake`模块,分三步完成:
`CMakeLists.txt`的最后一部分生成配置文件。包括` CMakePackageConfigHelpers.cmake`模块,分三步完成:

1. 调用`write_basic_package_version_file`函数生成一个版本文件包。宏的第一个参数是版本控制文件的路径:` messageConfigVersion.cmake`。版本格式为`Major.Minor.Patch`,并使用`PROJECT_VERSION`指定版本,还可以指定与库的新版本的兼容性。例子中,当库具有相同的主版本时,为了保证兼容性,使用了相同的`SameMajorVersion`参数。
2. 接下来,配置模板文件`messageConfig.cmake.in `,该文件位于`cmake`子目录中。
3. 最后,为新生成的文件设置安装规则。两者都将安装在`INSTALL_CMAKEDIR`下。

## 更多信息

消息库的客户现在非常高兴,因为终于可以在自己的系统上安装这个库,对自己的CMakeLists.txt进行简单的修改,就能找到消息库:
消息库的客户现在非常高兴,因为终于可以在自己的系统上安装这个库,对自己的`CMakeLists.txt`进行简单的修改,就能找到消息库:

```cmake
find_package(message VERSION 1 REQUIRED)
Expand All @@ -338,8 +338,8 @@ $ cmake -Dmessage_DIR=/path/to/message/share/cmake/message ..
tests/
├── CMakeLists.txt
└── use_target
├── CMakeLists.txt
└── use_message.cpp
├── CMakeLists.txt
└── use_message.cpp
```

这个目录包含一个使用导出目标的小项目。有趣的部分是在CMakeLists.txt文件中指定的测试:
Expand Down
Loading

0 comments on commit 05acd0b

Please sign in to comment.