CMake 秘籍(七)(2)

简介: CMake 秘籍(七)

CMake 秘籍(七)(1)https://developer.aliyun.com/article/1525421

准备就绪

本食谱的源代码树与前两个食谱类似:

.
├── cmake
│   ├── FindPythonModule.cmake
│   ├── FindSphinx.cmake
│   └── UseBreathe.cmake
├── CMakeLists.txt
├── docs
│   ├── code-reference
│   │   ├── classes-and-functions.rst
│   │   └── message.rst
│   ├── conf.py.in
│   ├── Doxyfile.in
│   └── index.rst
└── src
    ├── CMakeLists.txt
    ├── hello-world.cpp
    ├── Message.cpp
    └── Message.hpp

现在,docs子目录中包含了Doxyfile.inconf.py.in模板文件,分别用于 Doxygen 和 Sphinx 的设置。此外,我们还有一个code-reference子目录。

紧随code-reference的文件包含 Breathe 指令,以在 Sphinx 中包含 Doxygen 生成的文档:

Messaging classes
=================
Message
-------
.. doxygenclass:: Message
   :project: recipe-03
   :members:
   :protected-members:
   :private-members:

这将输出Message类的文档。

如何操作

src目录中的CMakeLists.txt文件未更改。根目录中的CMakeLists.txt文件的唯一更改如下:

  1. 我们包含UseBreathe.cmake自定义模块:
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
include(UseBreathe)
  1. 我们调用了add_breathe_doc函数。该函数在自定义模块中定义,并接受关键字参数来设置结合 Doxygen 和 Sphinx 的构建:
add_breathe_doc(
  SOURCE_DIR
    ${CMAKE_CURRENT_SOURCE_DIR}/docs
  BUILD_DIR
    ${CMAKE_CURRENT_BINARY_DIR}/_build
  CACHE_DIR
    ${CMAKE_CURRENT_BINARY_DIR}/_doctrees
  HTML_DIR
    ${CMAKE_CURRENT_BINARY_DIR}/html
  DOXY_FILE
    ${CMAKE_CURRENT_SOURCE_DIR}/docs/Doxyfile.in
  CONF_FILE
    ${CMAKE_CURRENT_SOURCE_DIR}/docs/conf.py.in
  TARGET_NAME
    docs
  COMMENT
    "HTML documentation"
  )

让我们检查UseBreatheDoc.cmake模块。这遵循了我们之前两个配方中描述的明确优于隐式的相同模式。该模块详细描述如下:

  1. 文档生成依赖于 Doxygen:
find_package(Doxygen REQUIRED)
find_package(Perl REQUIRED)
  1. 我们还依赖于 Python 解释器和Sphinx
find_package(PythonInterp REQUIRED)
find_package(Sphinx REQUIRED)
  1. 此外,我们还必须找到breathe Python 模块。我们使用FindPythonModule.cmake模块:
include(FindPythonModule)
find_python_module(breathe REQUIRED)
  1. 我们定义了add_breathe_doc函数。该函数有一个单值关键字参数,我们将使用cmake_parse_arguments命令对其进行解析:
function(add_breathe_doc)
  set(options)
  set(oneValueArgs
    SOURCE_DIR
    BUILD_DIR
    CACHE_DIR
    HTML_DIR
    DOXY_FILE
    CONF_FILE
    TARGET_NAME
    COMMENT
    )
  set(multiValueArgs)
  cmake_parse_arguments(BREATHE_DOC
    "${options}"
    "${oneValueArgs}"
    "${multiValueArgs}"
    ${ARGN}
    )
  # ...
endfunction()
  1. BREATHE_DOC_CONF_FILE模板文件用于 Sphinx,配置为conf.pyBREATHE_DOC_BUILD_DIR中:
configure_file(
  ${BREATHE_DOC_CONF_FILE}
  ${BREATHE_DOC_BUILD_DIR}/conf.py
  @ONLY
  )
  1. 相应地,Doxygen 的BREATHE_DOC_DOXY_FILE模板文件配置为DoxyfileBREATHE_DOC_BUILD_DIR中:
configure_file(
  ${BREATHE_DOC_DOXY_FILE}
  ${BREATHE_DOC_BUILD_DIR}/Doxyfile
  @ONLY
  )
  1. 然后我们添加了自定义目标BREATHE_DOC_TARGET_NAME。请注意,只运行了 Sphinx;对 Doxygen 的必要调用在BREATHE_DOC_SPHINX_FILE内部发生:
add_custom_target(${BREATHE_DOC_TARGET_NAME}
  COMMAND
    ${SPHINX_EXECUTABLE}
       -q
       -b html
       -c ${BREATHE_DOC_BUILD_DIR}
       -d ${BREATHE_DOC_CACHE_DIR}
       ${BREATHE_DOC_SOURCE_DIR}
       ${BREATHE_DOC_HTML_DIR}
  COMMENT
    "Building ${BREATHE_DOC_TARGET_NAME} documentation with Breathe, Sphinx and Doxygen"
  VERBATIM
  )
  1. 最后,向用户打印一条状态消息:
