Makefile的规则
target ... : prerequisites ...command
...
...
target也就是一个目标文件,可以是Object File,也可以是执行文件。还可以是一个标签(Label),对于标签这种特性,在后续的“伪目标”章节中会有叙述。
prerequisites就是,要生成那个target所需要的文件或是目标。
command也就是make需要执行的命令。(任意的Shell命令)
这是一个文件的依赖关系,也就是说,target这一个或多个的目标文件依赖于prerequisites中的文件,其生成规则定义在command中。说白一点就是说,prerequisites中如果有一个以上的文件比target文件要新的话,或者target不存在的话,那么,make就会执行后续定义的命令command所定义的命令就会被执行(command一定要以一个Tab键作为开头)。这就是Makefile的规则。也就是Makefile中最核心的内容。
说明:clean不是一个文件,它只不过是一个动作名字,有点像C语言中的lable一样,其冒号后什么也没有,那么,make就不会自动去找文件的依赖性,也就不会自动执行其后所定义的命令。要执行其后的命令,就要在make命令后明显得指出这个lable的名字。这样的方法非常有用,我们可以在一个makefile中定义不用的编译或是和编译无关的命令,比如程序的打包,程序的备份,等等。
----------------------------------------------------------------------------------------------------
1. 写一个Makefile来告诉make命令如何编译和链接这几个文件。我们的规则是:
1)如果这个工程没有编译过,那么我们的所有C文件都要编译并被链接。2)如果这个工程的某几个C文件被修改,那么我们只编译被修改的C文件,并链接目标程序。
3)如果这个工程的头文件被改变了,那么我们需要编译引用了这几个头文件的C文件,并链接目标程序。
目标文件在编译的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make就会直接退出,并报错,而对于所定义的命令的错误,或是编译不成功,make根本不理。make只管文件的依赖性,即,如果在我找了依赖关系之后,冒号后面的文件还是不在,那么对不起,我就不工作啦。
2. object 变量,使用变量的形式,表示目标文件:objects = main.o kbd.o command.o display.o,然后很方便地在我们的makefile中以“$(objects)”的方式来使用这个变量;
3. “隐晦规则”和“伪目标文件”
1> “隐晦规则”:GNU的make 非常强大,可以通过目标 .o 文件推导出相应的 .c 及编译命令等;
2> “伪目标文件”:
.PHONY : clean
clean :-rm edit $(objects)
.PHONY意思表示clean是一个“伪目标”。而在rm命令前面加了一个小减号的意思就是,也许某些文件出现问题,但不要管,继续做后面的事;加上 .PHONY 的目的是为了避免和文件重名的这种情况;
.PHONY的实际使用范例:
1> 如果你的Makefile需要一口气生成若干个可执行文件,但你只想简单地敲一个make完事,并且,所有的目标文件都写在一个Makefile中,那么你可以使用“伪目标”这个特性:
all : prog1 prog2 prog3
.PHONY : all
prog1 : prog1.o utils.o
cc -o prog1 prog1.o utils.o
prog2 : prog2.o
cc -o prog2 prog2.o
prog3 : prog3.o sort.o utils.o
cc -o prog3 prog3.o sort.o utils.o
2> 目标也可以成为依赖。所以,伪目标同样也可成为依赖。看下面的例子:
.PHONY: cleanall cleanobj cleandiff
cleanall : cleanobj cleandiff
rm program
cleanobj :
rm *.o
cleandiff :
rm *.diff
“make clean”将清除所有要被清除的文件。“cleanobj”和“cleandiff”这两个伪目标有点像“子程序”的意思。我们可以输入“make cleanall”和“make cleanobj”和“make cleandiff”命令来达到清除不同种类文件的目的。
4. 引用其它的Makefile
在Makefile使用include关键字可以把别的Makefile包含进来,这很像C语言的#include,被包含的文件会原模原样的放在当前文件的包含位置。
include foo.make *.mk
等价于:
include foo.make a.mk b.mk
查找Makefile路径一般是在当前的目录下,或者make执行的时候,“-I”或“--include-dir”参数;
5. 文件搜寻
在一些大的工程中,有大量的源文件,我们通常的做法是把这许多的源文件分类,并存放在不同的目录中。所以,当make需要去找寻文件的依赖关系时,你可以在文件前加上路径,但最好的方法是把一个路径告诉make,让make在自动去找;
1、 首先搜索的目录是当前目录;
2、 VPATH = src:../headers 冒号分离不同的文件目录,此例子先后在 src 和 ../headers 目录下进行查询;
3、 make的“vpath”关键字(注意,它是全小写的);
1> vpath <pattern>; <directories>;
为符合模式<pattern>;的文件指定搜索目录<directories>。
例子:vpath %.h ../headers 表示在目录 ../headers 下查找 .h 头文件;
2> vpath <pattern>;
清除符合模式<pattern>;的文件的搜索目录。
3> vpath
清除所有已被设置好了的文件搜索目录。