CMake is an open-source, cross-platform family of tools designed to build, test and package software.


第一个例子:

1
2
3
4
cmake_minimum_required (VERSION 3.12.2)

project (Demo1)
add_executable(Demo main.cc)

cmake_minimum_required CMake 最低版本号要求。

project 指定项目信息。

add_executable 指定生成目标,将名为 main.cc 的源文件编译成名称为 Demo 的可执行文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-- The C compiler identification is AppleClang 9.1.0.9020039
-- The CXX compiler identification is AppleClang 9.1.0.9020039
-- Check for working C compiler: /Library/Developer/CommandLineTools/usr/bin/cc
-- Check for working C compiler: /Library/Developer/CommandLineTools/usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /Library/Developer/CommandLineTools/usr/bin/c++
-- Check for working CXX compiler: /Library/Developer/CommandLineTools/usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/darion.yaphet/source/cmake-demo/Demo1

当前目录执行 cmake . ,得到 Makefile 后再使用 make 命令编译得到 Demo1 可执行文件。

1
2
3
4
Scanning dependencies of target Demo
[ 50%] Building CXX object CMakeFiles/Demo.dir/main.cc.o
[100%] Linking CXX executable Demo
[100%] Built target Demo

aux_source_directory 会查找指定目录下的所有源文件,然后将结果存进指定变量名。

1
aux_source_directory(<dir> <variable>)

The ctest is the CMake test driver program. CMake-generated build trees created for projects that use the ENABLE_TESTING and ADD_TEST commands have testing support.


基本语法规则

  • 变量使用${}方式取值,但是在 IF 控制语句中是直接使用变量名
  • 指令(参数 1 参数 2…) 参数之间使用空格或分号分开
  • 指令是大小写无关的,参数和变量是大小写相关的。

指令 语法 介绍
PROJECT PROJECT(projectname [CXX] [C] [Java]) 定义工程名称,并可指定工程支持的语言。
SET SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]]) 显式定义变量
MESSAGE MESSAGE(STATUS “message to display”…) 向终端输出信息
ADD_EXECUTABLE ADD_EXECUTABLE(hello ${SRC_LIST}) 生成一个可执行文件
ADD_SUBDIRECTORY ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL]) 向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制存放位置
SUBDIRS SUBDIRS(dir1 dir2…) 不推荐 一次添加多个子目录

set( CMAKE_BUILD_TYPE "Debug" ) 设置Debug模式。

STREQUAL 是 CMAKE 的关键字,用于字符串比较,相同返回 true。

include(CMakeParseArguments) 使用 cmake_parse_arguments(),是用来解析输入参数的。

变量

CMake基本数据类型是字符串,一组字符串在一起称为列表。
1, ON, YES, TRUE, Y, 非0的数为
0, OFF, NO, FALSE, N, IGNORE, 空字符串,以-NOTFOUND结尾的字符串为

变量显式定义 :

1
2
set(VAR a b c)
message("VAR = ${VAR}")
指令 语法
CMAKE_C_COMPILER 指定C编译器
CMAKE_CXX_COMPILER 指定C++编译器
CMAKE_C_FLAGS 指定编译C文件时的编译选项
EXECUTABLE_OUTPUT_PATH 指定可执行文件的存放路径,最终结果的存放目录
LIBRARY_OUTPUT_PATH 指定库文件存放路径,最终结果的存放目录
CMAKE_BUILD_TYPE build类型(Debug\Release)
BUILD_SHARED_LIBS 指定编译成静态库还是动态库
BUILD_LIBS
CMAKE_BINARY_DIR 工程顶层目录(内部构建),工程编译发生的目录(外部构建)
PROJECT_BINARY_DIR CMAKE_BINARY_DIR
CMAKE_SOURCE_DIR 工程源代码文件所在的目录,指的是工程顶层目录
PROJECT_SOURCE_DIR 工程源代码文件所在的目录,指的是工程顶层目录
CMAKE_CURRENT_SOURCE_DIR 当前处理的CMakeLists.txt所在的路径
CMAKE_CURRRENT_BINARY_DIR 如果是in-source编译,则跟CMAKE_CURRENT_SOURCE_DIR一致;如果是out-of-source,指的是target编译目录;
CMAKE_CURRENT_LIST_FILE 输出调用这个变量的CMakeLists.txt的完整路径
CMAKE_CURRENT_LIST_LINE 输出这个变量所在的行
CMAKE_MODULE_PATH 设置搜索CMakeModules模块(.cmake)的额外路径,用来定义自己的cmake模块所在的路径
EXECUTABLE_OUTPUT_PATH 指定可执行文件的存放路径,最终结果的存放目录;
LIBRARY_OUTPUT_PATH 指定库文件存放路径,最终结果的存放目录;
PROJECT_NAME 工程名称,即使用PROJECT命令设置的名称;
CMAKE_CXX_FLAGS_DEBUG 用于 debug 的编译选项
CMAKE_C_FLAGS_DEBUG 用于 debug 的编译选项
CMAKE_CXX_FLAGS_RELEASE 用于 release 的编译选项
CMAKE_C_FLAGS_RELEASE 用于 release 的编译选项
CMAKE_MAJOR_VERSION CMake主版本号
CMAKE_MINOR_VERSION CMake次版本号
CMAKE_PATCH_VERSION CMake补丁等级
CMAKE_SYSTEM 系统名称,如Linux-2.6.22
CMAKE_SYSTEM_NAME 不包含版本的系统名,如Linux
CMAKE_SYSTEM_VERSION 系统版本,如2.6.22
CMAKE_SYSTEM_PROCESSOR 处理器名称,如i686
UNIX 所有的类UNIX平台为TRUE,包括OS X和cygwin
WIN32 所有的win32平台为TRUE,包括cygwin

