面向 C++ 的现代 CMake 教程(五)(4)

简介: 面向 C++ 的现代 CMake 教程(五)

面向 C++ 的现代 CMake 教程(五)(3)https://developer.aliyun.com/article/1526953

库的安装

要安装库,最好先配置逻辑目标并指定其工件的安装位置。为了避免手动提供路径,我们将使用GNUInstallDirs模块提供的默认值。为了模块化,我们将把工件分组到组件中。默认安装将安装所有文件,但你可以选择只安装runtime组件并跳过development工件:

chapter-12/01-full-project/cmake/Install.cmake(片段)

include(GNUInstallDirs)
# Calc library
install(TARGETS calc_obj calc_shared calc_static
  EXPORT CalcLibrary
  ARCHIVE COMPONENT development
  LIBRARY COMPONENT runtime 
  PUBLIC_HEADER DESTINATION
    ${CMAKE_INSTALL_INCLUDEDIR}/calc
      COMPONENT runtime
)

在安装过程中,我们想用ldconfig注册我们复制的共享库:

chapter-12/01-full-project/cmake/Install.cmake(继续)

if (UNIX)
  install(CODE "execute_process(COMMAND ldconfig)"
    COMPONENT runtime
  )
endif()

有了这些步骤的准备,我们可以通过将其封装在可重用的 CMake 包中来使库对其他 CMake 项目可见。我们需要生成并安装目标导出文件和包括它的配置文件:

chapter-12/01-full-project/cmake/Install.cmake(继续)

install(EXPORT CalcLibrary
  DESTINATION ${CMAKE_INSTALL_LIBDIR}/calc/cmake
  NAMESPACE Calc::
  COMPONENT runtime
)
install(FILES "CalcConfig.cmake"
  DESTINATION ${CMAKE_INSTALL_LIBDIR}/calc/cmake
)

正如我们所知,对于非常简单的包,配置文件可以非常简洁:

chapter-12/01-full-project/CalcConfig.cmake

include("${CMAKE_CURRENT_LIST_DIR}/CalcLibrary.cmake")

就这样。现在,在构建解决方案后运行cmake--install模式,库将被安装。剩下的要安装的只有可执行文件。

可执行文件的安装

所有二进制可执行文件的安装是最简单的一步。我们只需要使用一个命令:

chapter-12/01-full-project/cmake/Install.cmake(继续)

# CalcConsole runtime
install(TARGETS calc_console
  RUNTIME COMPONENT runtime
)

完成啦!让我们继续进行配置的最后部分——打包。

使用 CPack 打包

我们可以放手去配置一大堆受支持的包类型;对于这个项目,然而,基本的配置就足够了:

chapter-12/01-full-project/cmake/Install.cmake(继续)

# CPack configuration
set(CPACK_PACKAGE_VENDOR "Rafal Swidzinski")
set(CPACK_PACKAGE_CONTACT "email@example.com")
set(CPACK_PACKAGE_DESCRIPTION "Simple Calculator")
include(CPack)

如此简洁的设置对于标准归档文件,如 ZIP 文件,效果很好。我们可以用一个命令(项目必须先构建)来测试整个安装和打包:

# cpack -G TGZ -B packages
CPack: Create package using TGZ
CPack: Install projects
CPack: - Run preinstall target for: Calc
CPack: - Install project: Calc []
CPack: Create package
CPack: - package: /tmp/b/packages/Calc-1.0.0-Linux.tar.gz generated. 

安装和打包就此结束;接下来要处理的事务是文档。

提供文档

当然,一个专业项目的最后一个元素是文档。它分为两个类别:

  • 技术文档(接口、设计、类和文件)
  • 一般文档(其他不如此技术性的文档)

正如我们在第十章中看到的,生成文档,很多技术文档可以通过使用 Doxygen 在 CMake 中自动生成。

自动文档生成

需要提及的是:一些项目在构建阶段生成文档,并将其与其他项目内容一起打包。这是个人喜好问题。对于这个项目,我们决定不这样做。你可能有选择其他方式的好理由(例如,在网上托管文档)。

图 12.7 展示了在此过程中使用的执行流程概述:

图 12.7 – 用于生成文档的文件

为了生成我们目标的用户文档,我们将创建另一个 CMake 工具模块Doxygen。我们将从使用 Doxygen 查找模块和下载doxygen-awesome-css项目主题开始:

chapter-12/01-full-project/cmake/Doxygen.cmake(片段)

find_package(Doxygen REQUIRED)
include(FetchContent)
FetchContent_Declare(doxygen-awesome-css
  GIT_REPOSITORY
    https://github.com/jothepro/doxygen-awesome-css.git
  GIT_TAG
    v1.6.0
)
FetchContent_MakeAvailable(doxygen-awesome-css)

然后,我们需要一个函数来创建生成文档的目标。我们将从第十章《生成文档》中介绍的代码中汲取灵感,并对其进行修改以支持许多目标:

chapter-12/01-full-project/cmake/Doxygen.cmake(继续)

