CMake 秘籍(一)(2)

简介: CMake 秘籍(一)

CMake 秘籍(一)(1)https://developer.aliyun.com/article/1524596

额外软件

一些配方将需要额外的软件,这些将在以下部分中介绍。

BLAS 和 LAPACK

大多数 Linux 发行版都提供了 BLAS 和 LAPACK 的软件包。例如,在 Ubuntu 14.04 LTS 上,您可以运行以下命令:

$ sudo apt-get install libatlas-dev liblapack-dev liblapacke-dev

在 macOS 上,随 XCode 一起提供的 Accelerate 库足以满足我们的需求。

在 Windows 上,使用 MSYS2 环境,可以按照以下方式安装这些库(假设是 64 位版本):

$ pacman -S mingw64/mingw-w64-x86_64-openblas

或者,您可以从 GitHub 下载 BLAS 和 LAPACK 的参考实现(github.com/Reference-LAPACK/lapack),并从源代码编译这些库。商业供应商可能会为其 BLAS 和 LAPACK API 的实现提供软件包,这些软件包作为适用于您平台的安装程序提供。

消息传递接口(MPI)

有许多商业和非商业的 MPI 实现。对于我们的入门目的,安装任何免费提供的非商业实现就足够了。在 Ubuntu 14.04 LTS 上,我们推荐 OpenMPI。可以使用以下命令安装它:

$ sudo apt-get install openmpi-bin libopenmpi-dev

对于 macOS,Homebrew 分发 MPICH:

$ brew install mpich

也可以从www.open-mpi.org/software/公开的源代码编译 OpenMPI。

对于 Windows,Microsoft MPI 实现可以通过msdn.microsoft.com/en-us/library/bb524831(v=vs.85).aspx安装。

Eigen 线性代数模板库

有些配方需要 Eigen 线性代数模板库,版本 3.3 或更高。如果您的包管理器不提供 Eigen,您可以从在线源代码存档(eigen.tuxfamily.org)安装它。例如,在 GNU/Linux 和 macOS 上,您可以将 Eigen 安装到目录$HOME/Deps/eigen,如下所示:

$ eigen_version="3.3.4"
$ mkdir -p eigen
$ curl -Ls http://bitbucket.org/eigen/eigen/get/${eigen_version}.tar.gz | tar -xz -C eigen --strip-components=1
$ cd eigen
$ cmake -H. -Bbuild_eigen -DCMAKE_INSTALL_PREFIX="$HOME/Deps/eigen" &> /dev/null
$ cmake --build build_eigen -- install &> /dev/null

Boost 库

Boost 包适用于每个操作系统;大多数 Linux 发行版都通过其包管理器提供包。例如,在 Ubuntu 14.04 LTS 上,可以使用以下命令安装 Boost Filesystem、Boost Python 和 Boost Test 库:

$ sudo apt-get install libboost-filesystem-dev libboost-python-dev libboost-test-dev

对于 macOS,MacPorts 和 Homebrew 都为较新版本的 Boost 提供了包。我们在 macOS 上的测试设置按如下方式安装 Boost:

$ brew cask uninstall --force oclint
$ brew uninstall --force --ignore-dependencies boost
$ brew install boost 
$ brew install boost-python3

预构建的 Windows 二进制分发版也可以从 Boost 网站www.boost.org下载。或者,您可以从www.boost.org下载源代码并自行编译库。

交叉编译器

在 Debian/Ubuntu 类系统上,可以使用以下命令安装交叉编译器:

$ sudo apt-get install gcc-mingw-w64 g++-mingw-w64 gfortran-mingw-w64

在 macOS 上,使用 Brew,交叉编译器可以按如下方式安装:

$ brew install mingw-w64

其他包管理器提供相应的包。

使用打包的交叉编译器的替代方案是使用 M 交叉环境(mxe.cc)从源代码构建它们。

ZeroMQ、pkg-config、UUID 和 Doxygen

在 Ubuntu 14.04 LTS 上,这些包可以按如下方式安装:

$ sudo apt-get install pkg-config libzmq3-dev doxygen graphviz-dev uuid-dev

在 macOS 上,我们建议使用 Brew 安装:

$ brew install ossp-uuid pkg-config zeromq doxygen

pkg-config程序和 UUID 库仅在类 Unix 系统上可用。

