Makefile
假设我们现在需要做一道水煮鱼,它需要n多复杂布置。但是我们厨艺不精,我们能不能写个配料表,直接给一个经验丰富的老师傅,让他制作(make)?这个配料表就是Makefile文件了,给老师傅一键制作的过程就是一键make了。对应代码就是,我们需要分步骤对文件进行编译,我们现在写个脚本,只要运行就能一键编译所有过程。这就是Makefile。
1、简单规则
-
在Makefile中,#代表着注释,这个是不会被编译进去的。
-
Makefile的基本语法是:
目标文件:依赖文件...(可以是多个依赖文件) 目标文件1:依赖文件... 目标文件2:依赖文件... ...可以理解为需要做一道水煮鱼(目标文件),需要鱼、调理(依赖文件)
水煮鱼:鱼 配料 //鱼已经有了,就需要其它“依赖文件”来制造他了,现在差调料 配料:调料 油 调料:辣椒 花椒 醋... ... //直到层层配好所有东西,即可一键制作“make” -
越是接近目标文件的命令,就越是要写在前面。程序按照递归的方式进行依赖文件查找的
现在了解了规则,可以开始进行写配料表了。
1.1 例子
Makefile例子:生成可执行文件全过程
hello:hello.o //最终目标:可执行文件hello,它依赖于hello.o
gcc hello.o -o hello //链接出可执行文件hello
hello.o:hello.S //hello.o,它又依赖于hello.S
gcc -c hello.S -o hello.o //汇编
hello.S:hello.i //hello.S,它又依赖于hello.i
gcc -S hello.i -o hello.S //编译
hello.i:hello.c //hello.i,它又依赖于hello.c
gcc -E hello.c -o hello.i //预处理
2、伪目标
水煮鱼做好了,我们发现我们多做了很多不需要的“调料”,我们只需要水煮鱼,不需要其它调料占地方。我们就需要添加一键去除多余材料的功能了。
假设当前文件夹中有hello.c和Makefile两个文件,当我们在终端输入make指令的时候,就会自动编译出hello.o,hello.S,hello.i(多余调料)以及hello可执行文件。当我们不需要这些不相关的文件,想对这些文件做一些操作,我们把这样的操作叫做伪目标,标志位.PHONY: 。我们只需在上述代码的最后面加上即可:
.PHONY:
clear:
rm hello.o hello.S hello.i
.PHONY:固定格式,不能变的,clear可以自己取比如“clear”,对应一键去除”多余调料“。当我们执行make clear指令后,将只剩下hello.c 和 hello可执行文件。
3、复杂例子简化
现在我们需要做一道更复杂的菜,比如“佛跳墙”,这道菜的菜单(Makefikle脚本),如下:
# 目标文件:test
# 现有文件:program1.c program1.h program2.c program2.h main.c main.h
test:program1.o program2.o main.o
gcc program1.o program2.o main.o -o test
program1.o:program1.c
gcc -c program1.c -o program1.o
program2.o:program2.c
gcc -c program2.c -o program2.o
main.o:main.c
gcc -c main.c -o main.o
.PHONY:
clean_all:
rm program1.o program2.o main.o
我们发现配料太多了,菜单太长太复杂了,我们能不能用某些记号来代替它,比如定义个TAR代表“佛跳墙”,OBJ代表那些“配料”,那我们定义以下统一规则来简化菜单(Makefile文件)
变量
| 符号 | 含义 |
|---|---|
| = | 替换 |
| += | 追加 |
| := | 恒等于 |
- 如果我们写TAR = test,就表示下面的代码中,我们可以用TAR代表test文件。
如果再写TAR += test1,就表示TAR代表test和test1。 - CC := gcc 就表示下面写gcc的地方全部可以用CC代替,因为gcc这个是不会变的,是常量,所以可以用恒等于替换,这个不能用+=。
- 当我们要调用这些变量的时候,就直接使用$(变量)的方式进行调用。
上面代码可以简化如下:
TAR = test
OBJ = program1.o program2.o main.o
CC := gcc
$(TAR):$(OBJ) //使用$(变量)的方式进行调用
$(CC) $(OBJ) -o $(TAR)
program1.o:program1.c
$(CC) -c program1.c -o program1.o
program2.o:program2.c
$(CC) -c program2.c -o program2.o
main.o:main.c
$(CC) -c main.c -o mian.o
.PHONY:
clean_all:
rm $(OBJ)
4、通配符
现在我们发现“菜单”还是太长了,我们能不能进一步进行简化,我们现在又加上新的一套规则(我们称它为通配符),假设.c结尾的配料我们统一称为原料:如:辣椒、花椒…现在我们只需要使用通配符这个规则,我们就不需要写这些原料的具体名称,只需要知道.c结尾的就回自动匹配为原料。下面就是我们定义的规则:
| 符号 | 含义 |
|---|---|
| %.o | 任意的.o文件 |
| *.o | 所有的.o文件 |
%.o和%.c中的%是通配符,表示任何文件名。%.o: %.c表示所有以.o结尾的目标文件,都依赖于相应的以.c结尾的源文件。例如,program1.o依赖于program1.c,main.o依赖于main.c。
上面代码可再次简化如下:
TAR = test
OBJ = program1.o program2.o main.o
CC := gcc
$(TAR):$(OBJ)
$(CC) $(OBJ) -o $(TAR)
%.o:%.c
$(CC) -c %.c -o %.o
.PHONY:
clean_all:
rm $(OBJ)
我们再多加个规则:
| 符号 | 含义 |
|---|---|
| $^ | 所有依赖文件 |
| $@ | 所有目标文件 |
| $< | 所有依赖文件的第一个文件 |
上面代码可再次简化如下:
TAR = test
OBJ = program1.o cube.o main.o
CC := gcc
RMRF := rm
$(TAR):$(OBJ)
$(CC) $^ -o $@
%.o:%.c //%.o表示以.o结尾的文件
$(CC) -c $^ -o $@
.PHONY:
cleanall:
$(RMRF) $(OBJ)
5、更多内容
OK,你已经入门Makefile,但要完成更复杂的任务还需要更多手法,比如修一栋房子,你需要进入其它房间,分批完成,这就涉及到多个Makefile文件的相互嵌套和更多的命令了。这就等后续再进行讲解了。
6862

被折叠的 条评论
为什么被折叠?



