CMake最早作为ITK(www.itk.org)组织中的项目,开始于1999年,该组织是由美国国家医学图书馆(US National library of medicine提供资金援助。ITK组织内部拥有大量的软件运行不同的平台,因此需要专门针对不同的平台编写不同的编译复杂构建系统,为了解决上述问题该组织开发出cmake构建工具。
cmake出现解决了两个问题:
1:开发者编写一种平台无关的CMakeList.txt文件定制整个软件编译流程,实现编译系统跨平台。
2:开发出了一系列命令,以简化整个编译系统,开发者只需要使用简单的命令就能构造编译系统,大大减少了代码量。
目前cmake的开发和维护工作由Kitware 公司负责,可以通过cmake --version可以查看到
cmake 主要是由三部分组成cmake, ctest,cpack
cmake:构建该软件的主要组成部分,包括大部分命令和功能。
ctest:cmake中的测试框架
cpack: cmake中的打包软件
cmake几乎支持市面上所有的操作系统,支持目前大部分编译器,主要支持C/C++语言。
用cmake编写编译系统相比之前非常简单, 下面使用一个hello world用例简单说明
main.cpp的hello world用例:
#include
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之前创建一个build目录,build目录执行cmake ..命令生成相应的makefile文件,下面是最小生成的目录文件:
生成makefile之后,直接make可生成可执行文件。
整个用cmake构建的编译系统与之前相比比较简单。
变量在cmke中占重中之重,理解cmake变量基本能够看懂和编写cmake文件。
cmake变量主要涉及到三种类型
自定义变量顾名思义是由开发人员定义编写变量,值可由开发人员在cmake文件中进行修改访问。
内置变量也成为预留变量,由cmake内部进行创建保留,内置变量基本上都是cache变量,由于表示特殊意义。
环境变量即为操作系统环境变量,cmake可与之交互,获取到系统相互信息,cmake中由专有命令可与之交互。
自定义变量按照定义方式分为:隐式定义和显示定义
隐式定义调用cmake的一些特殊命令之后,由cmake帮助开发人员定义的一些变量,省去开发人员定义繁琐。
支持隐式定义的命令由project 和enable_language命令。
project命令
project命令格式为:
project(<projectname> [languageName1 languageName2 ... ] )
该命令字段主要是定义工程名,上述命令会隐式定义一些变量,以所定义的project name开头
隐式定义变量名 |
|
|
|
|
|
|
|
|
|
例如:
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_ |
CMAKE_ |
CMAKE_ |
CMAKE_ |
CMAKE_ |
CMAKE_ |
CMAKE_ |
CMAKE_ |
CMAKE_ |
… … … … |
显示定义按照变量类型可以分为Normal变量和cache变量。
Nornal变量定义一般是采用set命令
set(
]) ... [PARENT_SCOPE
将创建
PARENT_SCOPE:为变量名作用域,默认状况下变量默认作用域属于当前 CMakeLists.txt或者函数 ,如果添加PARENT_SCOPE字段命令则把一个变量的值设置到父路径或者调用函数中 。该句话貌似理解起来有点难度,下面以一个用例来说明。
创建如下一个工程, 在父目录中创建一个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的值。
在用例1中,其实很多使用场景中子目录中的MY_VAL修改的值需要在父目录中生效,为了解决这一问题set命令添加了PARENT_SCOPE命令字段,将用例1中稍作改造,src目录中的CMakeLists.txt文件修改为:
set(MY_VAL "777" PARENT_SCOPE)
意思是MY_VAL这个变量来自于父目录中,修改的并不是本地文件中的MY_VAL。
运行结果:
可以看到上述结果修改MY_VAL值有效。
cache变量使用如下命令定义:
set(
CACHE ... < docstring> [FORCE])
< 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(
一般运行中间最好不要修改,会造成通过cmake-gui或者命令行设置的值无效
将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如何与其交互:
cmake变量读取规则如下:
CMake变量打印主要使用message
message([
] "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》