在 Windows 上,使用 MSYS2 环境,这些依赖项可以按如下方式安装(假设是 64 位版本):

$ pacman -S mingw64/mingw-w64-x86_64-zeromq
$ pacman -S mingw64/mingw-w64-x86_64-pkg-config
$ pacman -S mingw64/mingw-w64-x86_64-doxygen
$ pacman -S mingw64/mingw-w64-x86_64-graphviz

Conda 构建和部署工具

探索使用 Conda 打包的配方将需要系统上安装了 Miniconda 和 Conda 构建和部署工具。之前给出了安装 Miniconda 的说明。要在 GNU/Linux 和 macOS 上安装 Conda 构建和部署工具,请运行以下命令:

$ conda install --yes --quiet conda-build anaconda-client jinja2 setuptools
$ conda clean -tipsy
$ conda info -a

这些工具可以按如下方式在 Windows 上安装:

$conda_path = "C:\Deps\conda\Scripts\conda.exe"
$args = "install --yes --quiet conda-build anaconda-client jinja2 setuptools"
Start-Process -FilePath "$conda_path" -ArgumentList $args -Wait -Passthru
$args = "clean -tipsy"
Start-Process -FilePath "$conda_path" -ArgumentList $args -Wait -Passthru
$args = "info -a"
Start-Process -FilePath "$conda_path" -ArgumentList $args -Wait -Passthru

测试配方

这些配方在先进的持续集成(CI)服务上进行了测试:Travis(travis-ci.org)用于 GNU/Linux 和 macOS,Appveyor(www.appveyor.com)用于 Windows,以及 CircleCI(circleci.com)用于使用商业编译器的额外 GNU/Linux 测试。CI 服务的配置文件可以在仓库中找到(github.com/dev-cafe/cmake-cookbook/):.travis.yml 用于 Travis,.appveyor.yml 用于 Appveyor,以及 .circleci/config.yml 用于 CircleCI。Travis 和 Appveyor 的额外安装脚本可以在 testing/dependencies 文件夹中找到。

我们在 Travis GNU/Linux 基础设施上使用 CMake 3.5.2 和 CMake 3.12.1 测试这些配方。在 Travis macOS 基础设施上使用 CMake 3.12.1。在 Appveyor 上,测试使用 CMake 3.11.3。在 CircleCI 上,使用 CMake 3.12.1。

测试机制是一套包含在 testing 文件夹中的 Python 脚本。脚本 collect_tests.py 将运行测试并报告它们的状态。可以单独测试配方,也可以批量测试;collect_tests.py 接受一个正则表达式作为命令行输入,例如:

$ pipenv run python testing/collect_tests.py 'chapter-0[1,7]/recipe-0[1,2,5]'

此命令将运行第一章和第七章中第 1、2 和 5 个配方的测试。输出示例如下:

要获取更详细的输出,请设置VERBOSE_OUTPUT=ON:

$ env VERBOSE_OUTPUT=ON pipenv run python testing/collect_tests.py 'chapter-*/recipe-*'

报告问题和提出改进建议

请在github.com/dev-cafe/cmake-cookbook/issues报告问题。

为了贡献更改,我们建议分叉仓库github.com/dev-cafe/cmake-cookbook并使用拉取请求提交更改,遵循help.github.com/articles/creating-a-pull-request-from-a-fork/。

对于非简单的更改,我们建议首先在github.com/dev-cafe/cmake-cookbook/issues上打开一个问题来描述和讨论提议的更改,然后再发送拉取请求。

第二章:从简单的可执行文件到库

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

  • 将单个源文件编译成可执行文件
  • 切换生成器
  • 构建和链接静态和共享库
  • 使用条件控制编译
  • 向用户展示选项
  • 指定编译器
  • 切换构建类型
  • 控制编译器标志
  • 设置语言标准
  • 使用控制流结构

引言

本章中的示例将引导您完成构建代码所需的基本任务:编译可执行文件、编译库、根据用户输入执行构建操作等。CMake 是一个构建系统生成器,特别适合于平台和编译器无关。我们努力在本章中展示这一方面。除非另有说明,所有示例都与操作系统无关;它们可以在不加修改的情况下在 GNU/Linux、macOS 和 Windows 上运行。