function(Doxygen target input)
  set(NAME "doxygen-${target}")
  set(DOXYGEN_HTML_OUTPUT
    ${PROJECT_BINARY_DIR}/${NAME})
  set(DOXYGEN_GENERATE_HTML         YES)
  set(DOXYGEN_GENERATE_TREEVIEW     YES)
  set(DOXYGEN_HAVE_DOT              YES)
  set(DOXYGEN_DOT_IMAGE_FORMAT      svg)
  set(DOXYGEN_DOT_TRANSPARENT       YES)
  set(DOXYGEN_HTML_EXTRA_STYLESHEET
      ${doxygen-awesome-css_SOURCE_DIR}/doxygen-
        awesome.css)
  doxygen_add_docs(${NAME}
    ${PROJECT_SOURCE_DIR}/${input}
      COMMENT "Generate HTML documentation"
  )
endfunction()

现在,我们需要通过为库目标调用它来使用这个函数:

chapter-12/01-full-project/src/calc/CMakeLists.txt(继续)

# ... calc_static target definition
# ... testing and program analysis modules
include(Doxygen)
Doxygen(calc src/calc)

然后我们为控制台可执行文件调用它:

chapter-12/01-full-project/src/calc_console/CMakeLists.txt(继续)

# ... calc_static target definition
# ... testing and program analysis modules
include(Doxygen)
Doxygen(calc_console src/calc_console)
add_executable(calc_console bootstrap.cpp)
target_link_libraries(calc_console calc_console_static)

在项目中添加了两个新目标:doxygen-calcdoxygen-calc_console,可以按需生成技术文档。

我们还应该提供其他文档吗?

非技术性专业文档

专业项目应该总是至少包括两个存储在顶级目录中的文件:

  • README – 通常描述项目
  • LICENSE – 指定项目的法律特性

您可能还想添加这些:

  • INSTALL – 描述安装所需的步骤
  • CHANGELOG – 列出不同版本中发生的重要变化
  • AUTHORS – 如果项目有多个贡献者,则包含信用和联系信息
  • BUGS – 告知已知错误,并指导如何报告新错误

至于 CMake,当涉及到这些文件时并不会发挥任何作用——没有自动化行为或脚本可以使用。然而,这些文件是 C++项目的重要组成部分,应该为完整性而覆盖。作为参考,我们将提供一套最小化的示例文件,从一个简短的README文件开始:

chapter-12/01-full-project/README.md

# Calc Console
Calc Console is a calculator that adds two numbers in a
terminal. It does all the math by using a **Calc** library.
This library is also available in this package.
This application is written in C++ and built with CMake.
## More information
- Installation instructions are in the INSTALL file
- License is in the LICENSE file

这个文件简短而可能有点傻。注意.md扩展名——它代表Markdown,这是一种易于阅读的基于文本的格式化语言。像 GitHub 这样的网站和许多文本编辑器都会以丰富的格式显示这些文件。

我们的INSTALL文件将如下所示:

chapter-12/01-full-project/INSTALL

To install this software you'll need to provide the following:
- C++ compiler supporting C++17
- CMake >= 3.20
- GIT
- Doxygen + Graphviz
- CPPCheck
- Valgrind
This project also depends on GTest, GMock and FXTUI. This
software is automatically pulled from external repositories
during the installation.
To configure the project type:
cmake -B <temporary-directory>
Then you can build the project:
cmake --build <temporary-directory>
And finally install it:
cmake --install <temporary-directory>
To generate the documentation run:
cmake --build <temporary-directory> -t doxygen-calc
cmake --build <temporary-directory> -t doxygen-calc_console

这个文件最后变得有点长,但它涵盖了最重要的要求、步骤和命令,它将完全符合我们的需求。

LICENSE文件有点棘手,因为它需要一些版权法的专业知识(否则)。与其自己写所有的条款,我们可以像许多其他项目一样,使用现成的软件许可证。对于这个项目,我们将选择 MIT 许可证,这是一个非常宽松的许可证。根据特定项目的需求,您可能想要选择其他的东西——在进一步阅读部分查看一些有用的参考资料:

chapter-12/01-full-project/LICENSE

Copyright 2022 Rafal Swidzinski
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

最后,我们有CHANGELOG。正如之前所建议的,保留一个文件来跟踪变更是个好主意,这样使用你项目的开发者可以轻松地找到哪个版本支持他们需要的特性。例如,说库在 0.8.2 版本中增加了乘法功能可能是有用的。如下所示的简单内容已经很有帮助了:

chapter-12/01-full-project/CHANGELOG

1.0.0 Public version with installer
0.8.2 Multiplication added to the Calc Library
0.5.1 Introducing the Calc Console application
0.2.0 Basic Calc library with Sum function

我们的专业项目现在已经完成——我们可以构建它,测试它,生成包,将所有源代码上传到仓库,并发布工件。当然,如果这一切可以自动发生,也许通过 CI/CD 管道,那就更容易了。但那是另一本书的故事。

概要

这一章结束了我们通过 CMake 的漫长旅程。现在你完全理解了 CMake 旨在解决的问题以及实现这些解决方案所需的步骤。

