<<Modern CMake>> 翻译 2. CMake 基础

最低版本

这是每个 CMakeLists.txt 文件的第一行。CMakeLists.txt 是 CMake 所需的配置文件名称:

cmake_minimum_required(VERSION 3.1)

我们来了解一点 CMake 语法。 命令名称 cmake_minimum_required 不区分大小写,因此通常的做法是使用小写。1 这里 VERSION 是该命令所需的特殊关键字。 版本号紧跟在 VERSION 关键字之后。 与本书中的任何其他地方一样,你只需单击命令名称即可链接到官方文档,然后可以使用下拉列表切换不同版本的 CMake 文档。

这一行很特别!2 版本号也同时指明了 CMake 的行为变化。 因此,如果你设置 minimum_required 为 VERSION 2.8,在macOS上你就会获得错误的链接行为, 例如,在最新的 CMake 版本中也是如此。 如果你把版本设置为 3.3 或更低,你会得到错误的符号隐藏行为,等等。 在 policies 有一个策略和版本列表。

在 CMake 3.12 中,可以这样写来指定支持的 CMake 版本范围,例如 VERSION 3.1...3.12; 这意味着您最低支持 3.1,同时也测试过并支持到 3.12 的新策略。 这对于需要更好设置的用户来说很不错,并且由于语法上的技巧,它向后兼容旧版本的 CMake(尽管实际运行 CMake 3.2-3.11 只会在此示例中设置 3.1 版本的策略)。 新版本的策略对于 macOS 和 Windows 用户来说往往是最重要的,他们通常也有最新版本的 CMake。

新项目应该这样写:

cmake_minimum_required(VERSION 3.1...3.15)

if(${CMAKE_VERSION} VERSION_LESS 3.12)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
endif()

如果 CMake 版本小于 3.12,则 if 块将为 true,并且策略将设置为当前 CMake 版本。 如果 CMake 为 3.12 或更高,if 块将为 false,此时新语法 cmake_minimum_required 将起作用,这将能够正常工作!

警告:MSVC 的 CMake 服务器模式最初在读取此格式时有一个 bug, 因此如果您需要支持旧版 MSVC 的非命令行 Windows 版本,则需要执行以下操作:

cmake_minimum_required(VERSION 3.1)

if(${CMAKE_VERSION} VERSION_LESS 3.15)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
else()
cmake_policy(VERSION 3.15)
endif()
 

如果您确实需要在此处设置较低的版本,则可以使用 cmake_policy 有条件地增加策略级别或设置特定策略。 请至少为您的 macOS 用户执行此操作!

设置项目

现在,每个顶级 CMake 文件(CMakeLists.txt)都有下面这一行:

project(MyProject VERSION 1.0
DESCRIPTION "非常出色的项目"
LANGUAGES CXX)

现在我们看到了更多的新语法。 字符串被引号包围起来,空格可多可少,项目名称是第一个参数(位置参数)。 这里的所有的关键字参数都是可选的。 通过 VERSION 参数,这会设置了一堆变量,比如 MyProject_VERSION 和 PROJECT_VERSION。 LANGUAGE 可以是 C,CXX,Fortran 和 CUDA(CMake 3.7+)。 C CXX 是默认值。 在 CMake 3.9 中,DESCRIPTION 添加进来设置对项目的描述。 你可以参考 project 这个文档。

 

你可以通过使用 # 开头来添加 注释。 CMake 也有注释的内联语法,但很少需要,因为空格并不重要。

项目名称没什么特别之处。此时不添加任何目标。

生成可执行文件

虽然链接库更有趣,通常我们大部分时间都在生成链接库,但这里我们要从一个简单的可执行文件开始。

add_executable(one two.cpp three.h)

这里有几件要说明的事情。 one 是生成的可执行文件的名称,同时也是创建的 CMake 目标的名称(我保证你会很快听到很多关于目标的信息)。 可执行文件名称后紧接的是源文件列表,您可以根据需要列出任意数量的源文件列表。 CMake 很聪明,会根据文件扩展名正确识别源文件,所以列表中的头文件会被 CMake 理解并忽略。 大多数时候,我们在源文件列表中列出头文件的唯一原因是让它们出现在 IDE 中。 有关通用构建系统和目标的更多信息,请参见 buildsystem

生成链接库

使用 add_library 生成链接库, 也是非常简单:

add_library(one STATIC two.cpp three.h)

