Introduction
CMake是一个编译系统生成工具,而非编译系统。CMake能够生成编译系统的输入文件如Makefile
,CMake本身支持Make/Ninja/Visual Studio/XCode
等。
CMake是跨平台的,支持Linux、Windows、OSX等,同时也支持跨平台构建(编译器要支持跨平台才可以哦)。
CMake开始于1999/2000年,现代CMake开始于2014年的3.0
版本,现代CMake有一个非常重要的概念,Everything is a (self-contained) target
。
Everything that is needed to (successfully) build that target.
Everything that is needed to (successfully) use that target.
Let’s Go
时刻牢记以下三句话。
- Declare a target
- Declare target’s traits
- It’s all about targets
Minimum Version
1 | cmake_minimum_required(VERSION 3.5) |
Setting a Project
1 | project(hello-world VERSION 1.0 |
Making an Executable
1 | add_executable(one two.cpp three.h) |
one
既是生成的可执行程序也是Target,后续为源文件列表和头文件列表,大多数情况下,头文件将会被忽略,只是为了让他们显示在IDE中。
Making an Library
1 | ## BUILD_SHARED_LIBS |
Target
1 | target_include_directories(ont PUBLIC include) |
PUBLIC
意味着所有链接到此目标的目标都需要包含include
目录,PRIVATE
表示只有当前target需要,依赖项不需要,INTERFACE
表示只有依赖项许需要。
1 | add_library(another STATIC another.cpp another.h) |
target_include_directories
指定了target包含的头文件路径。target_link_libraries
指定了target链接的库。target_compile_options
指定了taget的编译选项。
target由add_library()
和add_executable()
生成。
我们以如下工程目录介绍PUBLIC/PRIVATE/INTERFACE
。
1 | cmake-test/ 工程主目录,main.c 调用 libhello-world.so |
其调用关系如下所示
1 | ├────libhello.so |
PRIVATE
:生成libhello-world.so
时,只在hello_world.c
中包含了hello.h
,libhello-world.so
对外的头文件hello_world.h
不包含hello.h
,并且main.c
不调用hello.c
中的函数,那么应当用PRIVATE
。
1 | target_link_libraries(hello-world PRIVATE hello) |
INTERFACE
:生成libhello-world.so
时,只在libhello-world.so
对外的头文件hello_world.h
包含hello.h
,hello_world.c
不包含hello.h
即libhello-world.so
不使用libhello.so
提供的功能,只需要hello.h
中定义的结构体/类等类型信息,但main.c
需要调用hello.c
中的函数即libhello.so
中的函数,那么应当用INTERFACE
。
1 | target_link_libraries(hello-world INTERFACE hello) |
PUBLIC
:生成libhello-world.so
时,在libhello-world.so
对外的头文件hello_world.h
包含hello.h
,hello_world.c
也包含hello.h
即libhello-world.so
使用libhello.so
提供的功能,并且main.c
需要调用hello.c
中的函数即libhello.so
中的函数,那么应当用PUBLIC
。
1 | target_link_libraries(hello-world PUBLIC hello) |
着重理解依赖传递的概念,main.c
依赖于libhello-world.so
,libhello-world.so
依赖于libhello.so
和libworld.so
,若main.c
不调用libhello.so
中的功能,则hello-world
与hello
之间采用PRIVATE
。若main.c
调用libhello.so
中的函数,但libhello-world.so
不调用,则用INTERFACE
。若main.c
和libhello-world.so
都调用libhello.so
的函数,则使用PUBLIC
关键字。
可以参考C++继承中PRIVATE/PROTECTED/PUBLIC
的概念1。
Variables
Local Variables
1 | set(VAR1 "local variable") |
Cache Variables
1 | set(VAR2 |
命令行调用之后,会将该变量写入CMakeCache.txt
,之后调用若不从命令行重新赋值,则会一直采用Cache中的值。
1 | mkdir build && cd build |
bool
类型的变量常用OPTION表示,OPTION也可以看作cache变量的一种,所以会写进CMakeCache.txt
。
1 | OPTION(VAR3 "description" OFF/ON) |
cmake的一些常见变量见官网2。
Environment Variables
1 | set(ENV{variable_name} value) |
Properties
1 | set_property(TARGET TargetName PROPERTY CXX_STANDARD 11) |
Control Flow
1 | if(${variable}) |
Function
1 | function(SIMPLE_FUNC) |
其他控制逻辑有NOT/TARGET/EXISTS/DEFINED/AND/OR/STREQUAL/MATCHES/VERSION_LESS/VERSION_LESS_EQUAL
等。