函数

1
2
3
function(函数名 参数名)
...
endfunction()

1
2
3
macro(宏名 参数)
...
endmacro()

文件操作命令

FILE(WRITE filename “message towrite”… )

WRITE 将一则信息写入文件’filename’中,如果该文件存在,它会覆盖它,如果不存在,它会创建该文件。

FILE(APPEND filename “message to write”… )

APPEND 如同WRITE,区别在于它将信息内容追加到文件末尾。

FILE(READ filename variable [LIMIT numBytes] [OFFSEToffset] [HEX])

READ 会读取文件的内容并将其存入到变量中。它会在给定的偏移量处开始读取最多numBytes个字节。如果指定了HEX参数,二进制数据将会被转换成十进制表示形式并存储到变量中。

FILE(<MD5|SHA1|SHA224|SHA256|SHA384|SHA512> filenamevariable)

MD5, SHA1, SHA224, SHA256, SHA384, 和SHA512 会计算出文件内容对应的加密散列。


CTest


CMake time & configure time CMake will process the CMakeLists.txt files in your project and
configure it.

Generation time CMake will generate the scripts needed by the native build tools to perform subsequent steps in the project.

Build time native build tools are invoked on the platformand tool-native build scripts previously generated by CMake.

CTest time or test time run the test suite of the project to check whether the targets perform as intended.

CDash time or report time results of testing the project are uploaded to a dashboard to be shared with other developers.

Install time project’s targets, source files, executables, and libraries are installed from the build directory to an install location.

CPack time or packaging time package our project for distribution, either as source code or binary.

Package install time newly minted package is installed system-wide.


Cmake Cookbook

cmake --build . --target help


Discovering the operating system

1
2
3
4
5
6
7
8
9
10
11
12
# print custom message depending on the operating system
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
message(STATUS "Configuring on/for Linux")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
message(STATUS "Configuring on/for macOS")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
message(STATUS "Configuring on/for Windows")
elseif(CMAKE_SYSTEM_NAME STREQUAL "AIX")
message(STATUS "Configuring on/for IBM AIX")
else()
message(STATUS "Configuring on/for ${CMAKE_SYSTEM_NAME}")
endif()

Commands

add_custom_command

添加一条自定义的构建规则 生成输出文件或是添加一条自定义命令

  • PRE_BUILD 在所有其它的依赖之前执行
  • PRE_LINK 在所有其它的依赖之后执行
  • POST_BUILD 在目标被构建之后执行

add_custom_target

添加一个目标,它没有输出;这样它就总是会被构建

add_definitions

为源文件的编译添加由-D引入的define flag

add_dependencies

为顶层目标引入一个依赖关系

add_executable

使用给定的源文件,为工程引入一个可执行文件

add_library

使用指定的源文件向工程中添加一个库

add_subdirectory

为构建添加一个子路径

add_test

以指定的参数为工程添加一个测试

aux_source_directory

查找在某个路径下的所有源文件

break

从foreach或while循环中跳出

build_command

获取构建该工程的命令行

cmake_minimum_required

设置一个工程所需要的最低CMake版本

cmake_policy