本书中的示例主要针对 C++项目,并使用 C++示例进行演示,但 CMake 也可用于其他语言的项目,包括 C 和 Fortran。对于任何给定的示例,只要合理,我们都尝试包括 C++、C 和 Fortran 的示例。这样,您就可以选择您喜欢的语言的示例。有些示例是专门为突出特定语言选择时需要克服的挑战而定制的。

将单个源文件编译成可执行文件

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

在本示例中,我们将演示如何运行 CMake 来配置和构建一个简单的项目。该项目由单个源文件组成,用于单个可执行文件。我们将讨论 C++项目,但 GitHub 存储库中提供了 C 和 Fortran 的示例。

准备工作

我们希望将以下源代码编译成一个单独的可执行文件:

#include <cstdlib>
#include <iostream>
#include <string>
std::string say_hello() { return std::string("Hello, CMake world!"); }
int main() {
  std::cout << say_hello() << std::endl;
  return EXIT_SUCCESS;
}

如何操作

除了源文件外,我们还需要向 CMake 提供一个描述,说明如何为构建工具配置项目。描述使用 CMake 语言完成,其全面的文档可以在cmake.org/cmake/help/latest/在线找到。我们将把 CMake 指令放入一个名为CMakeLists.txt的文件中。

文件名是区分大小写的;它必须被称为CMakeLists.txt,以便 CMake 能够解析它。

详细来说,以下是遵循的步骤:

  1. 使用您喜欢的编辑器打开一个文本文件。该文件将被命名为CMakeLists.txt。
  2. 第一行设置 CMake 的最低要求版本。如果使用的 CMake 版本低于该版本,将发出致命错误:
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
  1. 第二行声明了项目的名称(recipe-01)和支持的语言(CXX代表 C++):
project(recipe-01 LANGUAGES CXX)
  1. 我们指示 CMake 创建一个新的目标:可执行文件hello-world。这个可执行文件是通过编译和链接源文件hello-world.cpp生成的。CMake 将使用所选编译器和构建自动化工具的默认设置:
add_executable(hello-world hello-world.cpp)
  1. 将文件保存在与源文件hello-world.cpp相同的目录中。请记住,它只能被命名为CMakeLists.txt。
  2. 我们现在准备通过创建并进入构建目录来配置项目:
$ mkdir -p build
$ cd build
$ cmake ..
-- The CXX compiler identification is GNU 8.1.0
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/user/cmake-cookbook/chapter-01/recipe-01/cxx-example/build
  1. 如果一切顺利,项目配置已经在构建目录中生成。我们现在可以编译可执行文件了:
$ cmake --build .
Scanning dependencies of target hello-world
[ 50%] Building CXX object CMakeFiles/hello-world.dir/hello-world.cpp.o
[100%] Linking CXX executable hello-world
[100%] Built target hello-world

它是如何工作的

在这个示例中,我们使用了一个简单的CMakeLists.txt来构建一个“Hello world”可执行文件:

cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
project(recipe-01 LANGUAGES CXX)
add_executable(hello-world hello-world.cpp)

CMake 语言是不区分大小写的,但参数是区分大小写的。

CMake 中,C++是默认的编程语言。然而,我们建议始终在project命令中使用LANGUAGES选项明确声明项目的语言。

为了配置项目并生成其构建系统,我们必须通过命令行界面(CLI)运行 CMake。CMake CLI 提供了许多开关,cmake --help将输出屏幕上列出所有可用开关的完整帮助菜单。我们将在本书中了解更多关于它们的信息。正如您将从cmake --help的输出中注意到的,大多数开关将允许您访问 CMake 手册。生成构建系统的典型命令序列如下:

$ mkdir -p build
$ cd build
$ cmake ..

在这里,我们创建了一个目录,build,其中将生成构建系统,我们进入了build目录,并通过指向CMakeLists.txt的位置调用了 CMake(在这种情况下位于父目录中)。可以使用以下调用来实现相同的效果:

$ cmake -H. -Bbuild

这个调用是跨平台的,并引入了-H和-BCLI 开关。使用-H.我们指示 CMake 在当前目录中搜索根CMakeLists.txt文件。-Bbuild告诉 CMake 在名为build的目录中生成所有文件。

注意,cmake -H. -Bbuild调用 CMake 仍在进行标准化:cmake.org/pipermail/cmake-developers/2018-January/030520.html。这就是为什么我们在这本书中将使用传统方法(创建一个构建目录,进入它,并通过指向CMakeLists.txt的位置来配置项目)。

