cmake教程
# Makefile
在Linux环境下,当我们输入make命令时,它就在当前目录查找一个名为Makefile的文件,然后,根据这个文件定义的规则,自动化地执行任意命令,包括编译命令。
Makefile
这个单词,顾名思义,就是指如何生成文件。
# 规则
目标文件: 依赖文件1 依赖文件2...
执行的命令
2
注意:Makefile的规则中,命令必须以Tab开头,不能是空格
例如:下面是一个简单的C++程序:
// main.cpp
#include <iostream>
int main() {
std::cout << "Hello World!" << std::endl;
return 0;
}
2
3
4
5
6
7
使用命令行g++ main.cpp -o main
和./main
来构建和执行代码,输出Hello World!
现在将程序复杂:
.
├── main
├── main.cpp
├── message.cpp
└── message.h
2
3
4
5
这时我们可以添加Makefile
文件,更加方便构建:
project: main.cpp message.cpp
g++ main.cpp message.cpp -o project
2
此时,make
会新建一个project文件,./project
执行后输出结果
更加规范地,可以把编译和链接过程分开编写:
project: main.o message.o
g++ main.o message.o -o project
main.o: main.cpp
g++ -c main.cpp
message.o: message.cpp
g++ -c message.cpp
2
3
4
5
6
7
8
# 伪目标(.PHONY)
伪目标(Phony Target) 是一种特殊的“目标”,它并不代表一个实际的文件,而是用来执行某些特定操作的一组命令。常见的伪目标包括clean、install、all
等。
- clean
.PHONY:clean
clean:
rm *.o project
2
3
.PHONY
显式的表示clean是一个伪目标,这样make不会将clean当作文件名来处理
- all
# ...
.PHONY:clean all
clean:
rm *.o project
all:main.o message.o
echo 'all done'
2
3
4
5
6
# cmake
CMake是一个跨平台的开源构建系统生成器,它简化了复杂软件项目的构建过程。不同于直接编写 Makefile,CMake 使用一种高级语言(CMakeLists.txt 文件)来描述如何编译和链接代码(自动生成Makefile文件)
# 示例
写一个简单的main
函数,创建CMakeLists.txt
# 表明项目的最低版本号 3.10
cmake_minimum_required(VERSION 3.10)
# 声明项目名称
project(testCmake)
# 声明目标文件和依赖文件
add_executable(main main.cpp)
2
3
4
5
6
7
8
终端执行命令cmake .
和make
,最后./main
输出结果
现在将程序复杂:
.
├── main
├── main.cpp
├── message01.cpp
├── message01.h
├── message02.cpp
└── message02.h
2
3
4
5
6
7
# 表明项目的最低版本号 3.10
cmake_minimum_required(VERSION 3.10)
# 声明项目名称
project(testCmake)
# 声明目标文件和依赖文件
add_executable(main main.cpp message01.cpp message02.cpp)
2
3
4
5
6
7
8
这里,如果我们的源文件太多的话,就会极不方便,可以用以下写法简化:
# 表明项目的最低版本号 3.10
cmake_minimum_required(VERSION 3.10)
# 声明项目名称
project(testCmake)
# 将当前目录的所有源文件保存在SRC_DIR中
aux_source_directory(. SRC_DIR)
# 声明目标文件和依赖文件
add_executable(main ${SRC_DIR})
2
3
4
5
6
7
8
9
10
11
但是我们看一下文件树
.
├── CMakeCache.txt
├── CMakeFiles
│ ├── 3.26.5
│ │ ├── CMakeCCompiler.cmake
│ │ ├── CMakeCXXCompiler.cmake
│ │ ├── CMakeDetermineCompilerABI_C.bin
│ │ ├── CMakeDetermineCompilerABI_CXX.bin
│ │ ├── CMakeSystem.cmake
│ │ ├── CompilerIdC
│ │ │ ├── a.out
│ │ │ ├── CMakeCCompilerId.c
│ │ │ └── tmp
│ │ └── CompilerIdCXX
│ │ ├── a.out
│ │ ├── CMakeCXXCompilerId.cpp
│ │ └── tmp
│ ├── cmake.check_cache
│ ├── CMakeConfigureLog.yaml
│ ├── CMakeDirectoryInformation.cmake
│ ├── main.dir
│ │ ├── build.make
│ │ ├── cmake_clean.cmake
│ │ ├── compiler_depend.internal
│ │ ├── compiler_depend.make
│ │ ├── compiler_depend.ts
│ │ ├── DependInfo.cmake
│ │ ├── depend.make
│ │ ├── flags.make
│ │ ├── link.txt
│ │ ├── main.cpp.o
│ │ ├── main.cpp.o.d
│ │ ├── message01.cpp.o
│ │ ├── message01.cpp.o.d
│ │ ├── message02.cpp.o
│ │ ├── message02.cpp.o.d
│ │ └── progress.make
│ ├── Makefile2
│ ├── Makefile.cmake
│ ├── pkgRedirects
│ ├── progress.marks
│ └── TargetDirectories.txt
├── cmake_install.cmake
├── CMakeLists.txt
├── main
├── main.cpp
├── Makefile
├── message01.cpp
├── message01.h
├── message02.cpp
└── message02.h
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
会发现太过于杂乱,为了更加规范,我们可以在bin文件夹存放生成的源码文件(a.out/.o/...),build文件夹存放(cmake产生的文件),include文件夹(存放头文件),src文件夹(存放源文件)。
# 表明项目的最低版本号 3.10
cmake_minimum_required(VERSION 3.10)
# 声明项目名称
project(testCmake)
# bin 存放生成的可执行文件
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
# 将当前目录的所有源文件保存在SRC_DIR中
aux_source_directory(src SRC_DIR)
# include 存放头文件
include_directories(include)
# 声明目标文件和依赖文件
add_executable(main ${SRC_DIR})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
执行命令:
cd build
cmake ..
cd ..
make
cd buile/bin
./main
2
3
4
5
6
这样一来,目录树会更加清晰:
.
├── build
│ ├── bin
│ │ └── main
│ ├── CMakeCache.txt
│ ├── CMakeFiles
│ │ ├── 3.26.5
│ │ │ ├── CMakeCCompiler.cmake
│ │ │ ├── CMakeCXXCompiler.cmake
│ │ │ ├── CMakeDetermineCompilerABI_C.bin
│ │ │ ├── CMakeDetermineCompilerABI_CXX.bin
│ │ │ ├── CMakeSystem.cmake
│ │ │ ├── CompilerIdC
│ │ │ │ ├── a.out
│ │ │ │ ├── CMakeCCompilerId.c
│ │ │ │ └── tmp
│ │ │ └── CompilerIdCXX
│ │ │ ├── a.out
│ │ │ ├── CMakeCXXCompilerId.cpp
│ │ │ └── tmp
│ │ ├── cmake.check_cache
│ │ ├── CMakeConfigureLog.yaml
│ │ ├── CMakeDirectoryInformation.cmake
│ │ ├── main.dir
│ │ │ ├── build.make
│ │ │ ├── cmake_clean.cmake
│ │ │ ├── compiler_depend.make
│ │ │ ├── compiler_depend.ts
│ │ │ ├── DependInfo.cmake
│ │ │ ├── depend.make
│ │ │ ├── flags.make
│ │ │ ├── link.txt
│ │ │ ├── progress.make
│ │ │ └── src
│ │ │ ├── main.cpp.o
│ │ │ ├── main.cpp.o.d
│ │ │ ├── message01.cpp.o
│ │ │ ├── message01.cpp.o.d
│ │ │ ├── message02.cpp.o
│ │ │ └── message02.cpp.o.d
│ │ ├── Makefile2
│ │ ├── Makefile.cmake
│ │ ├── pkgRedirects
│ │ ├── progress.marks
│ │ └── TargetDirectories.txt
│ ├── cmake_install.cmake
│ └── Makefile
├── CMakeLists.txt
├── include
│ ├── message01.h
│ └── message02.h
└── src
├── main.cpp
├── message01.cpp
└── message02.cpp
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55