0%

makefile语法规则

环境准备

  • Linux下自带make,如果没有sudo apt install make即可
  • Windows下使用make比较麻烦,因为MinGW实际上是Linux的gcc在Windows下的移植版本,而make的名字不叫make,所以需要改exe的名字
    在MinGW的bin目录下将mingw32-make.exe改成make,如果你配置好了MinGW的环境变量,这里理所应当的可以直接在terminal里调用make的,然后就可以从事makefile的编写了
    make

makefile的编写:基础版

假设你有main.cpp, func1.cpp, func2.cpp三个独立的cpp文件,然后希望将其编译到成一个可执行文件res(这里和编译时的强类型和弱类型有关,实际上并不推荐这种写法)

1
2
3
4
res: main.cpp func1.cpp func2.cpp
g++ -g main.cpp func1.cpp func2.cpp -o res
clean:
del *.o res.exe

  • 有两个重要的问题:
    • 项目比较大的时候,一行规则不够
    • 改一个文件就要整个项目重新编译,很蠢

makefile的编写:进阶版

这里采用了header.h文件让main.cpp能够比较靠谱地调用另外两个cpp文件里的函数。在header.h文件里声明他们,然后在func1.cpp和func2.cpp文件里实现

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
// header.h
#pragma
#include<iostream>
using namespace std;
class listNode{
public:
int val;
listNode* next;
listNode(int v):val(v), next(nullptr){}
};
void func1();// only declared
void func2();// only declared

// func1.cpp
#include<iostream>
#include "header.h"
using namespace std;

void func1(){
cout << "func1" << endl;
}

//fun2.cpp
...

// main.cpp
#include "header.h"
#include<iostream>
using namespace std;
int main(){
func1();
func2();
system("pause");
return 0;
}

然后makefile的编写如下所示:

1
2
3
4
5
6
7
8
9
10
res: main.o func1.o func2.o
g++ main.o func1.o func2.o -o res
main.o: main.cpp header.h
g++ -c main.cpp -o main.o
func1.o: func1.cpp
g++ -c func1.cpp -o func1.o
func2.o: func2.cpp
g++ -c func2.cpp -o func2.o
clean:
del *.o res.exe

  • 优点:当有一个文件发生改动时,只需重新编译此文件即可,而无需重新编译整个项目
  • 缺点:
    • 里面存在一些重复的内容,可以考虑用变量代替
    • 后面三条规则非常类似,可以考虑用一条模式规则代替

makefile的编写:高级版

1
2
3
4
5
6
7
8
9
obj = main.o func1.o func2.o
target = res
CC = g++
$(target): $(obj)
$(CC) $(obj) -o $(target)
%.o: %.c
$(CC) -c $< -o $@
clean:
del *.o res.exe

使用的规则如下:即所有的.o文件都由对应的.c文件生成。

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

  • 自动变量有很多种:
    • $<:第一个依赖文件
    • $@:目标
    • $^:所有不重复的依赖文件,以空格分开
  • 优点:可以减少重复的内容
  • 缺点:
    • obj对应的文件需要一个个输入,工作量大
    • 文件数目比较少时还好,文件数目一旦很多的话,obj将很长
    • 而且每增加/删除一个文件,都需要修改Makefile

makefile的编写:究极版

有两个重要函数:wildcardpatsubst


然后我就不会了,平时也没什么机会用到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
src = $(wildcard ./*.c)  
obj = $(patsubst %.c, %.o, $(src))
#obj = $(src:%.c=%.o)
target = app
CC = gcc

$(target): $(obj)
$(CC) $(obj) -o $(target)

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

.PHONY: clean
clean:
rm -rf $(obj) $(target)

Reference

在Windows下使用make命令
如何系统地学习 Makefile 相关的知识(读/写)