运行cmake命令会输出一系列状态消息来通知您配置情况:

$ cmake ..
-- The CXX compiler identification is GNU 8.1.0
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/user/cmake-cookbook/chapter-01/recipe-01/cxx-example/build

在CMakeLists.txt所在的同一目录中运行cmake .原则上足以配置项目。但是,CMake 随后会将所有生成的文件写入项目的根目录。这将是一个源内构建,通常是不希望的,因为它混合了项目的源代码和构建树。我们演示的源外构建是首选实践。

CMake 是一个生成器构建系统。您描述了构建系统(如 Unix Makefiles、Ninja、Visual Studio 等)需要执行的操作类型,以便编译您的代码。然后,CMake 为所选的构建系统生成相应的指令。默认情况下,在 GNU/Linux 和 macOS 系统上,CMake 使用 Unix Makefiles 生成器。在 Windows 上,Visual Studio 是默认生成器。我们将在下一个配方中更详细地了解生成器,并在第十三章,替代生成器和交叉编译中重新审视生成器。

在 GNU/Linux 上,CMake 将默认生成 Unix Makefiles 以构建项目:

  • Makefile:make将运行以构建项目的一组指令。
  • CMakeFiles:该目录包含 CMake 用于检测操作系统、编译器等的临时文件。此外,根据所选的生成器,它还包含特定于项目的文件。
  • cmake_install.cmake:一个 CMake 脚本,用于处理安装规则,在安装时使用。
  • CMakeCache.txt:正如文件名所示,这是 CMake 的缓存文件。在重新运行配置时,CMake 会使用此文件。

要构建示例项目,我们运行了以下命令:

$ cmake --build .

此命令是一个通用的跨平台包装器,用于所选生成器的本地构建命令,在本例中为make。我们不应忘记测试我们的示例可执行文件:

$ ./hello-world
Hello, CMake world!

最后,我们应该指出,CMake 不强制要求特定的名称或特定的位置用于构建目录。我们可以将其完全放置在项目路径之外。这将同样有效:

$ mkdir -p /tmp/someplace
$ cd /tmp/someplace
$ cmake /path/to/source
$ cmake --build .

还有更多

官方文档位于cmake.org/runningcmake/,提供了运行 CMake 的简明概述。由 CMake 生成的构建系统,在上面的示例中为Makefile,将包含构建给定项目的对象文件、可执行文件和库的目标和规则。在当前示例中,hello-world可执行文件是我们唯一的目标,但是运行命令:

$ cmake --build . --target help
The following are some of the valid targets for this Makefile:
... all (the default if no target is provided)
... clean
... depend
... rebuild_cache
... hello-world
... edit_cache
... hello-world.o
... hello-world.i
... hello-world.s

揭示了 CMake 生成的目标比仅构建可执行文件本身所需的目标更多。可以使用cmake --build . --target 语法选择这些目标,并实现以下目标:

  • all(或使用 Visual Studio 生成器时的ALL_BUILD)是默认目标,将构建项目中的所有其他目标。
  • clean,是选择删除所有生成的文件的目标。
  • depend,将调用 CMake 为源文件生成任何依赖项。
  • rebuild_cache,将再次调用 CMake 来重建CMakeCache.txt。如果需要从源代码中添加新条目,这是必要的。
  • edit_cache,这个目标将允许你直接编辑缓存条目。

对于更复杂的项目,包括测试阶段和安装规则,CMake 将生成额外的便利目标:

  • test(或使用 Visual Studio 生成器时的RUN_TESTS)将使用 CTest 运行测试套件。我们将在第四章,创建和运行测试中详细讨论测试和 CTest。
  • install,将执行项目的安装规则。我们将在第十章,编写安装程序中讨论安装规则。
  • package,这个目标将调用 CPack 来为项目生成可重新分发的包。打包和 CPack 将在第十一章,打包项目中讨论。

切换生成器

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

CMake 是一个构建系统生成器,单个CMakeLists.txt可以用于为不同平台上的不同工具链配置项目。你可以在CMakeLists.txt中描述构建系统需要运行的操作来配置和编译你的代码。基于这些指令,CMake 将为所选构建系统(Unix Makefiles、Ninja、Visual Studio 等)生成相应的指令。我们将在第十三章,替代生成器和交叉编译中重新讨论生成器。

准备工作

