1. CMake概述
CMake 是一个项目构建工具,并且是跨平台的。关于项目构建我们所熟知的还有Makefile(通过 make 命令进行项目的构建),但是makefile 通常依赖于当前的编译平台,而且编写 makefile 的工作量比较大,解决依赖关系时也容易出错。(这在之前的博文makefile和cmake入门中有提到)
而 CMake 恰好能解决上述问题, 其允许开发者指定整个工程的编译流程,在根据编译平台,自动生成本地化的Makefile和工程文件,最后用户只需make编译即可,所以可以把CMake看成一款自动生成 Makefile的工具,其编译流程如下图:
-
蓝色虚线表示使用makefile构建项目的过程
-
红色实线表示使用cmake构建项目的过程
CMake的优点如下所示:
- 跨平台
- 能够管理大型项目
- 简化编译构建过程和编译过程
- 可扩展:可以为 cmake 编写特定功能的模块,扩充 cmake 功能
简而言之,就是我们希望通过编写CMakeLists.txt文件,通过执行cmake命令,让其自适应地在不同平台生成makefile文件!
2. CMake的使用
CMake支持大写、小写、混合大小写的命令。如果在编写CMakeLists.txt文件时使用的工具有对应的命令提示,那么大小写随缘即可,不要太过在意。
2.1 注释
2.1.1 注释行
CMake 使用 # 进行行注释,可以放在任何位置。
# 这是一个 CMakeLists.txt 文件
cmake_minimum_required(VERSION 3.0.0)
2.1.2 注释块
CMake 使用 #[[ ]] 形式进行块注释。
#[[ 这是一个 CMakeLists.txt 文件。
这是一个 CMakeLists.txt 文件
这是一个 CMakeLists.txt 文件]]
cmake_minimum_required(VERSION 3.0.0)
2.2 只有源文件
2.2.1 源文件与CMakeList.txt在同一目录下
1.首先有如下源文件
add.cpp
#include <iost>
#include "head.h"
int add(int a, int b)
{
return a+b;
}
sub.cpp
#include <iostream>
#include "head.h"
int substract(int a, int b)
{
return a - b;
}
mult.cpp
#include <iostream>
#include "head.h"
int multiply(int a, int b)
{
return a * b;
}
div.cpp
# include <iostream>
# include "head.h"
double divide(int a, int b)
{
return (double) a/b;
}
head.h
#ifndef _HEAD_H
#define _HEAD_H
int add(int a, int b);
int substract(int a, int b);
int multiply(int a, int b);
double divide(int a, int b);
#endif
main.cpp
#include <iostream>
#include "head.h"
using namespace std;
int main()
{
int a = 20;
int b = 12;
cout<<"a = "<<a<<" b = "<<b<<endl;
cout<<"a + b = "<<add(a, b)<<endl;
cout<<"a - b = "<<substract(a, b)<<endl;
cout<<"a * b = "<<multiply(a, b)<<endl;
cout<<"a / b = "<<divide(a, b)<<endl;
return 0;
}
2.上述文件的目录结构如下
$ tree
.
├── add.c
├── div.c
├── head.h
├── main.c
├── mult.c
└── sub.c
3.编写CMakeLists.txt文件
cmake_minimum_required(VERSION 3.0)
project(CALC)
add_executable(main add.cpp div.cpp main.cpp mult.cpp sub.cpp)
接下来依次介绍一下在 CMakeLists.txt 文件中添加的三个命令:
- cmake_minimum_required:指定使用的 cmake 的最低版本。可选,非必须,如果不加可能会有warning
- project:定义工程名称,并可指定工程的版本、工程描述、web主页地址、支持的语言(默认情况支持所有语言),如果不需要这些都是可以忽略的,只需要指定出工程名字即可。
# PROJECT 指令的语法是:
project(<PROJECT-NAME> [<language-name>...])
project(<PROJECT-NAME>
[VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
[DESCRIPTION <project-description-string>]
[HOMEPAGE_URL <url-string>]
[LANGUAGES <language-name>...])
- add_executable:定义工程会生成一个可执行程序
add_executable(可执行程序名 源文件名称)
这里的可执行程序名和project中的项目名没有任何关系
源文件名可以是一个也可以是多个,如有多个可用空格或;间隔
# 样式1
add_executable(app add.c div.c main.c mult.c sub.c)
# 样式2
add_executable(app add.c;div.c;main.c;mult.c;sub.c)
4.执行CMake命令
# cmake 命令原型
$ cmake CMakeLists.txt文件所在路径
当前路径下的文件结构如下所示:
$ tree
.
├── add.cpp
├── CMakeLists.txt
├── div.cpp
├── head.h
├── main.cpp
├── mult.cpp
└── sub.cpp
0 directories, 7 files
当执行cmake命令之后,CMakeLists.txt 中的命令就会被执,
$ cmake .
-- The C compiler identification is GNU 9.4.0
-- The CXX compiler identification is GNU 9.4.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /media/peter/Data/MyProject/my_git/v0
执行命令之后,看一下源文件所在目录中是多了一些文件:
$ tree -L 1
.
├── add.cpp
├── CMakeCache.txt
├── CMakeFiles
├── cmake_install.cmake
├── CMakeLists.txt
├── div.cpp
├── head.h
├── main.cpp
├── Makefile
├── mult.cpp
└── sub.cpp
1 directory, 10 files
我们可以看到在对应的目录下生成了一个makefile文件,此时再执行make命令,就可以对项目进行构建得到所需的可执行程序了。
$ make
[ 16%] Building CXX object CMakeFiles/main.dir/add.cpp.o
[ 33%] Building CXX object CMakeFiles/main.dir/div.cpp.o
[ 50%] Building CXX object CMakeFiles/main.dir/main.cpp.o
[ 66%] Building CXX object CMakeFiles/main.dir/mult.cpp.o
[ 83%] Building CXX object CMakeFiles/main.dir/sub.cpp.o
[100%] Linking CXX executable main
[100%] Built target main
$ tree -L 1
.
├── add.cpp
├── CMakeCache.txt
├── CMakeFiles
├── cmake_install.cmake
├── CMakeLists.txt
├── div.cpp
├── head.h
├── main # 生成的可执行程序
├── main.cpp
├── Makefile
├── mult.cpp
└── sub.cpp
1 directory, 11 files
最终可执行程序main就被编译出来了(这个名字是在CMakeLists.txt中指定的)。
2.2.2 创建build目录
通过上面的例子可以看出,如果在CMakeLists.txt文件所在目录执行了cmake命令之后就会生成一些目录和文件(包括 makefile 文件),如果再基于makefile文件执行make命令,程序在编译过程中还会生成一些中间文件和一个可执行文件,这样会导致整个项目目录看起来很混乱,不太容易管理和维护,此时我们就可以把生成的这些与项目源码无关的文件统一放到一个对应的目录里边,比如将这个目录命名为build:
$ mkdir build
$ cd build
$ cmake ..
-- The C compiler identification is GNU 9.4.0
-- The CXX compiler identification is GNU 9.4.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /media/peter/Data/MyProject/my_git/v0/build
现在cmake命令是在build目录中执行的,但是CMakeLists.txt文件是build目录的上一级目录中,所以cmake 命令后指定的路径为..,即当前目录的上一级目录。
当命令执行完毕之后,在build目录中会生成一个makefile文件
$ tree build -L 1
build
├── CMakeCache.txt
├── CMakeFiles
├── cmake_install.cmake
└── Makefile
1 directory, 3 files
这样就可以在build目录中执行make命令编译项目,生成的相关文件自然也就被存储到build目录中了。这样通过cmake和make生成的所有文件就全部和项目源文件隔离开了,结构更加清晰。
在build目录下,执行make命令进行编译。
$ make
[ 16%] Building CXX object CMakeFiles/main.dir/add.cpp.o
[ 33%] Building CXX object CMakeFiles/main.dir/div.cpp.o
[ 50%] Building CXX object CMakeFiles/main.dir/main.cpp.o
[ 66%] Building CXX object CMakeFiles/main.dir/mult.cpp.o
[ 83%] Building CXX object CMakeFiles/main.dir/sub.cpp.o
[100%] Linking CXX executable main
[100%] Built target main
运行可执行程序main
$ ./main
a = 20 b = 12
a + b = 32
a - b = 8
a * b = 240
a / b = 1.66667
Reference:
[1] 【CMake 保姆级教程【C/C++】 https://www.bilibili.com/video/BV14s4y1g7Zj/?spm_id_from=333.999.0.0&vd_source=eb2aff91d0c138676172d1f9746b9f1ehttps://www.bilibili.com/video/BV1HM411377j/?spm_id_from=333.337.search-card.all.click&vd_source=eb2aff91d0c138676172d1f9746b9f1e