CMake使用介绍(1)
CMake历史及背景
CMake最早作为ITK(www.itk.org)组织中的项目,开始于1999年,该组织是由美国国家医学图书馆(US National library of medicine提供资金援助。ITK组织内部拥有大量的软件运行不同的平台,因此需要专门针对不同的平台编写不同的编译复杂构建系统,为了解决上述问题该组织开发出cmake构建工具。
cmake出现解决了两个问题:
1:开发者编写一种平台无关的CMakeList.txt文件定制整个软件编译流程,实现编译系统跨平台。
2:开发出了一系列命令,以简化整个编译系统,开发者只需要使用简单的命令就能构造编译系统,大大减少了代码量。
目前cmake的开发和维护工作由Kitware 公司负责,可以通过cmake --version可以查看到
CMake组成
cmake 主要是由三部分组成cmake, ctest,cpack
cmake:构建该软件的主要组成部分,包括大部分命令和功能。
ctest:cmake中的测试框架
cpack: cmake中的打包软件
cmake几乎支持市面上所有的操作系统,支持目前大部分编译器,主要支持C/C++语言。
Hello world用例
用cmake编写编译系统相比之前非常简单, 下面使用一个hello world用例简单说明
main.cpp的hello world用例:
#include <stdio.h>int main()
{printf("hello world\n");
}
在代码源目录下创建一个CMakeLists.txt,代码仅需三行:
cmake_minimum_required(VERSION 3.10)#set the project name
project(helloworld)#add the executable
add_executable(helloworld main.cpp)
- cmake_minimum_required为设置允许该工程最小的cmake版本,因为各个cmake版本之前略有差异,都是最小版本都是遵循向下兼容,需要设置满足该工程的最小版本。
- project指令为设置该工程名
- add_executable:将所需要编译成可执行文件的 cpp文件加入当中。
一般运行cmake之前创建一个build目录,build目录执行cmake ..命令生成相应的makefile文件,下面是最小生成的目录文件:
- CMakeCache.txt为cache变量保存文件,相当于配置文件,里面保存当前工程中所有cache变量及其值
- CMakeFiles: 该编译工程很多所需要的中间文件。
- Makefile: 根目录makefle
- cmake_install.cmake:编译之后的make install安装配置文件。
生成makefile之后,直接make可生成可执行文件。
整个用cmake构建的编译系统与之前相比比较简单。
CMake变量
变量在cmke中占重中之重,理解cmake变量基本能够看懂和编写cmake文件。
CMake变量划分
cmake变量主要涉及到三种类型
- 自定义变量
自定义变量顾名思义是由开发人员定义编写变量,值可由开发人员在cmake文件中进行修改访问。
- 内置变量
内置变量也成为预留变量,由cmake内部进行创建保留,内置变量基本上都是cache变量,由于表示特殊意义。
- 环境变量
环境变量即为操作系统环境变量,cmake可与之交互,获取到系统相互信息,cmake中由专有命令可与之交互。
自定义变量
自定义变量按照定义方式分为:隐式定义和显示定义
隐式定义
隐式定义调用cmake的一些特殊命令之后,由cmake帮助开发人员定义的一些变量,省去开发人员定义繁琐。
支持隐式定义的命令由project 和enable_language命令。
project命令
project命令格式为:
project(<projectname> [languageName1 languageName2 ... ] )
该命令字段主要是定义工程名,上述命令会隐式定义一些变量,以所定义的project name开头
隐式定义变量名 |
<PROJECT-NAME>_BINARY_DIR |
<PROJECT-NAME>_DESCRIPTION |
<PROJECT-NAME>_HOMEPAGE_URL |
<PROJECT-NAME>_SOURCE_DIR |
<PROJECT-NAME>_VERSION |
<PROJECT-NAME>_VERSION_MAJOR |
<PROJECT-NAME>_VERSION_MINOR |
<PROJECT-NAME>_VERSION_PATCH |
<PROJECT-NAME>_VERSION_TWEAK |
例如:
project(helloworld)
上述指令会自动添加如下变量定义:
隐式定义变量名 |
helloworld_BINARY_DIR |
helloworld_DESCRIPTION |
helloworld_HOMEPAGE_URL |
helloworld_SOURCE_DIR |
helloworld_VERSION |
helloworld_VERSION_MAJOR |
helloworld_VERSION_MINOR |
helloworld_VERSION_PATCH |
helloworld_VERSION_TWEAK |
除了上述命令还有enable_language
enable_language(<lang> [OPTIONAL] )
该 命令打开了 CMake 对参数中指定的语言的支持,支持CXX/C/Fortran/Asm,该命令会定义如下隐藏变量:
隐式定义变量名 |
CMAKE_<LANG>_COMPILER |
CMAKE_<LANG>_CPPCHECK |
CMAKE_<LANG>_CPPLINT |
CMAKE_<LANG>_CREATE_SHARED_LIBRARY |
CMAKE_<LANG>_CREATE_SHARED_MODULE |
CMAKE_<LANG>_CREATE_STATIC_LIBRARY |
CMAKE_<LANG>_FLAGS_DEBUG |
CMAKE_<LANG>_FLAGS_RELEASE |
CMAKE_<LANG>_COMPILER_AR |
… … … … |
显示定义
显示定义按照变量类型可以分为Normal变量和cache变量。
Normal变量定义
Nornal变量定义一般是采用set命令
set(<variable> <value>... [PARENT_SCOPE])
将创建<variable>变量,并将 值设置为<value>,在<variable>被设置之前, <value>会被展开。value值可以跟多个,如果是多个value,则variable变量以list形式进行保存。
PARENT_SCOPE:为变量名作用域,默认状况下变量默认作用域属于当前 CMakeLists.txt或者函数 ,如果添加PARENT_SCOPE字段命令则把一个变量的值设置到父路径或者调用函数中 。该句话貌似理解起来有点难度,下面以一个用例来说明。
Normal变量用例1
创建如下一个工程, 在父目录中创建一个CMakeLists.txt文件,同时创建一个src子目录且子目录中创建一个CMakeList.txt,如下图所示:
父目录中CMakeList.txt内容如下:
cmake_minimum_required(VERSION 3.10)set(MY_VAL "666")
message("Parent dir, MY_VAL: ${MY_VAL}")
add_subdirectory(src)
message("After src, MY_VAL: ${MY_VAL}")
父目录中创建一个MY_VAL变量值为666, 之后将添加子目录src, add_subdirectory(src)会自动搜索添加src目录中的CMakeList.txt。子目录CMakeList.txt的内容如下:
set(MY_VAL "777")
将其变量MY_VAL的值为777,查看运行结果:
会发现在src目录中修改的MY_VAL值并没有在父目录中有效。
出现这样的原因:set变量的作用域为在当前 CMakeLists.txt或者函数内,在src目录中MY_VAL相当于只修改本CMakeList.txt中的变量,并不会影响父目录中的MY_VAL的值。
出现这一问题的根本原因是:CMake会为每个CMakeList.txt文件创建各自的实例,在根目录中的CMakeList.txt称之为全局实例,而在其他目录中的称之为本地实例。其实我们可以进一步发现子目录中的CMakeList.txt创建的实例会继承相应父目录中创建的变量,并复制一份给自己使用,这样修改MY_VAL值相当于修改的是自己复制的那一份,并不影响父目录中MY_VAL的值。
Normal变量用例2
在用例1中,其实很多使用场景中子目录中的MY_VAL修改的值需要在父目录中生效,为了解决这一问题set命令添加了PARENT_SCOPE命令字段,将用例1中稍作改造,src目录中的CMakeLists.txt文件修改为:
set(MY_VAL "777" PARENT_SCOPE)
意思是MY_VAL这个变量来自于父目录中,修改的并不是本地文件中的MY_VAL。
运行结果:
可以看到上述结果修改MY_VAL值有效。
Cache变量
cache变量使用如下命令定义:
set(<variable> <value>... CACHE <type> <docstring> [FORCE])
<type> <docstring>为必选项
<type> 可以被 CMake GUI 用来选择一个窗口。
FILEPATH = 文件选择对话框。
PATH = 路径选择对话框。
STRING = 任意的字符串。
BOOL = 布尔值选择复选框。
INTERNAL = 不需要 GUI 输入端。 (适用于永久保存的变量)<docstring>常用于该变量解释说明一段文字。
[FORCE]可选项将覆盖 cache 值,常用于修改cache变量。
Cache变量作用相当于全局变量,即同一个CMake工程中所有CMakeLists.txt 都可以访问。
所有的 Cache 变量都会出现在 CMakeCache.txt 文件中。
option、find_file命令同样可以创建cache变量。
设置Cache变量值方法:
- 定义初始化: set(<variable> <value>... CACHE <type> <docstring>)。
- 直接在终端中使用 cmake -D var=value ..或者通过cmake-gui
- 使用FORCE命令字段修改已经定义Cache变量值:
set(<variable> <value>... CACHE <type> <docstring> FORCE)
一般运行中间最好不要修改,会造成通过cmake-gui或者命令行设置的值无效
Cache变量用例
将Normal变量用例进一步改进MY_VAL使用cache变量 ,则父目录中代码修改为:
cmake_minimum_required(VERSION 3.10)set(MY_VAL "666" CACHE STRING INTERNAL )
message("Parent dir, MY_VAL: ${MY_VAL}")
add_subdirectory(src)
message("After srcr, MY_VAL: ${MY_VAL}")
子目录中代码修改为:
set(MY_VAL "777" CACHE STRING INTERNAL FORCE)
运行结果:
内置变量
内置变量为cmake保留变量,可以使用cmake --help-variable-list查看到所有的变量,常用变量如下:
CMAKE_SYSTEM |
CMAKE_INCLUDE_PATH |
CAMAKE_SYSTEM_NAME |
CMAKE_LIBRARY_PATH |
CMAKE_SYSTEM_VERSION |
CMAKE_INSTALL_PREFIX |
CMAKE_SYSTEM_PROCESSOR |
PROJECT_BINARY_DIR |
UNIX |
PROJECT_SOURVE_DIR |
WIN32 |
CMAKE_CURRENT_SOURCE_DIR |
CMAKE_MAJOR_VERSION |
CMAKE_CURRENT_BINARY_DIR |
CMAKE_MINOR_VERSION |
CMAKE_PREFIX_PATH |
CMAKE_PATCH_VERSION |
CMAKE_SHARED_LIBS |
PROJECT_NAME |
CMAKE_BUILD_TYPE |
环境变量
环境变量主要涉及到cmake如何与其交互:
- 读取环境变量:$ENV{NAME}
- 设置环境变量:SET(ENV{变量名} 值)
CMake变量读取
cmake变量读取规则如下:
- 获取变量值:${}
- if 语句中直接使用变量名而不通过${}取值
CMake变量打印
CMake变量打印主要使用message
message([<mode>] "message text" ...)
mode为打印模式,针对不同的模式会有不同的动作:
mode支持打印级别 |
程序运行 |
FATTAL_ERROR |
停止运行 |
SEND_ERROR |
继续执行,但是会跳过生成的步骤 |
WARNING |
继续运行 |
AUTHOR_WARNING |
继续运行 |
DEPRECATION |
继续运行 |
(none)or NOTICE |
继续运行 |
STATUS |
继续运行 |
VERBOSE |
继续运行 |
DEBUG |
继续运行 |
TRACE |
继续运行 |
参考资料
https://cmake.org/documentation/
https://gitlab.kitware.com/cmake/community/-/wikis/home
《Mastering CMake》
CMake使用介绍(1)相关推荐
- Cmake的介绍和使用 Cmake实践 - 吾尝终日而思矣 不如须臾之所学也 - C++博客
Cmake的介绍和使用 Cmake实践 - 吾尝终日而思矣 不如须臾之所学也 - C++博客 Cmake的介绍和使用 Cmake实践 - 吾尝终日而思矣 不如须臾之所学也 - C++博客 Cmake的 ...
- CMake使用介绍(2)
如何设置编译器 实际使用过程中,尤其是嵌入式开发中,经常需要使用到交叉编译,这时就要将系统默认编译器切换到相对应的使用到的编译器,常用的编译器设置主要由一下几种方法: 1:修改系统环境变量,修改默认编 ...
- make和cmake简要介绍
GCC GCC(GNU Compiler Collection,GNU编译器套件)是由GNU开发的编程语言译器.GNU编译器套件包括C.C++. Objective-C. Fortran.Java.A ...
- make、makefile和cmake简单介绍
make.makefile和cmake的关系 cmake安装 cmake简单示例 make.makefile和cmake的关系 提到make,makefile就不得不提GNU,GNU是"GN ...
- 三、安装cmake,安装resin ,tars服务,mysql 安装介绍,安装jdk,安装maven,c++ 开发环境安装...
三.安装cmake,安装resin 2018年07月01日 21:32:05 youz1976 阅读数:308 开发环境说明: centos7.2 ,最低配置:1核cpu,2G内存,1M带宽 1.安装 ...
- cmake使用总结(转)---工程主目录CMakeList文件编写
在linux 下进行开发很多人选择编写makefile 文件进行项目环境搭建,而makefile 文件依赖关系复杂,工作量很大,搞的人头很大.采用自动化的项目构建工具cmake 可以将程序员从复杂的m ...
- 熟悉 CMake(二)—— 以一个实例说明 CMakeLists.txt 文件的编写
原文请见 cmake使用总结(转)-工程主目录CMakeList文件编写 在 Linux 下进行开发很多人选择编写 makefile 文件进行项目环境搭建,而makefile 文件依赖关系复杂,工作量 ...
- CMake Tutorial
CMake Tutorial 介绍 CMake教程提供了一个循序渐进的指南,涵盖了CMake帮助解决的常见的系统构建问题.了解示例项目中各种主题是如何一起工作的会非常有帮助.教程文档和示例源代码可以在 ...
- CMake | include_guard命令详解
目录 一.命令详解 二.简单使用 1.CMakeLists.txt 2.cmake/custom.cmake 3.配置 三.为低于3.10的版本自定义"包含保护"机制 1.cmak ...
最新文章
- linux学习-awk工具
- chrome浏览器上传文件延迟_扫描识别工具Dynamic Web TWAIN使用教程:移动浏览器捕获(下)...
- telnet或SQLplus下命令输入错误如何删掉重新输入
- linux 配置思科路由器,将配置文件导入cisco2611路由器步骤
- python线程池模块第三方包_python线程池(threadpool)模块使用笔记详解
- confirm的意思中文翻译_confirm的中文意思
- Ubuntu20.04安装eBPF BCC
- 深入浅出 SSL 管理配置实战
- 摄影测量学知识点总结(万字长文警告)
- 有关微信小程序云数据库修改数据的坑
- Failed to load C:\SDK\android-sdk-windows\build-tools\27.0.2\lib\dx.jar
- 职场“巨婴”,毁人不倦
- 一分钟集成类似抖音、头条、腾讯视频、网易新闻、飞猪、咸鱼等常用标题栏
- C/C++基础查漏补缺(一)----------寒假学习笔记(一)
- Cat.1、Cat.4、4G之间的区别
- 了解一下winsock
- 磁共振功能成像BOLD-fMRI原理
- LeetCode 796. 旋转字符串
- 铁道部新客票系统设计(一)
- Linux信号量与互斥锁解决生产者与消费者问题