03 最小CMake项目
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
部分。在大多数项目中,不需要patch
和tweak
部分,这些通常只出现在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()
命令中。如果在项目生命周期的后期,要克服现有流程的惯性来改变项目的版本号,可能会很困难。
03 最小CMake项目的更多相关文章
- 直接在CMake项目中编译GoogleTest和GoogleMock作为项目的一部分
直接在CMake项目中编译GoogleTest和GoogleMock作为项目的一部分 本文是关于如何将GoogleTest和GoogleMock在没有预先编译安装在机器的情况下,直接在项目中作为项目的 ...
- 通过例子进阶学习C++(七)CMake项目通过模板库实现约瑟夫环
本文是通过例子学习C++的第七篇,通过这个例子可以快速入门c++相关的语法. 1.问题描述 回顾一下约瑟夫环问题:n 个人围坐在一个圆桌周围,现在从第 s 个人开始报数,数到第 m 个人,让他出局:然 ...
- Visual Studio CMake 项目和 WSL
Visual Studio CMake 项目和 WSL https://devblogs.microsoft.com/cppblog/c-with-visual-studio-2019-and-win ...
- Flutter 即学即用系列博客——03 在旧有项目引入 Flutter
前言 其实如果打算在实际项目中引入 Flutter,完全将旧有项目改造成纯 Flutter 项目的可能性比较小,更多的是在旧有项目引入 Flutter. 因此本篇我们就说一说如何在旧有项目引入 Flu ...
- hge引擎示例教程cmake项目
hge引擎的示例代码在vs2017不能很好的运行,需要调不少东西,所以我将其重新整理成cmake的项目. 所有示例均在vs2017 msvc 下测试可以正常运行. 由于缺少libhgehelp.a所以 ...
- Qt Creator 源码学习笔记03,大型项目如何管理工程
阅读本文大概需要 6 分钟 一个项目随着功能开发越来越多,项目必然越来越大,工程管理成本也越来越高,后期维护成本更高.如何更好的组织管理工程,是非常重要的 今天我们来学习下 Qt Creator 是如 ...
- 「Python实用秘技03」导出项目的极简环境依赖
本文完整示例代码及文件已上传至我的Github仓库https://github.com/CNFeffery/PythonPracticalSkills 这是我的系列文章「Python实用秘技」的第3期 ...
- ASP.NET Core Web API 最小化项目
ASP.NET Core中默认的ASP.NET Core 模板中有Web API 模板可以创建Web API项目. 有时,只需要创建一个API,不需要关心Razor,本地化或XML序列化.通过删除无用 ...
- Qt Creator下应用CMake项目调试mex文件
网上可以找到很多应用Visual Studio编写.编译mex文件,并与MATLAB联合调试的文章.但这只限于Win平台,网上许多源码都是.mexa64的文件,它们的作者是怎么调试的呢?这里我介绍一下 ...
随机推荐
- 不要让Microsoft edge 打开IE浏览器的设置(兼容性问题)
1打开Microsoft edge 2 打开设置 3 搜索栏搜索IE,打开即可
- NC202498 货物种类
NC202498 货物种类 题目 题目描述 某电商平台有 \(n\) 个仓库,编号从 \(1\) 到 \(n\) . 当购进某种货物的时候,商家会把货物分散的放在编号相邻的几个仓库中. 我们暂时不考虑 ...
- charles(CA证书)的app端安装
在使用charles进行的app抓包的时候势必需要对他进行配置: 1. pc端: 第一步: http请求接收charles > proxy > proxy setting > por ...
- 如何准备论文线上Presentation视频录制教程(Summary of Video Recording)
0:前言 由于国外的疫情严重,目前大多数学术会议都是线上举办,因此往往需要制作presentation的视频录制.由于各种软件横飞,有的需要会员并且不熟悉操作,特别浪费时间.因此,我将这次的操作和遇到 ...
- centos7 nginx 域名能ping通,但无法打开网页
方法一:关闭防火墙 sudo systemctl stop firewalld.service 方法二:容许80端口访问 vim打开iptables, 命令如下: #vim /etc/sysconfi ...
- python测试开发django-197.django-celery-beat 定时任务
前言 django-celery-beat 可以支持定时任务,把定时任务写到数据库. 接着前面这篇写python测试开发django-196.python3.8+django2+celery5.2.7 ...
- 【docker专栏6】详解docker容器状态转换管理命令
docker容器有三种状态运行.停止.暂停,镜像可以创建.运行容器,镜像和容器也可以转换成tar压缩包进行存储.本文为大家介绍容器的状态转换命令及镜像创建运行容器.tar包导入导出相关的命令及使用场景 ...
- [ZJCTF 2019]NiZhuanSiWei 1
考察知识点:反序列化.php伪协议 1.打开之后获得源码信息,如下: <?php $text = $_GET["text"]; $file = $_GET["fil ...
- 无需CORS,用nginx解决跨域问题,轻松实现低代码开发的前后端分离
近年来,前后端分离已经成为中大型软件项目开发的最佳实践. 在技术层面,前后端分离指在同一个Web系统中,前端服务器和后端服务器采用不同的技术栈,利用标准的WebAPI完成协同工作.这种前后端分离的&q ...
- 时间模块之datatime模块、os模块、sys模块、json模块、json模块实操
目录 一.模块的绝对导入和相对导入 二.包的概念 三.编程思想的转变 四.软件开发目录规范 五.常见的内置模块 一.时间模块之datatime模块 1.datetime.datetime.today( ...