message(STATUS "Added ${BREATHE_DOC_TARGET_NAME} [Breathe+Sphinx+Doxygen] target to build documentation")
  1. 配置完成后,我们可以像往常一样构建文档:
$ mkdir -p build
$ cd build
$ cmake ..
$ cmake --build . --target docs

文档将可在构建树的BREATHE_DOC_HTML_DIR子目录中找到。启动浏览器打开index.html文件后,您可以导航到Message类的文档:

工作原理

您会注意到,尽管在声明自定义BREATHE_DOC_TARGET_NAME目标时只给出了对 Sphinx 的调用,但 Doxygen 和 Sphinx 都运行了。这是由于 Sphinx 的conf.py文件中定义的以下设置:

def run_doxygen(folder):
    """Run the doxygen make command in the designated folder"""
    try:
        retcode = subprocess.call("cd {}; doxygen".format(folder), shell=True)
        if retcode < 0:
            sys.stderr.write(
                "doxygen terminated by signal {}".format(-retcode))
    except OSError as e:
        sys.stderr.write("doxygen execution failed: {}".format(e))
def setup(app):
    run_doxygen('@BREATHE_DOC_BUILD_DIR@')

Doxygen 将生成 XML 输出,Breathe 插件将能够以与所选 Sphinx 文档样式一致的形式呈现这些输出。

第十四章:替代生成器和跨编译

在本章中,我们将介绍以下内容:

  • 在 Visual Studio 中构建 CMake 项目
  • 跨编译一个 hello world 示例
  • 使用 OpenMP 并行化跨编译 Windows 二进制文件

引言

CMake 本身并不构建可执行文件和库。相反,CMake 配置一个项目并生成由另一个构建工具或框架用来构建项目的文件。在 GNU/Linux 和 macOS 上,CMake 通常生成 Unix Makefiles,但存在许多替代方案。在 Windows 上,这些通常是 Visual Studio 项目文件或 MinGW 或 MSYS Makefiles。CMake 包含了一系列针对本地命令行构建工具或集成开发环境(IDEs)的生成器。您可以在以下链接了解更多信息:cmake.org/cmake/help/latest/manual/cmake-generators.7.html

这些生成器可以使用cmake -G来选择,例如:

$ cmake -G "Visual Studio 15 2017"

并非所有生成器在每个平台上都可用,根据 CMake 运行的平台,通常只有一部分可用。要查看当前平台上所有可用的生成器列表,请输入以下内容:

$ cmake -G

在本章中,我们不会遍历所有可用的生成器,但我们注意到本书中的大多数配方都使用Unix MakefilesMSYS MakefilesNinjaVisual Studio 15 2017生成器进行了测试。在本章中,我们将专注于在 Windows 平台上进行开发。我们将演示如何直接使用 Visual Studio 15 2017 构建 CMake 项目,而不使用命令行。我们还将讨论如何在 Linux 或 macOS 系统上跨编译 Windows 可执行文件。

使用 Visual Studio 2017 构建 CMake 项目

本配方的代码可在github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-13/recipe-01找到,并包含一个 C++示例。该配方适用于 CMake 版本 3.5(及以上),并在 Windows 上进行了测试。

虽然早期的 Visual Studio 版本要求开发者在不同的窗口中编辑源代码和运行 CMake 命令,但 Visual Studio 2017 引入了对 CMake 项目的内置支持(aka.ms/cmake),允许整个编码、配置、构建和测试工作流程在同一个 IDE 中发生。在本节中,我们将测试这一点,并直接使用 Visual Studio 2017 构建一个简单的“hello world”CMake 示例项目,而不求助于命令行。

准备工作

首先,我们将使用 Windows 平台,下载并安装 Visual Studio Community 2017(www.visualstudio.com/downloads/)。在撰写本文时,该版本可免费使用 30 天试用期。我们将遵循的步骤也在此视频中得到了很好的解释:www.youtube.com/watch?v=_lKxJjV8r3Y

在运行安装程序时,请确保在左侧面板中选择“使用 C++的桌面开发”,并验证“Visual C++工具用于 CMake”在右侧的摘要面板中被选中:

在 Visual Studio 2017 15.4 中,您还可以为 Linux 平台编译代码。为此,请在其他工具集中选择“Linux 开发与 C++”:

启用此选项后,您可以从 Visual Studio 内部为 Windows 和 Linux 机器编译代码,前提是您已配置了对 Linux 服务器的访问。但是,我们不会在本章中演示这种方法。

在本节中,我们将在 Windows 上构建 Windows 二进制文件,我们的目标是配置和构建以下示例代码(hello-world.cpp):

#include <cstdlib>
#include <iostream>
#include <string>
const std::string cmake_system_name = SYSTEM_NAME;
int main() {
  std::cout << "Hello from " << cmake_system_name << std::endl;
  return EXIT_SUCCESS;
}

操作方法

要创建相应的源代码,请按照以下步骤操作:

  1. 创建一个目录并将hello-world.cpp文件放入新创建的目录中。
  2. 在此目录中,创建一个CMakeLists.txt文件,其中包含以下内容:
# set minimum cmake version
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
# project name and language
project(recipe-01 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
include(GNUInstallDirs)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY
  ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY
  ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY
  ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR})