管理CMake的策略设置

configure_file

将一份文件拷贝到另一个位置并修改它的内容

create_test_sourcelist

为构建测试程序创建一个测试驱动器和源码列表

define_property

定义并描述(Document)自定义属性

else

开始一个if语句块的else部分

elseif

开始 if 块的 elseif 部分

enable_language

支持某种语言

enable_testing

打开当前及以下目录中的测试功能

endforeach

结束foreach语句块中的一系列命令

endfunction

结束一个function语句块中的一系列命令

endif

结束一个if语句块中的一系列命令

endmacro

结束一个macro语句块中的一系列命令

endwhile

结束一个while语句块中的一系列命令

execute_process

执行一个或更多个子进程

export

从构建树中导出目标供外部使用

file

文件操作命令

find_file

查找一个文件的完整路径

find_library

查找一个库文件

find_package

为外部工程加载设置

find_path

搜索包含某个文件的路径

find_program

查找可执行程序

fltk_wrap_ui

创建FLTK用户界面包装器

find_program

查找可执行程序

fltk_wrap_ui

创建FLTK用户界面包装器

foreach

对一个list中的每一个变量执行一组命令

function

开始记录一个函数,为以后以命令的方式调用它做准备

get_cmake_property

获取一个CMake实例的属性

get_directory_property

获取DIRECTORY域中的某种属性

get_filename_component

得到一个完整文件名中的特定部分

get_property

获取一个属性值

get_source_file_property

为一个源文件获取一种属性值

get_target_property

从一个目标中获取一个属性值

get_test_property

获取一个测试的属性

if

执行一组命令

include

从给定的文件中读取CMake的列表文件

include_directories

为构建树添加包含路径

include_external_msproject

在一个workspace中包含一个外部的Microsoft工程

include_regular_expression

设置用于依赖性检查的正则表达式

install

指定在安装时要运行的规则

link_directories

指定连接器查找库的路径

list

列表操作命令

load_cache

从另一个工程的CMake cache中加载值

load_command

将一条命令加载到一个运行中的CMake

macro

为后续以命令方式调用而开始记录一组宏

mark_as_advanced

将CMake 的缓存变量标记为高级

math

数学表达式

message

为用户显示一条消息

option

为用户提供一个可选项

output_required_files

输出一个list,其中包含了一个给定源文件所需要的其他源文件

project

为整个工程设置一个工程名

qt_wrap_cpp

创建Qt包裹器

qt_wrap_ui

创建Qt的UI包裹器

remove_definitions

取消由add_definitions命令添加的-D定义标志

return

从一个文件,路径或函数内返回

separate_arguments

将空格分隔的参数解析为一个分号分隔的list

set

将一个CMAKE变量设置为给定值

set_directory_properties

设置某个路径的一种属性

set_property

在给定的作用域内设置一个命名的属性

set_source_files_properties

源文件有一些属性来可以改变它们构建的方式

set_target_properties

设置目标的一些属性来改变它们构建的方式

set_tests_properties

设置若干个测试的属性值

site_name

将给定的变量设定为计算机名

source_group

为Makefile中的源文件定义一个分组

string

字符串操作函数

target_link_libraries

将给定的库链接到一个目标上

try_compile

尝试编译一些代码

try_run

尝试编译并运行某些代码

unset

撤销对一个变量,cache变量或者环境变量的设置

variable_watch

监视CMake变量的改变

while

当条件为真时,执行一组命令


find_package

CMake本身不提供任何搜索库的便捷方法,所有搜索库并给变量赋值的操作必须由CMake代码完成。

find_package采用两种模式搜索库:

  1. Module模式:搜索CMAKE_MODULE_PATH指定路径下的FindXXX.cmake文件,执行该文件从而找到XXX库。
  2. Config模式:搜索XXX_DIR指定路径下的XXXConfig.cmake文件,执行该文件从而找到XXX库。

CMake默认采取Module模式,如果Module模式未找到库,才会采取Config模式。

如果XXX_DIR路径下找不到XXXConfig.cmake文件,则会找/usr/local/lib/cmake/XXX/中的XXXConfig.cmake文件。


Reference:

  1. CMake 入门实战
  2. cmake-tutorial
  3. CMake构建系统的骨架
  4. CMake Practice.pdf
  5. cmake-cookbook.pdf
  6. CMake代码示例
  7. cmake使用示例与整理总结
  8. Cmake之深入理解find_package的用法
  9. CMake如何查找链接库