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等。