您可以选择链接库类型:STATIC,SHARED 或 MODULE。 如果没有设置,CMake 会根据变量 BUILD_SHARED_LIBS 的值在 STATIC 和 SHARED 之间选择。

正如您将在下一节中看到的那样,通常您需要创建一个伪目标,也就是一个不需要编译任何文件的目标,例如,对于仅包含头文件的库。这也可以称为 INTERFACE 库; 唯一的区别是接口库不能跟文件名。

您还可以用一个现有的链接库生成一个 ALIAS 链接库,该库简单地为您提供目标的新名称。这样做的一个好处是你可以生成一个名称中带 :: 的链接库(稍后会看到)。3

配置构建目标

现在我们已经指定了目标,然后我们怎么给它添加相关信息呢?例如,它可能需要一个 include 目录:

target_include_directories(one PUBLIC include)

target_include_directories 将 include 目录添加到目标. PUBLIC 对可执行文件来说意义不大; 对于一个链接库,它让 CMake 知道链接到这个目标的任何目标也必须包含该目录。 其他选项是 PRIVATE(仅影响当前目标,而不影响依赖项)和 INTERFACE(仅限依赖项所需)。

现在,我们可以把目标串联起来:

add_library(another STATIC another.cpp another.h)
target_link_libraries(another PUBLIC one)

target_link_libraries 可能是 CMake 中最有用也最令人困惑的命令。 它需要一个target(another)并添加依赖目标项。 如果名为 one 的目标不存在,则它会添加指向路径上的一个叫做 one 链接库(即命令的名称)。 或者你可以给它一个完整的链接库路径。或链接器标志。 最后还有一点容易混淆的东西,那就是经典的 CMake 允许你忽略关键字 PUBLIC,等等。 如果目标已经链接完成,尝试在链中进一步混合样式,你会收到错误。

主要关注在任何地方使用目标和关键字,这就对了。

目标可以包含目录,链接库(或链接目标),编译选项,编译定义,编译特征(参见 C++11 章节)等。 正如您将在两个包括项目章节中看到的那样,您通常可以使用目标(并始终制作目标)来表示所有你使用的链接库。 即使那不是真正的链接库的,比如 OpenMP,也可以用目标来表示。 这就是现代 CMake 很棒的原因!

开始动手实践

看看您是否可以理解以下文件操作。 它创建了一个简单的 C++11 链接库和一个使用它的程序。 没有依赖。 我稍后将使用 CMake 3.8 系统讨论更多 C++ 标准选项。

cmake_minimum_required(VERSION 3.8)

project(Calculator LANGUAGES CXX)

add_library(calclib STATIC src/calclib.cpp include/calc/lib.hpp)
target_include_directories(calclib PUBLIC include)
target_compile_features(calclib PUBLIC cxx_std_11) add_executable(calc apps/calc.cpp)
target_link_libraries(calc PUBLIC calclib)

1. 在这本书中,我将尽可能避免向你展示错误的做事方式; 你可以在网上找到很多这方面的例子。我偶尔会提到替代做法,但除非绝对必要,否则不推荐这些。通常它们只是帮助您阅读较老的 CMake 代码。

2. 你有时会看到 FATAL_ERROR, 在 CMake <2.6 版本中,需要使用它来支持失败,现在已经不需要了。

3. :: 语法最初用来生成 INTERFACE IMPORTED 链接库, 但是,正因为如此,大多数 target_* 命令都不适用于 IMPORTED 链接库。这使得它们很难自行设置。所以现在不要使用 IMPORTED 关键字,请使用 ALIAS 构件目标; 这在你导出目标前都能正常工作。此限制已经在 CMake 3.11 中修复。

