03 最小CMake项目

时间:2022-09-23 00:35:53

03 最小CMake项目

所有CMake项目都从一个CMakeLists.txt文件开始,此文件应该放在源代码树的最顶层目录下。可以将CMakeLists.txt想象成CMake项目文件,定义了从源和目标的构建到测试、打包和其他自定义任务的一切事物。他可以仅有简单的几行,也可以相当的复杂并且从其他目录中导入更多的文件。CMakeLists.txt只是一个普通的文本文件,通常像项目中其他源文件一样直接编辑。

和其他源文件的语言规范类似,CMake也定义了自己的语言规范,其中有许多程序员熟悉的东西,例如变量、函数、宏、条件逻辑、循环、注释等。这些概念和功能将在后续章节进行介绍。但目前,我们从一个简单的构建开始。如下是一个极小的,格式良好的CMakeLists.txt文件,用于生成一个简单可执行文件:

cmake_minimum_required(VERSION 3.2)
project(MyApp)
add_executable(myExe main.cpp)

示例中的每一行都执行了一个CMake内建命令。在CMake中,命令和其他语言的函数调用类似,只是虽然它们支持参数,但是不能直接返回值(后续章节显示如何以其他方式将值返回给调用者),参数之间用空格分隔,可以跨多行分隔:

add_executable(myExe
    main.cpp
    src1.cpp
    src2.cpp)

命令的名字是大小写不敏感的,但如今更常见的是命令名称全使用小写(CMake官方文档也是如此)。

3.1 管理CMake版本

CMake一直在更新并新增对其他工具、平台和特性的支持。CMake开发人员保证了每个新版本的向后兼容性,因此当用户更新到较新版本的CMake时,项目可以继续像以前一样构建。有时,CMake在新的版本中会更改自身的某一行为,或者引入更严格的检查和警告,CMake提供了策略(policy)机制,允许项目不立即处理此类问题,而是声明其“像CMake版本X.Y.Z一样执行”。这允许CMake在内部修复错误并引入新功能,但仍可以保持与任何过去的版本的行为一致。

项目指定其预期的CMake版本行为的主要方式是使用cmake_minimum_required()命令。这个命令应该是CMakeLists.txt文件的第一行,以便在进行任何其他行为之前进行检查和配置,这个命令执行两件事:

  • 它指定项目所需的CMake的最低版本。如果CMakeLists.txt文件使用比指定版本更老的CMake来处理,则它会立即报错并停止运行。这可确保在CMake执行之前,所需的最小功能集可用。
  • 它强制使CMake的行为与指定版本一致。

此命令十分重要,如果CMakeLists.txt的第一条命令不是cmake_minimum_required()命令,则CMake会发出警告,因为CMake需要知道如何为后续的命令设置策略行为(policy behavior)。对于大多数项目,将cmake_minimum_required()简单地视为指定所需的最低CMake版本就足够了,而另一个作用,将CMake行为设置为与特定版本相同,可以被认为是附带的,在12 策略TODO中更详细的讨论了策略的设置并解释了如何根据需要定制此行为。

cmake_minimum_required()命令的格式很直观:

cmake_minimum_required(VERSIOn major.minor[.patch[.tweak]])

VERSION关键字必须始终存在,并且提供的版本详细信息中有major.minor部分。在大多数项目中,不需要patchtweak部分,这些通常只出现在CMake的次要更新版本中。只有在需要修复CMake的特定的错误时,项目才应该指定patch部分,而由于CMake 3.x系列中没有使用tweak,项目也不应该使用此部分。

开发人员应该仔细考虑它们的项目所需的CMake最低版本,3.2版本可能是现在项目所考虑的最低的版本,因为它为现代CMake提供了相当完整的功能集。2.8.12版本缺乏许多有用的功能,但它可能适用于较老的项目。如果需要在iOS等一些fast-moving平台中开发,可能需要较新版本的CMake才能支持新的操作系统版本。

作为一般经验法则,使用最新的CMake版本,不会给项目的构建带来重大的问题。通常项目中最大的困难是需要支持较老的平台,而这些平台提供的CMake版本可能相当旧,对于这种情况,开发人员应该尽可能考虑安装一个更新的版本,而不是将自己限制在非常旧的CMake版本上。另一方面,如果项目本身是其他项目的依赖项,那么使用较新版本的CMake可能会给适配带来障碍,在这种情况下,使用能满足所需的CMake功能的较低的版本,如何可以则使用高版本的功能可能更好(12 策略TODO中介绍了实现此目的的方法)。这种方式防止了其他项目*使用比目标环境所提供的版本更高的CMake。使用旧版本的主要缺点是它可能会导致更多的告警,CMake鼓励使用较新的版本。

3.2 project()命令

每个CMake项目都应该包含一个project()命令,并且应该紧随在cmake_minimum_required()命令之后。这个命令的常用调用形式如下:

