编译工具:CMake(二)| 最简单的实例[构建、解析、外部构建]
- 编写代码与文件
- 构建工程
- 解析
- PROJECT 指令的语法是:
- SET 指令的语法是:
- MESSAGE 指令的语法是:
- ADD_EXECUTABLE 指令
- `${}` 指令
- 外部构建
# 前言
按照程序员惯例,从 hello world
开始构建一个最简单的实例。演练一下 cmake 的完整构建过程 , 并加以解释。
编写代码与文件
首先,在/Compilation_tool
目录建立一个 cmake
目录
mkdir -p /Compilation_tool/cmake
然后在 cmake
建立第一个练习目录 test1
cd Compilation_tool/cmake
mkdir test1
cd test1
在 test1 目录建立 main.c 和 CMakeLists.txt(注意文件名大小写):
main.c 文件内容:
//main.c
#include <stdio.h>
int main()
{
printf(“Hello World from test1 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})
构建工程
所有的文件创建完成后,test1 目录中应该存在 main.c
和 CMakeLists.txt
两个文件接下来构建这个工程,在test1 这个目录运行:
cmake .
注意命令后面的点号,代表本目录
终端输出:
CMake Warning (dev) at CMakeLists.txt:4:
Syntax Warning in cmake code at column 37
Argument not separated from preceding token by whitespace.
This warning is for project developers. Use -Wno-dev to suppress it.
– This is BINARY dir /home/jk-jone/Compilation_tool/cmake/test1
– This is SOURCE dir /home/jk-jone/Compilation_tool/cmake/test1
– Configuring done
– Generating done
– Build files have been written to: /home/jk-jone/Compilation_tool/cmake/test1
出现:
– Configuring done
– Generating done
– Build files have been written to: /home/jk-jone/Compilation_tool/cmake/test1
表示没有问题。
在看test1路径下面,多了些文件
CMakeFiles
, CMakeCache.txt
, cmake_install.cmake
等文件,并且生成了
Makefile
.
不需要理会这些文件的作用,是自动生成的过程文件。最关键的是,它自动生成了Makefile
,也不用管文件里面的内容。
然后进行工程的实际构建,在/test1这个目录输入 make 命令
make
终端输出:
Scanning dependencies of target hello
[ 50%] Building C object CMakeFiles/hello.dir/main.c.o
[100%] Linking C executable hello
[100%] Built target hello
如果你需要看到 make 构建的详细过程,可以使用 make VERBOSE=1 或者 VERBOSE=1 make 命令来进行构建。
make VERBOSE=1
VERBOSE=1 make
这时候,我们需要的目标文件 hello 已经构建完成,位于当前目录,
尝试运行一下:
./hello
终端输出:
Hello World from test1 Main!
最简单的实例已搭建成功
解析
下面来解析下CMakeLists.txt文件中的CMake语句
CMakeLists.txt,这个文件是 cmake 的构建定义文件,文件名是大小写相关的
文件的内容如下:
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 变量:
<projectname>_BINARY_DIR
<projectname>_SOURCE_DIR
本工程里就是HELLO_BINARY_DIR
和 HELLO_SOURCE_DIR
(所以 CMakeLists.txt 中两个 MESSAGE指令可以直接使用了这两个变量),因为采用的是内部编译,两个变量目前指的都是工程所在路径/Compilation_tool/cmake/test1,外部编译,两者所指代的内容会有所不同。
同时 cmake 系统也帮助我们预定义了 PROJECT_BINARY_DIR
和 PROJECT_SOURCE_DIR
变量,他们的值分别跟HELLO_BINARY_DIR
与 HELLO_SOURCE_DIR
一致。
为了统一起见,建议以后直接使用 PROJECT_BINARY_DIR
,PROJECT_SOURCE_DIR
,即使修改了工程名称,也不会影响这两个变量。
如果使用了<projectname>_SOURCE_DIR
,修改工程名称后,需要同时修改这些变量。
SET 指令的语法是:
SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])
SET 指令可以用来显式的定义变量。
我们用到的是 SET(SRC_LIST main.c),如果有多个源文件,也可以定义成:
SET(SRC_LIST main.c t1.c t2.c)
MESSAGE 指令的语法是:
MESSAGE([SEND_ERROR | STATUS | FATAL_ERROR] "message to display" ...)
这个指令用于向终端输出用户定义的信息,包含了三种类型:
- SEND_ERROR,产生错误,生成过程被跳过
- SATUS ,输出前缀为–的信息
- FATAL_ERROR,立即终止所有 cmake 过程
我们在这里使用的是 STATUS 信息输出,演示了由 PROJECT 指令定义的两个隐式变量HELLO_BINARY_DIR
和 HELLO_SOURCE_DIR
。
ADD_EXECUTABLE 指令
ADD_EXECUTABLE(hello ${SRC_LIST})
定义了这个工程会生成一个文件名为 hello 的可执行文件,相关的源文件是 SRC_LIST 中定义的源文件列表,
本例也可以直接写成
ADD_EXECUTABLE(hello main.c)
${}
指令
在本例我们使用了${}
来引用变量,这是 cmake 的变量应用方式,但是,有一些例外,比如在 IF 控制语句,变量是直接使用变量名引用,而不需要${}
。如果使用了${}
去应用变量,其实 IF 会去判断名为${}
所代表的值的变量,那当然是不存在的了。
外部构建
上面进行操作编译的属于 内部构建
内部构建有个缺点就是会在源文件下面生成很多的过程文件,这是不希望的。
例如之前,源文件仅有main.c与CMakeLists.txt文件,果编译完,在原文件下面多了这么多的文件。
为了解决掉这个问题,则引入下面的操作,外部构建
对于上面的工程外部编译的过程如下:
1,首先,请清除 test1 目录中除 main.c CmakeLists.txt 之外的所有中间文件,最关键的是 CMakeCache.txt。
2,在 test1 目录中建立 build 目录,当然你也可以在任何地方建立 build 目录,不一定必须在工程目录中。
3,进入 build 目录,运行 cmake …(注意,…代表父目录,因为父目录存在我们需要的CMakeLists.txt,如果你在其他地方建立了 build 目录,需要运行 cmake <工程的全路径>),查看一下 build 目录,就会发现了生成了编译需要的 Makefile 以及其他的中间文件。
4,运行 make
构建工程,就会在当前目录(build 目录)中获得目标文件 hello。
上述过程就是所谓的 out-of-source
外部编译,一个最大的好处是,对于原有的工程没有任何影响,所有动作全部发生在编译目录。
这里需要特别注意的是:
通过外部编译进行工程构建,HELLO_SOURCE_DIR
仍然指代工程路径,即/Compilation_tool/cmake/test1
而 HELLO_BINARY_DIR
则指代编译路径即/Compilation_tool/cmake/test1/build