# define executable and its source file
add_executable(hello-world hello-world.cpp)
# we will print the system name in the code
target_compile_definitions(hello-world
  PUBLIC
    "SYSTEM_NAME=\"${CMAKE_SYSTEM_NAME}\""
  )
install(
  TARGETS
    hello-world
  DESTINATION
    ${CMAKE_INSTALL_BINDIR}
  )
  1. 打开 Visual Studio 2017,然后导航到包含源文件和CMakeLists.txt的新建文件夹,通过以下方式:文件 | 打开 | 文件夹。
  2. 一旦文件夹打开,请注意 CMake 配置步骤是如何自动运行的(底部面板):

  1. 现在,我们可以右键单击CMakeLists.txt(右侧面板)并选择“构建”:

  1. 这构建了项目(请参见底部面板的输出):

  1. 这样就成功编译了可执行文件。在下一个子节中,我们将学习如何定位可执行文件,并可能更改构建和安装路径。

工作原理

我们已经看到,Visual Studio 2017 很好地与 CMake 接口,并且我们已经能够从 IDE 内部配置和构建代码。除了构建步骤,我们还可以运行安装或测试步骤。这些可以通过右键单击CMakeLists.txt(右侧面板)来访问。

然而,配置步骤是自动运行的,我们可能更倾向于修改配置选项。我们还希望知道实际的构建和安装路径,以便我们可以测试我们的可执行文件。为此,我们可以选择 CMake | 更改 CMake 设置,然后我们到达以下屏幕:

在左上角的面板中,我们现在可以检查和修改生成器(在本例中为 Ninja)、设置、参数以及路径。构建路径在上面的截图中突出显示。设置被分组到构建类型(x86-Debugx86-Release等)中,我们可以在顶部面板栏的中间在这些构建类型之间切换。

现在我们知道实际的构建路径,我们可以测试编译的可执行文件:

$ ./hello-world.exe
Hello from Windows

当然,构建和安装路径可以进行调整。

另请参阅

交叉编译一个“Hello World”示例

本配方的代码可在github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-13/recipe-01找到,并包含一个 C++示例。本配方适用于 CMake 版本 3.5(及以上),并在 GNU/Linux 和 macOS 上进行了测试。

在本配方中,我们将重用上一个配方中的“Hello World”示例,并从 Linux 或 macOS 交叉编译到 Windows。换句话说,我们将在 Linux 或 macOS 上配置和编译代码,并获得一个 Windows 平台的可执行文件。

准备工作

我们从一个简单的“Hello World”示例开始(hello-world.cpp):

#include <cstdlib>
#include <iostream>
#include <string>
const std::string cmake_system_name = SYSTEM_NAME;
int main() {
  std::cout << "Hello from " << cmake_system_name << std::endl;
  return EXIT_SUCCESS;
}

我们还将使用上一个配方中未更改的CMakeLists.txt

# set minimum cmake version
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
# project name and language
project(recipe-01 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
include(GNUInstallDirs)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY
  ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY
  ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY
  ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR})
# define executable and its source file
add_executable(hello-world hello-world.cpp)
# we will print the system name in the code
target_compile_definitions(hello-world
  PUBLIC
    "SYSTEM_NAME=\"${CMAKE_SYSTEM_NAME}\""
  )
install(
  TARGETS
    hello-world
  DESTINATION
    ${CMAKE_INSTALL_BINDIR}
  )

为了交叉编译源代码,我们需要安装一个 C++的交叉编译器,以及可选的 C 和 Fortran 编译器。一个选项是使用打包的 MinGW 编译器。作为打包的交叉编译器的替代方案,我们还可以使用 MXE(M 交叉环境)从源代码构建一套交叉编译器:mxe.cc

CMake 秘籍(七)(3)https://developer.aliyun.com/article/1525426

相关文章
|
5月前
|
编译器 Shell 开发工具
CMake 秘籍(八)(5)
CMake 秘籍(八)
32 2
|
5月前
|
编译器 Shell
CMake 秘籍(八)(3)
CMake 秘籍(八)
33 2
|
5月前
|
编译器 Linux C语言
CMake 秘籍(二)(2)
CMake 秘籍(二)
45 2
|
5月前
|
消息中间件 Unix C语言
CMake 秘籍(二)(5)
CMake 秘籍(二)
79 1
|
5月前
|
编译器 开发工具 git
CMake 秘籍(八)(1)
CMake 秘籍(八)
23 1
|
5月前
|
编译器 Linux 开发工具
CMake 秘籍(四)(2)
CMake 秘籍(四)
20 0
|
5月前
|
编译器 Linux C++
CMake 秘籍(二)(1)
CMake 秘籍(二)
33 0
|
5月前
|
编译器 开发工具
CMake 秘籍(八)(2)
CMake 秘籍(八)
29 0
|
5月前
|
并行计算 编译器 Linux
CMake 秘籍(二)(4)
CMake 秘籍(二)
41 0
|
5月前
|
编译器 Linux C++
CMake 秘籍(六)(2)
CMake 秘籍(六)
64 0
下一篇
无影云桌面