<> 翻译 2. CMake 基础

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

最低版本

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

cmake_minimum_required(VERSION 3.1) 

咱们来了解一点 CMake 语法。 命令名称 cmake_minimum_required 不区分大小写,所以一般的作法是使用小写。1 这里 VERSION 是该命令所需的特殊关键字。 版本号紧跟在 VERSION 关键字以后。 与本书中的任何其余地方同样,你只需单击命令名称便可连接到官方文档,而后可使用下拉列表切换不一样版本的 CMake 文档。git

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

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

新项目应该这样写:app

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 版本,则须要执行如下操做:ui

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 用户执行此操做!spa

 

设置项目

如今,每一个顶级 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 中修复。  ↩
相关文章
相关标签/搜索