Cmake是一种跨平台的编译工具,用于构建编译配置文件,在Linux/Unix平台,生成makefile,在苹果平台,可以生成xcode,在Windows平台,可以生成MSVC的工程文件,并且对其进行编译生成相应的可执行文件或库文件。
Cmake 的工具链非常简单:cmake+make :
- cmake:构建编译配置文件
- make:编译工程
在linux系统下,我们使用下面指令下载cmake。
//下载 sudo apt install cmake //查看版本 cmake -version3. HelloWorld的内部构建 3.1 准备工作
首先,递归构建 /backup/cmake 目录,用来放置我们的cmake工程。
mkdir -p /backup/cmake
然后在cmake 目录建立第一个练习目录t1。
cd /backup/cmake mkdir t1 cd t1
在t1目录建立main.cpp 和 CMakeLists.txt:
main.cpp文件内容:
#includeusing namespace std; int main(){ cout(“Hello World from t1 Main!n”); return 0; }
CMakeLists.txt文件内容:
PROJECT (HELLO)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)
3.2 构建工程
在创建完文件之后,我们可以使用cmake指令来构建工程了,首先在这个目录运行:
cmake .
输出大概是这个样子:
– Check for working C compiler: /usr/bin/gcc
– Check for working C compiler: /usr/bin/gcc – works-- Check size of void*
– Check size of void* - done
– Check for working CXX compiler: /usr/bin/c++
– Check for working CXX compiler: /usr/bin/c++
– works-- This is BINARY dir /backup/cmake/t1
– This is SOURCE dir /backup/cmake/t1-- Configuring done
– Generating done
– Build files have been written to: /backup/cmake/t1
此时,t1目录中自动生成了CMakeFiles, CMakeCache.txt, cmake_install.cmake 等文件,并且生成了Makefile(编译文件)。
然后我们使用使用make指令进行工程的实际构建:
make
然后会得到下面的输出:
Scanning dependencies of target hello [100%]
Building C object CMakeFiles/hello.dir/main.o
Linking C executable hello [100%]
Built target hello
此时,我们需要的目标文件hello已经构建完成,位于当前目录,尝试运行一下:
./hello
得到输出:
Hello World from t1 Main!
以上就是cmake的简单使用。
3.3 指令解释我们来解释一下CMakeLists.txt的内容:
PROJECT(HELLO)
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})
- PROJECT 指令
语法:
PROJECT(projectname [CXX] [C] [Java])
该指令用于指定任意工程名称,并可以选择指定支持的语言。
这个指令隐式的定义了两个cmake 变量:_BINARY_DIR 和 _SOURCE_DIR ,对于该工程就是HELLO_BINARY_DIR 和HELLO_SOURCE_DIR(或者PROJECT_BINARY_DIR 和PROJECT_SOURCE_DIR 变量)。这两组变量是一致的,区别就是HELLO_BINARY_DIR 和HELLO_SOURCE_DIR 两个变量会根据工程名改变。
所以为了方便,我们直接使用PROJECT_BINARY_DIR 和PROJECT_SOURCE_DIR 变量是最好的。
需要说明的是,PROJECT_SOURCE_DIR指代工程路径,也就是t1,PROJECT_BINARY_DIR 指代编译路径,对于内部构建也是t1。
- SET 指令
语法:
SET(VAR [VALUE] [CACHE TYPE DOCSTRING[FORCE]])
该指令用于定义变量,如果有多个源文件,也可以定义成SET(SRC_LIST main.c t1.c t2.c) 。
- MESSAGE 指令
语法:
MESSAGE([SEND_ERROR | STATUS | FATAL_ERROR] "message to display" ...)
该指令用于向终端输出用户定义的信息,包括三种类型:
- SEND_ERROR:产生错误,生成过程被跳过。
- STATUS:输出普通状态信息。
- FATAL_ERROR:立即终止所有 cmake 过程。
- ADD_EXECUTABLE 指令
语法:
ADD_EXECUTABLE(程序名 源代码文件)
上面使用的指令是ADD_EXECUTABLE(hello ${SRC_LIST}),其实就是生成一个文件名为hello的可执行文件,相关的源文件是SRC_LIST中定义的源文件列表,等价于ADD_EXECUTABLE(hello main.c)。
本例中,我们可以看到,${}是引用变量的方式,相当于是取值运算符。如果我们IF控制语句中,我们是直接使用变量名,而不需要${}。
本例的最简化版本的CMakeLists.txt:
PROJECT(HELLO) ADD_EXECUTABLE(hello main.c)3.4 基本语法规则
CMake的语法规则如下:
- 变量使用${}方式取值,但是在IF控制语句中是直接使用变量名。
- 指令(参数1 参数2…),参数使用括号括起,参数之间使用空格或分号分开。比如:
# 下面两条指令等价 ADD_EXECUTABLE(hello main.c func.c) ADD_EXECUTABLE(hello main.c;func.c)
- 指令是大小写无关的,参数和变量是大小写相关的。但推荐你全部使用大写指令。
- 工程名和程序名是没有任何关系的,可以任意指定。
- 文件名可以有双引号,也可以没有双引号,但如果文件名中间有空格,就必须要用双引号:
# 以下两条指令等价 SET(SRC_LIST main.c) SET(SRC_LIST "main.c") # 文件名中间有空格,必须加双引号 SET(SRC_LIST “fu nc.c”)3.5 清理工程
使用make clean对构建结果进行清理:
make clean4. HelloWorld的外部构建
上面的例子展示的是内部构建,它是直接在工程目录里cmake,导致产生的临时文件都保存在工程目录,从而造成很多内存冗余。更好的做法是进行外部构建。具体如下:
- 在t1目录中创建main.c 和 CmakeLists.txt,跟上面一样。
- 在t1目录建立build目录,进入build目录,运行cmake:
mkdir build cd build cmake ..
此时我们会发现生成的编译文件makefile和其他中间文件都在build中。
- 使用make构建工程,就会在build目录中产生目标文件hello。
外部构建(也叫外部编译)的好处是对原有工程没有任何影响,且把所有的临时文件都放在编译目录build中,只要我们删除build,就可以很方便的删除所有的临时文件。
需要注意的是,PROJECT_SOURCE_DIR仍指代工程路径t1,但PROJECT_BINARY_DIR指代的是编译路径build。



