会不会写makefile,从侧面说明了一个人是否具备完成大型工程的能力。
一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的 规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂 的功能操作。(虽然目前还没有接触过大型项目,但其实这段话是可以理解的。)
makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编 译,极大的提高了软件开发的效率。
make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命 令
make是一条命令,makefile是一个文件,两个搭配使用,完成项目自动化构建。
好了好了,不CV了
起初存在这些文件,下面的makefile的作用是自动化构建项目。 main.c test.c test.h 构建出test可执行程序。 yzl.c 构建出yzl可执行程序
1 test: test.o main.o
2 gcc test.o main.o -o test
3 yzl: yzl.o
4 gcc yzl.o -o yzl
5 test.o: test.c
6 gcc -c test.c -o test.o
7 main.o: main.s
8 gcc -c main.s -o main.o
9 main.s: main.i
10 gcc -S main.i -o main.s
11 main.i: main.c
12 gcc -E main.c -o main.i
13 yzl.o: yzl.c
14 gcc -c yzl.c -o yzl.o
15
16 .PHONY: clean
17 clean:
18 rm -f main.i main.s main.o test.o test
19
20 .PHONY: ll
21 ll:
22 ls
23
24 .PHONY: cleanyzl
25 cleanyzl:
26 rm -f yzl yzl.o
编写makefile。两个核心是依赖关系和依赖方法
依赖关系:为了生成某个目标文件,此目标文件依赖于其他文件。比如上图makefile中的生成test依赖于test.o main.o 而test.o又依赖于test.c 依赖方法:生成test目标可执行文件,依赖关系是依赖于test.o 和main.o 而依赖方法就是下面的命令行,表示执行此命令(方法)之后即可生成目标文件。
在makefile中,依赖关系是层层依赖的,比如test依赖于test.o main.o ,如下test.o 依赖于test.c main.o依赖于main.s main.s 依赖于main.i make处理makefile时,默认进行第一个依赖关系和依赖方法。 也就是只有main.o 和 test.o不存在时,才会往下查找是否有某个依赖关系的目标文件是main.o 和 test.o 。所以编写makefile时,一定要从后往前,以程序形成的逆序来编写makefile。
所以,第二个依赖关系yzl : yzl.o 不主动执行的情况下,是无法自动自动进行的,因为第一个依赖关系中不依赖于yzl文件。所以,如果想生成yzl,比如主动执行make : make yzl
我们现在知道了make指令默认从makefile的第一个依赖关系开始,而重复进行make时,
就会出现如上情况,make: 'test' is up to date 意思是此时的目标文件test已经是最新的了,再次构建项目是没有意义的,那么,make是如何知道此时test是最新的呢?其实是依据目标文件test和其依赖的文件的修改时间,来判断是否需要进行此次make。 当所有的依赖文件的修改时间都比test的时间早时,表示test目标文件是最新的,也就没有必要进行make操作。一旦修改其中任何一个依赖文件,下一次的make就会生效。
工程是需要被清理的,我们可以设定一个clean,像clean这种,没有被第一个目标文件直接或间接关联,那么它后面所定义的命令将不会被自动执行, 不过,我们可以显示要make执行。即命令——“make clean”,以此来清除所有的目标文件,以便重编译。
但是一般clean这种的目标文件,我们将它设置为伪目标,用 .PHONY 修饰,伪目标的特性是,总是被 执行的。
总是被执行:每次make clean时,不会按照文件的修改时间来判断此时make clean是否执行,而是每次make clean都生效,这就是总是被执行。
再比如上方的yzl目标文件,因为它不是第一个依赖关系依赖的文件,所以它不会自动执行,我们可以make yzl 而执行这个依赖关系。 make cleanyzl即执行清理yzl相关文件的工作。
1. 如上的clean声明为.PHONY 除了让其总是被执行,还有一个原因是.PHONY是一个伪目标,可以防止在Makefile中定义的只执行命令的目标和工作目录下的实际文件出现名字冲突。也就是如果工作目录下存在clean文件,那么make就会不执行此依赖关系。而.PHONY声明clean后可以理解为clean并不是一个目标文件,只是一个操作。
2. 目标确实是一个文件,但是目标文件的构建很复杂,其构建是通过其他方式完成的,在当前makefile中没有包含其完整的依赖关系和构建方式。默认方式下makefile检查依赖后可能不执行目标的构建命令。这时使用.PHONY表示目标不是当前makefile直接构建的,不要通过检查依赖来决定是否执行命令,必须执行其构建命令来完成构建。
需要注意的是虽然.PHONY目标不通过依赖来决定目标是否要执行命令,但是还是会检查依赖的,依赖的文件不存在时仍然会尝试构建或报错。
总结一下:.PHONY目标一定会执行构建命令。一般用于目标非实体文件,或目标文件不受makefile管理、依赖关系不完整的情况。