综述:
Makefile里主要包含了五个东西:显式规则、隐晦规则、变量定义、文件指示和注释。
1、显式规则。显式规则说明了,如何生成一个或多的的目标文件。这是由Makefile的书写者明显指出,要生成的文件,文件的依赖文件,生成的命令。
2、隐晦规则。由于我们的make有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略地书写Makefile,这是由make所支持的。
3、变量的定义。在Makefile中我们要定义一系列的变量,变量一般都是字符串,这个有点你C语言中的宏,当Makefile被执行时,其中的变量都会被扩展到相应的引用位置上。
4、文件指示。其包括了三个部分,一个是在一个Makefile中引用另一个Makefile,就像C语言中的include一样;另一个是指根据某些 情况指定Makefile中的有效部分,就像C语言中的预编译#if一样;还有就是定义一个多行的命令。
5、注释。Makefile中只有行注释,和UNIX的Shell脚本一样,其注释是用“#”字符,这个就像C/C++中的“//”一样。如果你要在你的Makefile中使用“#”字符,可以用反斜框进行转义,如:“#”。
最后,还值得一提的是,在Makefile中的命令,必须要以[Tab]键开始。
1.Makefile中的显示规则
Makefile的执行规则:
1)如果这个工程没有编译过,那么我们的所有C文件都要编译并被链接。
2)如果这个工程的某几个C文件被修改,那么我们只编译被修改的C文件,并链接目标程序。
3)如果这个工程的头文件被改变了,那么我们需要编译引用了这几个头文件的C文件,并链接目标程序。
Makefile的书写规则:
target : file1 file 2 file 3…..
command1(得到这个目标文件需要执行的命令)
file1 :file4 file 5 file 6……
command2
或
target : prerequisites ; command
注:目标文件的依赖关系是一种层次的结构。
如果冒号后面没接任何文件,makefile不会自动执行这个目标下面的命令。除非在命令窗口显示指定这个目标。Make clean这个功能就是用它实现的。当然,也可以实现其他的一些功能,比如归档。
2.隐晦规则
makefile的自动推导功能
3. 变量
makefile中的变量
定义变量:Variabae_name = ……..(等号后面是一个字符串,一般是文件的列表或其他)
使用变量:$(variable_name)
(1) 多行变量
使用关键字 define,可以定义多行变量,即变量的值不止一行。结束时加上关键字endef。格式:
define two-lines
echo foo
echo $(bar)
endef
定义了一个变量 two-lines。
(2)目标变量
即只在一个目标和其所引发的规则中起作用,且会覆盖全局的变量。
target : variable_name = …
(3)系统预定义变量
$@ 表示着目前规则中所有的目标的集合, 就像一个数组,“$@”依次取出目标,并执于命令
-$(name,..,..) 执行makefile函数。name是函数名,后面是参数。
$< 表示当前目标的依赖文件集,它从整个依赖文件集里依次取出依赖文件。
$^ 表示整个的依赖文件集,除掉重名的文件。
4.文件包含
在Makefile使用include关键字可以把别的Makefile包含进来,这很像C语言的#include,被包含的文件会在当前文件的包含位置展开。include的语法是:
include <filename list>
例子:
include foo.make *.mk $(bar)
例子中变量bar定义了一个文件名字。*.mk指在所有后缀为mk的文件都会包含(在当前目录、命令行指定的目录、<prefix>/include)。由此可以看出,makefile的文件命名很灵活。如果‘makefile’不是定义的make文件的名字,在使用这个文件时,需要在命令行指定。格式如下: make –f filename
如果有文件没有找到的话,make会生成一条警告信息,但不会马上出现致命错误。它会继续载入其它的文件,一旦完成makefile的读取,make会再重试这些没有找到,或是不能读取的文件,如果还是不行,make才会出现一条致命信息。如果你想让make不理那些无法读取的文件,而继续执行,你可以在 include前加一个减号“-”。如:
-include <filename>
其表示,无论include过程中出现什么错误,都不要报错继续执行。和其它版本make兼容的相关命令是sinclude,其作用和这一个是一样的。‘-’可以加到makefile文件中任何处,表达的含义相同。
5.其他
(1)嵌套执行:进入其他目录并执行目录下的makefile文件
subsystem:
cd subdir && $(MAKE)
或:
subsystem:
$(MAKE) -C subdir
其中,subdir是下一级目录的名字。$(MAKE)是进入目录可能需要的参数。
传递变量到下一级目录,
export variable_name 传递变量
export variable_name = value 赋值后再传递变量
export 传递所有的变量
有两个变量,一个是SHELL,一个是MAKEFLAGS,总是要传递到下层Makefile中,特别是MAKEFILES变量,其中包含了make的参数信息。
(2)赋值
= 右边的值可以是在后面才赋值的变量
:= 对变量赋值时,只使用在此前已赋值的变量
+= 将值追加到变量的最后
?= 如果左边的变量已定义,则这条语句不做任何动作;否则将右边的值赋给左边变量
(3)伪目标
不生成目标文件的目标。格式:
target :
command
或
.PHONY : target
target :
command
(4) 命令执行顺序
如果你要让上一条命令的结果应用在下一条命令时,你应该使用分号分隔这两条命令。比如你的第一条命令是cd命令,你希望第二条命令得在cd之后的基础上运行,那么你就不能把这两条命令写在两行上,而应该把这两条命令写在一行上,用分号分隔。
(5) 命令行
如果有变量是通常make的命令行参数设置的,那么Makefile中对这个变量的赋值会被忽略。如果你想在Makefile中设置这类参数的值,那么,你可以使用“override”指示符。
在命令行中可以改变makefile文件中对变量值的设置,格式如下:
make “variable_name = new_value”
(6)静态模式
静态模式使用自动变量和通配符,可以将几百个目标的编译规则用很少的代码来实现。很强大的功能。格式,
<targets ...>: <target-pattern>: <prereq-patterns ...>
targets定义了一系列的目标文件,可以有通配符。是目标的一个集合。
target-parrtern是指明了targets的模式,也就是的目标集模式。
prereq-parrterns是目标的依赖模式,它对target-parrtern形成的模式再进行一次依赖目标的定义。
如果我们的<target-parrtern>定义成“%.o”,意 思是我们的<target>集合中都是以“.o”结尾的,而如果我们的<prereq-parrterns>定义成“%.c”, 意思是对<target-parrtern>所形成的目标集进行二次定义,其计算方法是,取<target-parrtern> 模式中的“%”(也就是去掉了[.o]这个结尾),并为其加上[.c]这个结尾,形成的新集合。
例子:
objects = foo.o bar.o
all: $(objects)
$(objects): %.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
等效为,
foo.o : foo.c
$(CC) -c $(CFLAGS) foo.c -o foo.o
bar.o : bar.c
$(CC) -c $(CFLAGS) bar.c -o bar.o
如果待编译的目标很多,静态模式可以发挥很大的威力。
%不是通配符。通配符包括:* ? …
通配符在规则中可以自动扩展,但设置在变量中或在函数的参数中通配符一般不能正常扩展