在前三章中,我们探索了所有基础知识:什么是 CMake 以及用户如何利用它将源代码从原始状态变为可运行状态,CMake 的关键组件是什么,不同项目文件有什么目的。我们解释了 CMake 的语法:注释,命令调用,参数,变量和控制结构。我们发现了模块和子项目是如何工作的,正确的项目结构是什么,以及如何与各种平台和工具链一起工作。

本书的第二部分教导我们如何使用 CMake 进行构建:如何使用目标,自定义命令,构建类型和生成器表达式。我们深入探讨了编译的技术细节,以及预处理器和优化器的配置。我们讨论了链接,并介绍了不同的库类型。然后,我们研究了 CMake 如何使用FetchContentExternalProject模块来管理项目的依赖关系。我们还研究了 Git 子模块作为可能的替代方案。最重要的是,我们学习了如何使用find_package()FindPkgConfig查找已安装的包。如果这些还不够,我们探讨了编写自己的查找模块。

最后一部分告诉我们如何进行测试,分析,文档,安装和打包的自动化。我们研究了 CTest 和测试框架:Catch2,GoogleTest 和 GoogleMock。覆盖率报告也得到了涵盖。第九章,程序分析工具,让我们了解了不同的分析工具:格式化器和静态检查器(Clang-Tidy,Cppcheck 等),并解释了如何添加 Valgrind 套件中的 Memcheck 内存分析器。接下来,我们简要介绍了如何使用 Doxygen 生成文档以及如何使其更具吸引力。最后,我们展示了如何将项目安装到系统上,创建可重用的 CMake 包,以及如何配置和使用 CPack 生成二进制包。

最后一章利用了所有的知识来展示一个完全专业的项目。

恭喜你完成这本书。我们已经涵盖了开发、测试和打包高质量 C ++软件所需的一切内容。从这里开始取得进步的最佳方式是将你所学的内容付诸实践,为你的用户创建伟大的软件。祝你好运!

R.

进一步阅读

更多信息,您可以参考以下链接:

附录:杂项命令

每种语言都有许多实用的命令,CMake 在这方面也不例外:它提供了进行简单算术、位运算、字符串处理、列表和文件操作的工具。有趣的是,它们必要性相对较少(感谢过去几年中所有的改进和编写模块),但在更自动化的项目中仍然可能需要。

因此,本附录是对各种命令及其多种模式的一个简要总结。将其视为一个方便的离线参考或官方文档的简化版。如果您需要更多信息,请访问提供的链接。

在本章中,我们将涵盖以下主要主题:

  • string()命令
  • list()命令
  • file()命令
  • math()命令

字符串()命令

string()命令用于操作字符串。它有多种模式,可以执行字符串的不同操作:搜索和替换、 manipulation、比较、散列、生成和 JSON 操作(从 CMake 3.19 开始提供后一种)。

完整细节请在线查阅文档:cmake.org/cmake/help/latest/command/string.html

接受参数的string()模式将接受多个值,并在命令执行前将它们连接起来:

string(PREPEND myVariable "a" "b" "c")

这相当于以下内容:

string(PREPEND myVariable "abc")

让我们探索所有可用的string()模式。

面向 C++ 的现代 CMake 教程(五)(5)https://developer.aliyun.com/article/1526955

相关文章
|
6天前
|
C++
Clion CMake C/C++程序输出乱码
Clion CMake C/C++程序输出乱码
9 0
|
8天前
|
存储 算法 编译器
C++ 函数式编程教程
C++ 函数式编程学习
|
8天前
|
存储 编译器 开发工具
C++语言教程分享
C++语言教程分享
|
8天前
|
存储 编译器 C++
|
29天前
|
C++ 存储 索引
面向 C++ 的现代 CMake 教程(一)(5)
面向 C++ 的现代 CMake 教程(一)
46 0
|
29天前
|
缓存 存储 C++
面向 C++ 的现代 CMake 教程(一)(4)
面向 C++ 的现代 CMake 教程(一)
45 0
|
29天前
|
C++ 缓存 存储
面向 C++ 的现代 CMake 教程(一)(3)
面向 C++ 的现代 CMake 教程(一)
43 0
|
29天前
|
缓存 C++ Windows
面向 C++ 的现代 CMake 教程(一)(2)
面向 C++ 的现代 CMake 教程(一)
57 0
|
29天前
|
C++ 容器 Docker
面向 C++ 的现代 CMake 教程(一)(1)
面向 C++ 的现代 CMake 教程(一)
67 0
|
Java 编译器 Linux
【CMake】CMake 引入 ( Android Studio 创建 Native C++ 工程 | C/C++ 源码编译过程 | Makefile 工具 | CMake 引入 )(二)
【CMake】CMake 引入 ( Android Studio 创建 Native C++ 工程 | C/C++ 源码编译过程 | Makefile 工具 | CMake 引入 )(二)
280 0
【CMake】CMake 引入 ( Android Studio 创建 Native C++ 工程 | C/C++ 源码编译过程 | Makefile 工具 | CMake 引入 )(二)