CMake学习笔记

介绍

学习CMake工具对大型项目编程是非常有帮助的。主要CMake是跨平台工具,以后想在树莓派上面也上面学习一下。 学习资源:
- IPADS新人培训(B站) github仓库
- ...

Modern CMake

makefile

这是我学习过一些makefile之后,提供的makefile模板。

1
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# write makefile with me
# recommond you to use the VERSION 2



# --------------------------------- VERSION 1 -------------------------------- #
# CC = gcc
# TARGET = hello
# OBJS = main.o printhello.o

# RM = rm -rf
# $(TARGET): $(OBJS)
# $(CC) -o $(TARGET) $(OBJS)

# printhello.o: printhello.c
# $(CC) -c printhello.c

# main.o: main.c functions.h
# $(CC) -c main.c


# .PHONY: run
# run:
# ./$(TARGET)

# .PHONY: clean
# clean:
# $(RM) $(TARGET)


# --------------------------------- VERSION 2 -------------------------------- #

# CC = gcc
# TARGET = hello
# OBJ = main.o printhello.o

# CCFLAGS = -c -Wall

# ## $@ stands for $(TARGET)
# ## $^ stands for dependencies
# ## $< stands for the first one in dependencies
# $(TARGET): $(OBJ)
# $(CC) -o $@ $^

# %.o: %.c
# $(CC) $(CCFLAGS) $< -o $@

# .PHONY: clean

# clean:
# $(RM) *.o $(TARGET)

# .PHONY: run

# run:
# ./$(TARGET)


# --------------------------------- VERSION 3 -------------------------------- #
# sustitude

CC = gcc
TARGET = hello
SRC = $(wildcard *.c)
# substitude the .c file as .o file in $(SRC)
OBJ = $(patsubst %.c, %.o,$(SRC))

CCFLAGS = -c -Wall

## $@ stands for $(TARGET)
## $^ stands for dependencies
## $< stands for the first one in dependencies
$(TARGET): $(OBJ)
$(CC) -o $@ $^

%.o: %.c
$(CC) $(CCFLAGS) $< -o $@

.PHONY: clean

clean:
$(RM) *.o $(TARGET)

.PHONY: run

run:
./$(TARGET)

使用第二版本就好了。如果我学的更多了,或者学习更深入之后,我会再修改这个。(2023.12.3)

示例

1
2
3
4
5
6
7
8
9
10
//main.cpp
#include<iostream>

int main(int argc,const char *argv[])
{
std::cout<<"Hello,World!"<<std::endl;
return 0;

}

对应的Makefile文件如下:

1
2
3
4
5
6
7
8
//Makefile  
hello: main.cpp //hello是target,下面的缩进都是command
$(CXX) -o hello main.cpp //CXX是变量,可以用编译器名称来代替
echo "OK" //基本思路就是目标 文件 指令

//基本格式:
// name: dependencies
// commands

Makefile文件里面涉及到了一些shell的命令。这一部分要多去实践运用。

项目示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include<iostream>

#include"answer.hpp" //包含头文件
int main(int argc, const char *argv[])
{
int expected_answer=answer::find_the_ultimate_answer();
for(;;)
{
std::cout<<"What is the ultimate answer ?"<<std::endl;

int answer;
std::cin>>answer;
if(answer==expected_answer){
std::cout<<"Correct!"<<std::endl;
break;
}

}
return 0;

}

其对应的Makefile文件如下:

1
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
//Makefile
CC:=clang
CXX:=clang++

.PHONY:all //.PHONY叫做伪目标
all:answer

#这里添加answer.o目标文件
objects:=main.o answer.o

answer: $(objects)
$(CXX) -o $@ $(objects)


#
# Make 可以自行推断.o文件需要依赖同名的.cpp文件
# 其实并不需要在依赖中指定main.cpp和answer.cpp文件
#也不需要编译commands,它知道要用CXX变量制定的命令
#作为C++编译器
#
# 这里只需要指定目标文件所依赖的头文件,使头文件变动时可以
# 重新编译对应目标文件
#
#
main.o: answer.hpp
answer.o: answer.hpp

.PHONY: clean
clean:
rm -f answer$(objects)

最好还是用.PHONY:伪指令名 好了太难了,还是使用CMake吧!

CMake

  • CMake的基本格式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 指定最小 CMake 版本要求
cmake_minimum_required(VERSION 3.9)
# 设置项目名称
project(answer)

#[[
添加可执行文件 target,类似于原来 Makefile 的:

answer: main.o answer.o
main.o: main.cpp answer.hpp
answer.o: answer.cpp answer.hpp

CMake 会自动找到依赖的头文件,因此不需要特别指定,
当头文件修改的时候,会重新编译依赖它的目标文件。
#]]
add_executable(answer main.cpp answer.cpp)

#[[
使用如下命令构建本项目:

cmake -B build # 生成构建目录
cmake --build build # 执行构建
./build/answer # 运行 answer 程序
#]]

当有些库可以复用的时候,可以在CMakeLists.txt中添加如下命令。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
cmake_minimum_required(VERSION 3.9)
project(answer)

# 添加 libanswer 库目标,STATIC 指定为静态库
add_library(libanswer STATIC answer.cpp)

add_executable(answer main.cpp)

# 为 answer 可执行目标链接 libanswer
target_link_libraries(answer libanswer)

#[[
使用如下命令构建本项目:

cmake -B build # 生成构建目录
cmake --build build # 执行构建
./build/answer # 运行 answer 程序
#]]
  • 使用子目录
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    文件目录
    .
    ├── CMakeLists.txt
    ├── README.md
    ├── answer
    │   ├── CMakeLists.txt
    │   ├── answer.cpp
    │   └── include
    │   └── answer.hpp
    ├── clear.sh
    ├── main.cpp
    └── tree.txt

完整内容还是看我的github仓库cpp_tutorial中的modern_cmake