CMake 支持大量不同平台的原生构建工具。无论是命令行工具,如 Unix Makefiles 和 Ninja,还是集成开发环境(IDE)工具,都得到支持。你可以通过运行以下命令来获取你平台和已安装的 CMake 版本上可用的生成器的最新列表:

$ cmake --help

此命令的输出将列出 CMake 命令行界面的所有选项。在底部,你将找到可用生成器的列表。例如,这是在安装了 CMake 3.11.2 的 GNU/Linux 机器上的输出:

Generators
The following generators are available on this platform:
  Unix Makefiles = Generates standard UNIX makefiles.
  Ninja = Generates build.ninja files.
  Watcom WMake = Generates Watcom WMake makefiles.
  CodeBlocks - Ninja = Generates CodeBlocks project files.
  CodeBlocks - Unix Makefiles = Generates CodeBlocks project files.
  CodeLite - Ninja = Generates CodeLite project files.
  CodeLite - Unix Makefiles = Generates CodeLite project files.
  Sublime Text 2 - Ninja = Generates Sublime Text 2 project files.
  Sublime Text 2 - Unix Makefiles = Generates Sublime Text 2 project files.
  Kate - Ninja = Generates Kate project files.
  Kate - Unix Makefiles = Generates Kate project files.
  Eclipse CDT4 - Ninja = Generates Eclipse CDT 4.0 project files.
  Eclipse CDT4 - Unix Makefiles= Generates Eclipse CDT 4.0 project files.

通过本配方,我们将展示为同一项目切换生成器是多么容易。

CMake 秘籍(一)(3)https://developer.aliyun.com/article/1524605

相关文章
lua字符串与十六进制数据转换
lua字符串与十六进制数据转换
1029 2
|
小程序 Shell 网络安全
【微信小程序】-- 使用 Git 管理项目(五十)
【微信小程序】-- 使用 Git 管理项目(五十)
|
存储 SQL 编解码
如何在ClickHouse中处理时序数据
ClickHouse具有强大的工具,可以高效地存储和处理时序数据,并可用于简单的解决方案和数据发掘,以及支持PB级的实时分析应用。
|
SQL 存储 关系型数据库
MySQL创建数据表(CREATE TABLE语句)
MySQL创建数据表(CREATE TABLE语句)
2451 0
|
11月前
|
人工智能 自然语言处理 安全
直播带货效率提升300%:这个AI指令让技术人也能写出专业话术
技术人写直播话术太难?逻辑思维 vs 情感营销冲突大,学得慢、改得累。本文分享一套结构化AI指令,将专业带货方法论转化为可执行模板,支持多品类定制,30分钟生成高转化话术,助力开发者高效应对朋友求助或产品推广,轻松玩转直播文案。
2391 5
|
数据采集 机器学习/深度学习 人工智能
2026年具身智能商业化浪潮前瞻:开发者工具与软件生态的万亿级掘金图谱
在具身智能执行器和传感器等硬件成本持续下降的背景下,真正驱动其大规模商业化爆发的,并非单一的硬件产品,而是其背后的软件与生态系统。正如互联网的价值最终体现在软件应用与服务上,具身智能的商业价值正在从传统的“硬件产品销售”转向“软件与服务订阅”。RaaS等创新商业模式的兴起,正是这一趋势的直接体现。这里我们将深入剖析2026年具身智能领域,特别是围绕数据采集、训练和任务开发的软件工具与服务所蕴藏的万亿级商业机遇,为开发者与投资者描绘一幅详尽的掘金图谱。
1512 0
|
存储 消息中间件 缓存
面试的系统设计题,给我整懵了。。。
先赞后看,Java进阶一大半小明(化名)坐在密不透风的会议室里,手握着笔,放在桌面上的是满满的两页面试题。其中一道系统设计题是这样。。。微博或者短信都有单条发送字数的限制,如果需要分享一个长网址,很容易越出限制,短链服务可以将长网址变成短网址,方便传播。请设计一个短链服务,要求短网址尽可能短,且保证系统安全和并发能力。各位hao,我是南哥,相信对你通关面试、拿下Offer有所帮助。
536 14
面试的系统设计题,给我整懵了。。。
|
安全 PHP 开发者
Web安全-URL跳转与钓鱼
Web安全-URL跳转与钓鱼
675 8
|
JavaScript Linux 网络安全
VS Code远程调试Nodejs项目
VS Code远程调试Nodejs项目