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

03 最小CMake项目的更多相关文章

  1. 直接在CMake项目中编译GoogleTest和GoogleMock作为项目的一部分

    直接在CMake项目中编译GoogleTest和GoogleMock作为项目的一部分 本文是关于如何将GoogleTest和GoogleMock在没有预先编译安装在机器的情况下,直接在项目中作为项目的 ...

  2. 通过例子进阶学习C++(七)CMake项目通过模板库实现约瑟夫环

    本文是通过例子学习C++的第七篇,通过这个例子可以快速入门c++相关的语法. 1.问题描述 回顾一下约瑟夫环问题:n 个人围坐在一个圆桌周围,现在从第 s 个人开始报数,数到第 m 个人,让他出局:然 ...

  3. Visual Studio CMake 项目和 WSL

    Visual Studio CMake 项目和 WSL https://devblogs.microsoft.com/cppblog/c-with-visual-studio-2019-and-win ...

  4. Flutter 即学即用系列博客——03 在旧有项目引入 Flutter

    前言 其实如果打算在实际项目中引入 Flutter,完全将旧有项目改造成纯 Flutter 项目的可能性比较小,更多的是在旧有项目引入 Flutter. 因此本篇我们就说一说如何在旧有项目引入 Flu ...

  5. hge引擎示例教程cmake项目

    hge引擎的示例代码在vs2017不能很好的运行,需要调不少东西,所以我将其重新整理成cmake的项目. 所有示例均在vs2017 msvc 下测试可以正常运行. 由于缺少libhgehelp.a所以 ...

  6. Qt Creator 源码学习笔记03,大型项目如何管理工程

    阅读本文大概需要 6 分钟 一个项目随着功能开发越来越多,项目必然越来越大,工程管理成本也越来越高,后期维护成本更高.如何更好的组织管理工程,是非常重要的 今天我们来学习下 Qt Creator 是如 ...

  7. 「Python实用秘技03」导出项目的极简环境依赖

    本文完整示例代码及文件已上传至我的Github仓库https://github.com/CNFeffery/PythonPracticalSkills 这是我的系列文章「Python实用秘技」的第3期 ...

  8. ASP.NET Core Web API 最小化项目

    ASP.NET Core中默认的ASP.NET Core 模板中有Web API 模板可以创建Web API项目. 有时,只需要创建一个API,不需要关心Razor,本地化或XML序列化.通过删除无用 ...

  9. Qt Creator下应用CMake项目调试mex文件

    网上可以找到很多应用Visual Studio编写.编译mex文件,并与MATLAB联合调试的文章.但这只限于Win平台,网上许多源码都是.mexa64的文件,它们的作者是怎么调试的呢?这里我介绍一下 ...

随机推荐

  1. windows server2012R2 上 .net core IIS 部署--应用程序池 自动停止

    在windows server2016安装部署.NET CORE时,只需要将.net core应用程序池设置无托管,然后对应你项目的版本安装一个dotnet-hosting-2.2.6-win.exe ...

  2. tauri+vue开发小巧的跨OS桌面应用-股票体检

    最近打算写一个用于股票体检的软件,比如股权质押比过高的股票不合格,ROE小于10的股票不合格,PE大于80的股票不合格等等等等,就像给人做体检一样给股票做个体检.也实现了一些按照技术指标.基本面自动选 ...

  3. Drone-比Jenkins更轻量化的持续集成部署工具

    Drone 简介 Drone 是一个基于Docker容器技术的可扩展的持续集成引擎,由GO语言编写,可用于自动化测试与构建,甚至发布.每个构建都在一个临时的Docker容器中执行,使开发人员能够完全控 ...

  4. SVM简要介绍

    SVM 支持向量机(SVM),是一个用于解决二分类问题的有监督机器学习模型. 1.SVM的两个优点 更高的速度 在有一定的样本数量支持下(成千上万张),具有比其他模型有更好的效果 2.SVM的工作过程 ...

  5. Css3入门详解

    一.Css基本语法 1.Html和Css没分开时 点击查看代码 <!DOCTYPE html> <html lang="en"> <head> ...

  6. APISpace 分钟级降水预报API接口 免费好用

    各种不同类型的降水对国民经济和国防建设会产生不同的影响.无论农业生产.航空.航海.交通运输.水利建设.防涝防旱等都需要以及准确的降水预报.   分钟级降水预报API,支持国内任一经纬度的预报数据,实时 ...

  7. CSS(十四):盒子模型

    页面布局的本质 网页布局过程: 先准备好相关的网页元素,网页元素基本都是盒子. 利用CSS设置好盒子样式,然后放到相应的位置 往盒子里面装内容 网页布局的本质:就是利用CSS摆盒子 盒子模型 组成 所 ...

  8. Nginx常用命令之启动与重启

    1.测试新的Nginx程序是否正确 [test@P-SH-Nginx-01 nginx]$ ./sbin/nginx -t nginx: the configuration file /usr/loc ...

  9. Flink Window&Time 原理

    Flink 中可以使用一套 API 完成对有界数据集以及无界数据的统一处理,而无界数据集的处理一般会伴随着对某些固定时间间隔的数据聚合处理.比如:每五分钟统计一次系统活跃用户.每十秒更新热搜榜单等等 ...

  10. 8000字讲透OBSA原理与应用实践

    摘要:OBSA项目是围绕OBS建立的大数据和AI生态,其在不断的发展和完善中,目前有如下子项目:hadoop-obs项目和flink-obs项目. 文章作者:存储服务产品部开发者支持团队 OBS存储服 ...