<<Modern CMake>> 翻译 2. CMake 基础的更多相关文章

  1. <<Modern CMake>> 翻译 1. CMake 介绍

    <<Modern CMake>> 翻译 1. CMake 介绍 人们喜欢讨厌构建系统. 仅仅观看 CppCon17 上的演讲,就可以看到开发人员因为构建系统而闹笑话的例子. 这 ...

  2. <<Modern CMake>> 翻译 2.2 CMake 编程

    <<Modern CMake>> 翻译 2.2 CMake 编程 流程控制 CMake有一个 if 语句, 经年累月之后,现在它已经相当复杂. 您可以在 if 语句中使用全大写 ...

  3. <<Modern CMake>> 翻译 2.3 与代码通信

    <<Modern CMake>> 翻译 2.3 与代码通信 配置文件 CMake 允许您使用代码通过 configure_file 存取 CMake 变量. 此命令复制一个文件 ...

  4. <<Modern CMake>> 翻译 2.4 项目目录结构

    <<Modern CMake>> 翻译 2.4 项目目录结构 本节内容有点跑题.但我认为这是一个很好的方法. 我将告诉你如何规划项目的目录. 这是基于惯例,但将帮助您: 轻松阅 ...

  5. 【转载】CMake 简介和 CMake 模板

    转载自我的博客: CMake 简介和 CMake 模板 . 如果你用 Linux 操作系统,使用 cmake 会简单很多,可以参考一个很好的教程: CMake 入门实战 | HaHack .如果你用 ...

  6. Effective Modern C++翻译(1):序言

    /*********************************************************** 关于书: 书是我从网上找到的effective Modern C++的样章,内 ...

  7. Cmake实践(Cmake Practice)第一部分

    参考资料地址:https://github.com/Akagi201/learning-cmake/blob/master/docs/cmake-practice.pdf 一.初识cmake 1. C ...

  8. mysqlQL 5.7 安装报错CMake Error at cmake/boost.cmake:81 (MESSAGE)

    CMake Error at cmake/boost.cmake:81 (MESSAGE): You can download it with -DDOWNLOAD_BOOST=1 -DWITH_BO ...

  9. CMake Error at cmake/OpenCVUtils.cmake

    CMake Error at cmake/OpenCVUtils.cmake:1047 (message): Failed to download . Status= Call Stack (most ...

随机推荐

  1. excel导入到数据库的异常处理

    excel导入到数据库,这个是经常发生的,今天就碰到了一个非常郁闷的事情,在导入到oracle数据的时候,总是出现ORA-01756: 引号内的字符串没有正确结束,认真的排插了数据当中可能出现的错误, ...

  2. PHP PSR4自动加载代码赏析

    第一部分是引入自动加载配置文件 1.入口文件:autoload.php里面没什么东西,就是导入ComposerAutoloader主题文件,一般由一个复杂的名字,不过不用担心就是机器随机生成的一个码而 ...

  3. python中的while循环,格式化输出,运算符,编码

    一.while循环 1.1语法 while 条件: 代码块(循环体) else: 当上面的条件为假的的时候,才会执行. 执行顺序:先判断条件是否为真,如果是真的,执行循环体,再次判断条件,直到条件不成 ...

  4. 3012C语言_数据

    第二章 数据 2.1 数据类型 2.1.1 数据类型决定 1. 数据占内存字节数 2. 数据取值范围 3. 其上可进行的操作 2.2基本数据类型 2.2.1分类 基本类型 类型 符号 关键字 字节 1 ...

  5. 机器学习之支持向量机原理和sklearn实践

    1. 场景描述 问题:如何对对下图的线性可分数据集和线性不可分数据集进行分类? 思路: (1)对线性可分数据集找到最优分割超平面 (2)将线性不可分数据集通过某种方法转换为线性可分数据集 下面将带着这 ...

  6. HBase 学习之路(七)——HBase过滤器详解

    一.HBase过滤器简介 Hbase提供了种类丰富的过滤器(filter)来提高数据处理的效率,用户可以通过内置或自定义的过滤器来对数据进行过滤,所有的过滤器都在服务端生效,即谓词下推(predica ...

  7. Java学习笔记——XML入门

    以下内容来自网络 什么是 XML? XML 指可扩展标记语言(EXtensible Markup Language). XML 是一种很像HTML的标记语言. XML 的设计宗旨是传输数据,而不是显示 ...

  8. Xshell连接WSL

    Xshell连接WSL Windows的Windows Subsystem for Linux很好用, 可以直接使用Linux的CLI模式, 对于开发来说很友好. 安装 Windows 10系统上, ...

  9. js深入(四)万脸懵圈的this指向

    作为一个js菜鸡的我而言,在之前讲到过那么多的js链式查找机制,比如说原型链,作用域链等等,想当然的把这个机制带入到了this指向上边,结果就是这个this指向指的我万脸懵逼(标题换字了,担心被河蟹) ...

  10. 微信小程序注册流程

    响应公司号召,跟上时代潮流,接下来我将独自开发微信小程序,接下来我介绍下注册流程,后续会补上小程序开发心得. 注册流程 注册之前,需要使用一个邮箱,该邮箱作为登录小程序的账号,这个邮箱不能被微信开放平 ...