CMake
CMake
一、cmake介绍
在早期和当今的Linux工程管理中,make工程管理器占据了半壁江山,但make的配置文件`Makefile的语法晦涩难懂,接触过的人都清楚,Makefile写起来非常困难。解决这个问题的办法无法有两个:
- 使用
automake工具生成configure脚本,让其自动生成Makefile。 - 使用
cmake工具直接生成Makefile。
cmake是什么
cmake 是一款跨平台的免费开源软件工具,用于使用与编译器无关的方法来管理软件的构建过程。比如,在 Android Studio 上进行 NDK 开发默认就是使用 cmake 管理 C/C++ 代码,在 Linux 环境下有大量项目都使用 cmake 来管理,因此最好对 cmake 有一定的了解。
cmake最重要的作用就是协助我们自动生成项目所需要的Makefile,以便于工程管理器make可以指导编译器的工作,他们的关系大概如下:
1.开发者编写CMakeLists.txt,指导cmake自动生成Makefile
2.自动生成的Makefile,指导make和gcc,将源代码编译成可执行程序
这样一来,我们就摆脱了晦涩难写的Makeifle,转而编写简单可爱的 CMakeLists.txt ,利用cmake即可管理整个项目。
源码隔离
一般而言,为了项目工程观感更干净、利落,我们不希望源码跟编译工具文档像上面的例子那样混在一起,因此对于cmake而言,通常的操作是:在源码中创建一个专门用于存储编译输出文件的存储区域,不妨命名为 build/ ,使自动生成的文件与开发者编写的源码隔离:
# 创建一个构建目录,专门用来存放构建过程中产生的非源码文件
gec@ubuntu:~/cmake$ mkdir build/
# 进入该构建目录
gec@ubuntu:~/cmake$ cd build
gec@ubuntu:~/cmake/build$
# 在构建目录中执行 `cmake`
gec@ubuntu:~/cmake/build$ cmake ..
二、安装cmake
在 ubuntu 中安装 cmake
ubuntu安装 cmake 只需一条指令:
sudo apt install cmake
可以通过以下指令来查看当前已安装的cmake的版本,若需要升级版本,可直接使用 apt 指令来升级:
# 查看cmake版本
gec@ubuntu:~$ cmake --version
# 升级cmake
gec@ubuntu:~$ sudo apt upgrade cmake
三、简单示例
入门操作
假设有一C语言源程序main.c,其内容如下:
#include <stdio.h>
int main(int argc, char const *argv[])
{
printf("一起学习cmake\n");
return 0;
}
现使用 cmake 来管理该项目的构建工作,在 main.c 同一目录下,编写一个 CMakeLists.txt:
gec@ubuntu:~/cmake$ tree
.
├── CMakeLists.txt
└── main.c
gec@ubuntu:~/cmake$
注意:
- 配置文件的名称 CMakeLists.txt 是固定的,不可改成别的名字
- 配置文件的名称 CMakeList.txt 不区分大小写,但一般的写法如此所示。
- add_executable 用来指明最终要生成一个可执行文件的名称,及其所依赖的源文件列表。
# CMakeLists.txt
add_executable(main main.c)
在源码目录中,直接执行命令 “cmake .”(其中 . 表示 CMakeLists.txt 所在的位置在当前目录) 来读取 CMakeLists.txt 并生成 Makefile:
有了Makefile,就可以直接make编译项目程序了:
此时,程序main已经编译完毕。
文件 CMakeLists.txt 是 cmake 的配置文件,用来告诉 cmake 如何生成最终的 Makefile。此处的 CMakeLists.txt 非常简单,仅包含一句话:
多文件编译
语法:
add_executable(可执行文件 源文件1 源文件2 ... ...)
假设某可执行文件 main 由多个源码文件编译而成:
add_executable(main main.c a.c b.c)
指定头文件路径
语法:
include_directories(头文件所在路径)
假设文件结构如下:
.
├── build/
├── inc/
│ └── head.h
└── main.c
├── CMakeLists.txt
其中,主程序 main.c 依赖于头文件 head.h,那么在与之同目录的 CMakeLists.txt 中,需要以其所在路径为基准添加头文件相对路径或绝对路径:
# CMakeLists.txt
include_directories(./inc) # 相对路径,基于CMakeLists.txt所在路径
add_executable(main main.c)
或者
# CMakeLists.txt
include_directories(/home/gec/cmake/inc) # 绝对路径
add_executable(main main.c)
设定变量和调用shell命令
语法:
set(变量名称 变量值)
在指定头文件路径的例子中,当使用绝对路径时,若采用上述方式则在不同电脑间执行会很容易出现错误,更好的方式是让 CMakeLists.txt 在被解析的时候自动获取其所在路径,这可以在 CMakeLists.txt中嵌套 shell 命令来达到:
# 定义一个变量 SRCDIR,使其值等于当前路径
set(SRCDIR $(pwd))
# 引用变量 SRCDIR 的值来设定头文件所在路径
include_directories($(SRCDIR)/inc)
指明库路径和链接指定的库文件
语法:
link_directories(库所在路径)
target_link_libraries(目标文件 库名1 库名2 ... ...)
假设主程序 main.c 引用了 lib/ 下各个库文件的接口,则编译时就必须链接相关的库文件。在顶层 CMakeLists.txt 中添加两行 target_link_libraries() 语句:
# CMakeLists.txt
set(SRCDIR $(pwd))
include_directories($(SRCDIR)/inc/)
add_executable(main main.c)
target_link_libraries(main a) # 指明可执行文件main依赖于库a
target_link_libraries(main b) # 指明可执行文件main依赖于库b
add_subdirectory(lib/)

浙公网安备 33010602011771号