【学习笔记】Mastering CMake (二)—— 开始

前言:

学习笔记,随时更新。如有谬误,欢迎指正。


说明:

  1. 红色字体为较为重要部分。
  2. 绿色字体为个人理解部分。

2 开始

2.1 在你的电脑上获取并安装 CMake

在使用 CMake 之前,你必须在你的系统上安装或者构建 CMake 二进制文件。在许多系统中,你可能会发现 CMake 已经被安装了,或者可以使用系统的标准软件包管理工具来进行安装。 Cygwin 、 Debian 、 FreeBSD 、 OS X MacPorts 、 Mac OS X Fink和其他很多(操作系统)都有 CMake 的发行版。

如果你的系统中没有 CMake 软件包,你可以在下载中找到为各种常见架构预编译好的 CMake 。选择你所需的发行版并按照下载说明进行操作。 CMake 可以安装到任何目录,所以安装时不需要 root 权限。
如果你没有找到为你的系统预编译好的 CMake ,你可以从源代码来自行构建 CMake 。要构建 CMake ,你需要一个现代的 C++ 编译器,以及来自 CMake 下载页面或 Kitware 的 GitLab 仓库的源代码的发行版。要构建 CMake ,请按照源代码树顶层的 README.rst 中的说明进行操作。

2.2 目录结构

有两个主要目录 CMake 在构建项目时会用到:源目录二进制目录源目录是指你的项目源代码所在的目录。这也是 CMakeLists 文件将要被查找的目录。二进制目录是指你想要 CMake 放置它所生成的对象文件、库和可执行文件的目录。 CMake 不会在源目录中写任何文件,而仅仅会在二进制路径(写文件)。
源外构建,即源目录和二进制目录不相同,这种方式是强烈推荐的。源内构建,即源目录和二进制目录相同,这种方式也是被支持的,但是如果可能的话尽量避免(这种方式)。

源外构建使得维护干净的源代码树变得非常容易,并允许快速删除构建所生成的所有文件。将构建树独立于源码树之外,这也使得支持单个源代码树的多个构建变得非常容易。这个在你想要使用一份源码而使用不同构建选项做多个构建的时候很有用

2.3 CMake 的基础用法

CMake 接受一个或多个 CMakeLists 文件作为输入,并生成项目文件或 makefile 文件,这些文件会被各种本地开发工具所使用。

典型的 CMake 流程如下:

  1. 整个项目被定义在一个或多个 CMakeLists 文件中。
  2. CMake 配置并生成项目。
  3. 用户使用自己喜欢的本地开发工具来构建项目。

下面几节将详细描述该流程的每个步骤。

2.4 CMakeLists 文件

CMakeLists 文件(实际上是CMakeLists.txt,但描述时通常省略扩展名)是纯文本文件,其中包含用 CMake 语言编写的对项目的描述。 CMake 语言一系列注释、命令和变量组成。你可能会好奇为什么 CMake 决定拥有自己的语言而不是使用一个已存在的语言如 Python 、 Java 或者 Tcl 。主要原因是 CMake 开发者不想 CMake 依赖一个额外的工具而运行。如果依赖这些其他语言之一,所有的 CMake 用户将被要求安装这些语言,甚至可能是那个语言的某个特定版本。这是上层的语言扩展,出于性能和功能的考虑,这些本应该是 CMake 的工作。

2.4.1 CMake 的 Hello World

首先,我们来看最简单的 CMakeLists 文件。为了从一个源文件中编译出一个可执行文件, CMakeLists 文件需要有如下两行:

cmake_minimum_required(VERSION 3.20)
project(Hello)
add_executable(Hello Hello.c)

顶层的 CMakeLists 文件的第一行应该总是 cmake_minimum_required 。这将给项目指定最低版本的 CMake ,还允许 CMake 向后兼容。

顶层的 CMakeLists 文件的下一行应该是 project 命令。该命令设置项目的名称,并可以指定其他选项,如语言或版本。

