cmake学习笔记
1. 什么是cmake
cmake是用于构建和管理中、大型开发项目(c、c++或者java)的一种工具,它简化工程的管理为一个CMakeLists.txt文件的管理,具有以下特点:
- 开放源代码,使用类BSD许可发布 http://cmake.org/HTML/Copyright.html
- 跨平台,并可生成native编译配置文件,在Linux/Unix平台,生成makefile,在苹果平台,可以生成xcode,在Windows平台,可以生成MSVC的工程文件。
- 能够管理大型项目,KDE4就是最好的证明。
- 简化编译构建过程和编译过程。Cmake的工具链非常简单:cmake+make。
- 高效虑,按照KDE官方说法,CMake构建KDE4的kdelibs要比使用autotools来 构建KDE3.5.6的kdelibs快40% ,主要是因为 Cmake在工具链中没有libtool。
- 可扩展,可以为cmake编写特定功能的模块,扩充cmake功能。
如何用好cmake?
- 我们需要学习cmake语言和语法;
- 学会编写自己项目的CMakeLists.txt文件;
- 在工程中不断实践。
cmake的不足
cmake跟已有体系的配合并不是特别理想,比如pkgconfig,您在实际使用中会有所 体会,虽然有一些扩展可以使用,但并不理想。
2. cmake基础语法
下面以一个实现控制台窗口输出 hello world 的CMakeLists.txt文件为例说明cmake的基础语法
# 声明要求的cmake最低版本
cmake_minimum_required(VERSION 2.8)
#声明一个cmake工程,这个工程名和可执行文件的名字没有关系,只是cmake工程的名字
project(HELLO)
# 添加一个可执行文件,语法: add_executable (程序名 源代码文件) 。 多个源代码文件用空格或者分号隔开,源代码后
#缀名(如.cpp)可以省略但不建议这么做。也可以使用SRC_LIST组织多个源文件后整体加入到程序中,
# 语法:SET(SRC_LIST main.c)
# MESSAGE(STATUS "This is BINARY dir " ${HELLO_BINARY_DIR})
# MESSAGE(STATUS "This is SOURCE dir "${HELLO_SOURCE_DIR})
# ADD_EXECUTABLE(hello ${SRC_LIST}) 注意cmake的保留字不区分大小写,变量名和工程名区分!
add_executable(hello main.cpp)
我们来重新看一下CMakeLists.txt,这个文件是cmake的构建定义文件,文件名是大小写相关的,如果工程存在多个目录,需要确保每个要管理的目录都存在一个 CMakeLists.txt。(关于多目录构建,后面我们会提到)。
指令名 | 语法 |
---|---|
project | PROJECT(projectname [CXX] [C] [Java]) 。这个指令隐式的定义了两个cmake变量<projectname>_BINARY_DIR以及<projectname>_SOURCE_DIR 1 |
set | SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])2 |
message | MESSAGE([SEND_ERROR |
add_executable | ADD_EXECUTABLE(hello ${SRC_LIST})或者ADD_EXECUTABLE(hello main.cpp)3 |
add_subdirectory | ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL]) |
- project指令的语法
- message语法
- set语法
- add_executable语法
3. 语法规则
基本规则:
- 变量使用${}方式取值,IF后面的括号中的值除外;
- 指令(参数1 参数2…);
- 指令是大小写无关的,参数和变量是大小写相关的。个人认为自己统一风格即可。
内部构建与外部构建
- 内部构建,即将工程编译链接生成的所有文件放在与源代码和CMakeLists.txt同样的文件路径下。这样做不利于我们管理工程,因为中间文件太多了,与源代码混在一起不利于管理。
- 外部构建,可以很好的解决内部构建的问题。CMakeLists.txt文件还是和源代码在同一文件夹下。新建一个 build 文件夹,将编译链接生成的结果和中间文件都保存在build文件夹下。这样的构建成为外部构建。
参考资料
[1] 《cmake实践》
[2] 《视觉SLAM十四讲》
为了统一起见,建议以后直接使用PROJECT_BINARY_DIR,PROJECT_SOURCE_DIR,即使修改了工程名称,也不会影响这两个变量。 ↩︎
现阶段,你只需要了解SET指令可以用来显式的定义变量即可。 比如我们用到的是SET(SRC_LIST main.c),如果有多个源文件,也可以定义成: SET(SRC_LIST main.c t1.c t2.c)。 ↩︎
在本例我们使用了 ${} 来引用变量,这是cmake的变量应用方式,但是,有一些例外,比如在IF控制语句,变量是直接使用变量名引用,而不需要${}。如果使用了${}去应用变 量,其实IF会去判断名为${}所代表的值的变量,那当然是不存在的了。 ↩︎