project(projectName
        [VERSION major[.minor[.patch[.tweak]]]]
        [LANGUAGES languageName ...])

其中projectName是必填项,只能包含字母、数字、下划线(_)和连字符(-),在实践中通常只使用字母和下划线。由于不允许空格,所以项目名称不必用引号包围。此名称可以用于具有某些项目生成器(例如Xcode和Visual Studio)的顶层项目中,也可用于项目的其他部分,例如作为打包和文档元数据的默认值,用来提供项目特定变量等。项目名称是project()命令的唯一必须参数。

可选项VERSION仅在CMake 3.0及之后支持,与projectName一样,版本详细信息被CMake用来填充一些变量或者作为默认的包元数据,除此之外没有其他意义。尽管如此,指定项目的版本是一个好的习惯,以便于项目的其他部分可以引用它,19 指定版本细节TODO中深入介绍了这一点,并说明了如何在CMakeLists.txt文件中引用此版本信息。

可选项LANGUAGES定义项目启用的编程语言,支持的值包括C、CXX、Fortran、ASM、Java等,如果指定多种语言,使用空格分隔它们。在某些特殊情况下,项目可能声明无需任何语言,此时可以使用LANGUAGES NONE来实现,后面章节介绍的技术利用了这种特殊的形式。如果没有提供LANGUAGES选项,则CMake默认使用C和CXX作为LANGUAGES的值。CMake 3.0版本之前不支持LANGUAGES关键字,但仍可以指定语言,只需要按照旧版本的形式,在项目名称后面追加:

project(myProj C CXX)

新的项目鼓励指定3.0及以上的CMake版本,并使用带有LANGUAGES关键字的形式。

project()命令不仅填充几个变量,它的重要职责之一是检查每种启用的语言的编译器,以确保它们能成功编译和链接,可以尽早发现编译器和链接器的问题。当检查通过后,CMake将设置一些变量和属性,这些变量和属性控制着启用的语言的构建过程。如果CMakeLists.txt文件没有调用project()或没有尽早调用,那么CMake将在内部隐式地使用默认语言C和CXX来调用它,确保正确设置编译器和链接器,保证依赖于它们的命令的正确性。后续章节将详细介绍如何设置工具链,并演示如何查询和修改编译器标志、编译器位置等内容。

当CMake检查编译器和链接器成功时,检查结果将缓存下载,以便在后续CMake运行时不重复检查,这些缓存的详细信息存储在构建目录的CMakeCache.txt文件中,有关检查的详细信息可以在构建区域的子目录中找到,但开发人员通常不关注那里,除非在使用不熟悉的编译器或设置交叉编译工具链文件时。

3.3 构建基本可执行文件

为了完成我们的最小示例,使用add_executable()命令告诉CMake使用一组源文件来创建可执行文件,此命令的基本形式为:

add_executable(targetName source1 [source2 ...])

此命令将创建一个可执行文件,该可执行文件在CMake中使用targetName来引用。此名称可以包含字母、数字、下划线和连字符。项目构建时,将在构建目录生成一个可执行文件,文件的名字基于目标名称且与平台有关。考虑如下示例:

add_executable(myApp main.cpp)

默认情况下,Windows平台中可执行文件名称为myApp.exe,而在基于Unix的平台上则为myApp。可以通过目标属性来自定义可执行文件的名称,将在09_属性TODO中介绍。可以使用多个不同目标名称的add_executable()命令来创建多个可执行文件,如果多个add_executable()命令使用了相同的目标名称,CMake将报错并结束运行。

3.4 注释

在本章结束之前,需要学习一下CMakeLists.txt文件的注释。CMake的注释和Unix shell脚本格式类似,任何以#开头的行都被视为注释,除了在以引号包围的字符串中,文本行中#之后的任何内容也被视为注释。如下显示了一些注释示例,并汇集了本章中介绍的概念:

cmake_minimum_required(VERSION3.2)

# 我们不使用C++编译器,所以project()命令无需测试
# 平台C++编译器是否可用
project(MyApp VERSION 4.7.2 LANGUAGES C)

add_executable(mainToo
    main.c
    debug.c)

add_executable(testTool testTool.c)

3.5 建议

确保每个CMake项目在*CMakeLists.txt文件的第一行中包含cmake_minimum_required()命令。在决定所需的最小版本号时,要记住版本越高,项目能够使用的CMake功能就越多,这意味着项目能适配新的平台或操作系统,但是也不可避免的引入了新的需要构建系统处理的问题。相反,如果创建一个为操作系统本身的一部分进行构建和分发的项目(常见于Linux),则最低CMake版本可能由系统本身的CMake版本决定。

如果项目需要CMake 3.0或更高版本,应该尽早将项目版本号写入project()命令中。如果在项目生命周期的后期,要克服现有流程的惯性来改变项目的版本号,可能会很困难。

github地址:https://github.com/theArgs/CMake-Guide