对于项目中每一个在 CMakeLists.txt 文件中调用 project 命令的目录, CMake 都将会生成一个顶层的 Makefile 或 IDE 项目文件。项目中将包含 CMakeLists.txt 文件中的所有目标,以及由 add_subdirectory 命令指定的任何子目录。如果在 add_subdirectory 命令中使用了 EXCLUDE_FROM_ALL 选项,生成的项目将不会出现在顶层的 Makefile 或 IDE 项目文件中。这对于生成那些对于主构建过程来说没什么意义的子项目来说十分有用。对于一个有许多例子(许多项目中带有例子来指导开发或者使用)的工程来说可以用这个特性,在 CMake 的一次运行中为每个例子生成构建文件,但这些例子的构建不会作为主构建过程的一部分。

最后,通过 add_executable 命令使用给定的源文件向项目中添加一个可执行文件。

在本例中,源目录中有两个文件: CMakeLists.txt 和 Hello.c 。

下一节将描述如何使用 CMake GUI 和命令行界面来配置和构建项目。

2.5 配置和生成

CMakeLists 文件创建完成后, CMake 会处理文本文件,并在缓存文件中创建缓存项(每个项其实就是缓存的变量值)。用户可以编辑 CMakeLists 文件、或通过 CMake GUI 或 ccmake 指定缓存值,也可以重新配置项目。接下来, CMake 使用缓存项在用户期望的构建系统(例如 Makefile 或 Visual Studio 解决方案)中生成一个项目。

2.5.1 运行 CMake GUI

CMake 拥有一个基于Qt的、可以在大多数平台上使用的用户界面,支持的平台包括 Unix、 Mac OS 和 Windows 。cmake-gui 被包含在 CMake 的源码中,但是如果你想构建它,需要在你的系统上安装 Qt 。

在 Windows 中,可执行文件叫做 cmake-gui.exe ,且应该在 Program Files 下的开始菜单中。它也可能在在你的桌面上有快捷方式,或者说如果你通过源码来构建 CMake ,它将在构建目录。对 UNIX 和 Mac 用户来说可执行文件名为 cmake-gui ,它在你安装 CMake 可执行文件的的地方。 GUI 类似图1所示。最上面两条是源目录和二进制目录。这就允许你指定你想编译哪个源码,并且指定生成的二进制应该放置在哪。你首先需要设置这两个值。如果你指定的二进制目录不存在,它将会帮你创建。如果二进制目录之前已经被 CMake 配置过,则源码树将会自动被设置。

2.5.2 运行 ccmake Curses 界面

在大多数 UNIX 平台上,如果支持 curses 库, CMake 提供了一个叫做 ccmake 的可执行文件。这个界面是一个基于终端的文本应用程序,它与基于 cmake-gui 很相似。要运行 ccmake ,需要把目录切换到你想要放置二进制的目录(可以控制源内构建和源外构建)。然后在命令行中运行 ccmake 并传入源目录路径。这将会开启文本界面,如图2所示。

窗口底部显示的是简短介绍。按下“ c ”键会配置工程。你应该在每次修改了缓存中的值之后进行配置操作。修改值时,使用箭头按键选择缓存项,使用“ enter ”键来进行编辑。按“ enter ”按键会勾选布尔值。一旦你设置好了你想设置的值,按“ g ”键生成 Makefiles 并且退出。你也可以按“ h ”键获取帮助,按“ q ”键退出,按“ t ”键勾选查看高级缓存项。

2.5.3 命令行运行 CMake

通过以命令行的方式使用 cmake 可执行文件来生成项目的构建系统。这很适合有很少选项或者没有选项的项目。对大型工程,如 VTK ,推荐使用 ccmake 、或者 cmake-gui 。使用 CMake 来构建一个项目,首先创建并切换到你想放置二进制的目录。运行 cmake , 指定源码树的路径,并且通过 -D 标记传递各种选项。不同于 ccmake 、或者 cmake-gui ,当使用 cmake 可执行文件的时候,配置和生成步骤是合二为一的。

2.5.4 对 CMake 指定编译器

在一些系统中,你可能有多个编译器可供选择,或者你的编译器可能在一个不标准的地方。这种情况下,你需要为 CMake 指定你所钟意的编译器的位置。这里有三种方式来指定编译器位置:设置生成器来指定编译器、设置环境变量来指定编译器、设置缓存项来指定编译器。某些生成器会与指定编译器绑定,例如 Visual Studio 17 2022 生成器总是使用 Visual Studio 17 编译器。对于基于 Makefile 的生成器, CMake 将会尝试使用一个列表中的常见的编译器,直到找到一个可用的编译器为止。

这个列表可以被在运行 CMake 之前所设置的环境变量截获(意思就是说环境变量可以填充这个列表)。CC 环境变量指定 C 编译器,而 CXX 环境变量指定 C++ 编译器。例如,你可以使用命令行并使用 -DCMAKE_CXX_COMPILER=cl 来直接指定编译器。一旦你选择了编译器并运行过 cmake ,如果你想要更改编译器,请从一个空的二进制目录重新开始(来构建项目)(你也可以通过修改 CMAKE_C_COMPILER 和 CMAKE_CXX_COMPILER 缓存项来更改编译器,但不推荐这样做。这样做的问题是你正在配置的工程或许已经在当前编译器上做了一些测测试来决定它支持所支持的功能,通过修改缓存项的方式修改编译器通常不会让这些测试重做,这样会导致一些错误结果。

编译器和链接器的标识符也可以通过环境变量来设置。设置 LDFLAGS 将会初始化链接标识符的缓存值,而 CXXFLAGS 和 CFLAGS 将会分别初始化 CMAKE_CXX_FLAGS 和 CMAKE_C_FLAGS

2.5.5 构建配置

构建配置允许项目以调试、优化或者一系列其他的特殊标记的方式被构建。 CMake 默认支持 Debug 、 Release 、 MinSizeRel 和 RelWithDebInfo 配置。 Debug 中基本的调试标记被开启。 Release 中基本的优化被开启。 MinSizeRel 中有产生最小目标代码、但不一定是(执行起来)最快的代码的标记。 RelWithDebInfo 是一个优化的构建但也携带者调试信息。

CMake中根据所使用的生成器的不同而处理配置的方式也略有不同。会尽可能的遵循本机构建系统的约定。这意味着使用 Makefiles 与使用 Visual Studio 工程文件时配置影响构建的方式是不同的。

Visual Studio IDE 支持构建配置的概念。 Visual Studio 中的工程默认有 Debug 和 Release 配置。在 IDE 中你可以选择构建 Debug ,文件将会以 Debug 的标记被构建。 IDE 将所有的二进制文件放置到以激活(当前)的配置为名的目录中。这对于构建需要把自定义命令作为构建过程一部分来构建程序的项目来说,有额外的复杂性。请看 CMAKE_CFG_INTDIR 变量和自定义命令章节来获取如何处理这个问题的更多信息。 CMAKE_CONFIGURATION_TYPES 变量被用来告诉 CMake 哪些配置被放入了工作空间

对于基于 Makefile 的生成器,在 CMake 运行时仅仅有一个配置是激活的,它通过 CMAKE_BUILD_TYPE 来指定。如果这个变量为空,则没有标记会被加入到构建中。如果这个变量被设置为一个配置的名字,则适当的变量和规则(例如 CMAKE_CXX_FLAGS_<ConfigName> )将会被加入到编译线中。 Makefiles 不会为目标文件使用特殊的配置子目录。为了构建 debug 和 release 树,用户被希望使用 CMake 的源代码外构建特性来创建多个构建目录,并且在每次构建时为 CMAKE_BUILD_TYPE 设置想要的值。例如:

# With source code in the directory MyProject
# to build MyProject-debug create that directory and cd into it and
ccmake ../MyPorject -DCMAKE_BUILD_TYPE:Debug
# the same idea is used for release tree MyProject-release
ccmake ../MyPorject -DCMAKE_BUILD_TYPE:Release

2.6 构建你的工程

在你运行 CMake 之后,你的工程就做好了被构建的准备。如果你的目标编译器是基于 Makefiles 的,你可以通过切换到二进制树目录然后输入 make(或者 gmake 或者 nmake )来构建的的工程。如果你为 IDE 生成了文件,如 Visual Studio ,你可以你的开启 IDE ,加载工程文件进来,然后如你平常一样来构建。

另一个选择是运行 cmake 命令行并传入 —bulid 选项。这个选项非常方便,它让你以命令行方式构建你的工程,即使这也需要启动IDE(命令行启动,不会有 IDE 界面)。

这就是对简单的工程来安装和运行 CMake 的所有操作。在下面的章节中,我们将考虑 CMake 中更多的细节,并阐述如何在更复杂的软件工程中使用 CMake 。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值