标签:
- objects = foo.o bar.o
- all: $(objects)
- $(CC) $(CFLAGS) -o -o $@ $^
- $(objects): %.o: %.c
- $(CC) -c $(CFLAGS) $< -o $@
上面的例子中,指明了我们的目标从$object中获取,“%.o”表明要所有以“.o”结尾的目标,也就是“foo.o bar.o”,也就是变量$object集合的模式,而依赖模式“%.c”则取模式“%.o”的“%”,也就是“foobar”,并为其加下“.c”的后缀,于是,我们的依赖目标就是“foo.cbar.c”。而命令中的“$<”和“$@”则是自动化变量,“$<”表示所有的依赖目标集(也就是“foo.c bar.c”),“$@”表示目标集(也就是oo.o bar.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
这是一个进行了提升的列子:
- files = foo.elc bar.o lose.o
- $(filter %.o,$(files)): %.o: %.c
- $(CC) -c $(CFLAGS) $< -o $@
- $(filter %.elc,$(files)): %.elc: %.el
- emacs -f batch-byte-compile $<
使用了filter进行单独过滤处理。
-
号,会标记所有后面的命令都是返回成功,也就是忽略失败。
@
号,会在make的时候,只是执行命令,而不输出命令本身。
make的 -n
参数,加上这个参数之后,只会展开命令,而不真的执行,可以帮助调试脚本。
.PHONY:clean
用来定一个伪目标,比如这里定义了一个清理操作。
[Tab]键后面跟着的会被当作命令来执行。多个命令有依赖关系的时候,要写在一行,并且用分号分隔。
=、:=、?=、+=
的区别,=
可以在前面的代码用后面的变量,:=
则不可以。?=
被赋值的变量如果没有定义过,就是等于后面的值,如果定义过,则什么都不做。+=
用于追加。
override
定义了一个覆盖操作。
有两个变量,一个是SHELL,一个是 MAKEFLAGS ,这两个变量不管你是否export,其总是要传递到下层Makefile中,其他环境变量需要export 导出一下。但是make命令中的有几个参数并不往下传递,它们是“-C”,“-f”,“-h”“-o”和“-W”(有关Makefile参数的细节将在后面说明)
MAKEFILES这个环境变量,执行make的时候,会进行一个类似include的动作。一般不建议使用.
里主要包含了五个东西:显式规则、隐晦规则、变量定义、文件指示和注释。
- 显式规则。显式规则说明了,如何生成一个或多的的目标文件。这是由Makefile的书写者明显指出,要生成的文件,文件的依赖文件,生成的命令。
-
- 隐晦规则。由于我们的make有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略地书写Makefile,这是由make所支持的。
-
- 变量的定义。在Makefile中我们要定义一系列的变量,变量一般都是字符串,这个有点你C语言中的宏,当Makefile被执行时,其中的变量都会被扩展到相应的引用位置上。
-
- 文件指示。其包括了三个部分,一个是在一个Makefile中引用另一个Makefile,就像C语言中的include一样;另一个是指根据某些情况指定Makefile中的有效部分,就像C语言中的预编译#if一样;还有就是定义一个多行的命令。有关这一部分的内容,我会在后续的部分中讲述。
-
- 注释。Makefile中只有行注释,和UNIX的Shell脚本一样,其注释是用“#”字符,这个就像C/C++中的“//”一样。如果你要在你的Makefile中使用“#”字符,可以用反斜框进行转义,如:“\#”。
变量替换
- foo:=a.o b.o c.o
- bar:=$(foo:.o=.c)
理解为bar的值等于,foo里面的值将.o替换为.c之后。
变量再当变量
- x = y
- y = z
- a := $($(x))
这个表达式a=的值等于z;
多层变量配合函数
- x = variable1
- variable2 := Hello
- y = $(subst 1,2,$(x))
- z = y
- a := $($($(z)))
“$($($(z)))”扩展为“$($(y))”,而其再次被扩展为“$($(subst 1,2,$(x)))”。$(x)的值是“variable1”,subst函数把“variable1”中的所有“1”字串替换成“2”字串,于是,“variable1”变成“variable2”,再取其值,所以,最终,$(a)的值就是$(variable2)的值—— “Hello”。
变量名组合
- first_second = Hello
- a = first
- b = second
- all = $($a_$b)
这里的“$a_$b”组成了“first_second”,于是,$(all)的值就是“Hello”。
“函数”和“条件语句”一同使用
- ifdef do_sort
- func := sort
- else
- func := strip
- endif
-
- bar := a d b g q c
-
- foo := $($(func) $(bar))
这个示例中,如果定义了“do_sort”,那么:foo := $(sort a d b g q c),于是$(foo)的值就是“a b c d g q”,而如果没有定义“do_sort”,那么:foo := $(sort a d bg q c),调用的就是strip函数。
某个目标的局部变量
- prog : CFLAGS = -g
- prog : prog.o foo.o bar.o
- $(CC) $(CFLAGS) prog.o foo.o bar.o
在这个示例中,不管全局的$(CFLAGS)的值是什么,在prog目标,以及其所引发的所有规则中(prog.o foo.o bar.o的规则),$(CFLAGS)的值都是“-g”
$@
表示规则中的目标文件集。在模式规则中,如果有多个目标,那么,"$@"就是匹配于目标中模式定义的集合。
$%
仅当目标是函数库文件中,表示规则中的目标成员名。例如,如果一个目标是"foo.a(bar.o)",那么,"$%“就是"bar.o”,"$@“就是"foo.a”。如果目标不是函数库文件(Unix下是
[.a],Windows下是[.lib]),那么,其值为空。
$<
依赖目标中的第一个目标名字。如果依赖目标是以模式(即"%")定义的,那么"$<"将是符合模式的一系列的文件集。注意,其是一个一个取出来的。
$?
所有比目标新的依赖目标的集合。以空格分隔。
$^
所有的依赖目标的集合。以空格分隔。如果在依赖目标中有多个重复的,那个这个变量会去除重复的依赖目标,只保留一份。
$+
这个变量很像"$^",也是所有依赖目标的集合。只是它不去除重复的依赖目标。
$*
这个变量表示目标模式中"%“及其之前的部分。如果目标是"dir/a.foo.b”,并且目标的模式是"a.%.b",那么,"$“的值就是"dir /a.foo”。这个变量对于构造有关联的文件名是比较有较。
如果目标中没有模式的定义,那么"$“也就不能被推导出,但是,如果目标文件的后缀是 make所识别的,那么”$“就是除了后缀的那一部分。
例如:如果目标是"foo.c”,因为".c"是make所能识别的后缀名,所以,"$“的值就是"foo”。这个特性是GNU make的,很有可能不兼容于其它版本的make,所以,你应该尽量避免使用"$“,除非是在隐含规则或是静态模式中。如果目标中的后缀是make所不能识别的,那么”$"就是空值。
$(@D)
表示"$@“的目录部分(不以斜杠作为结尾),如果”$@“值是"dir/foo.o”,那么"$(@D)“就是"dir”,而如果"$@“中没有包含斜杠的话,其值就是”."(当前目录)。
$(@F)
表示"$@“的文件部分,如果”$@“值是"dir/foo.o”,那么"$(@F)“就是"foo.o”,"$(@F)“相当于函数”$(notdir $@)"。
"$(*D)" "$(*F)"
和上面所述的同理,也是取文件的目录部分和文件部分。对于上面的那个例子,"$(*D)“返回"dir”,而"$(*F)“返回"foo”
"$(%D)" "$(%F)"
分别表示了函数包文件成员的目录部分和文件部分。这对于形同"archive(member)"形式的目标中的"member"中包含了不同的目录很有用。
"$(<D)" "$(<F)"
分别表示依赖文件的目录部分和文件部分。
"$(^D)" "$(^F)"
分别表示所有依赖文件的目录部分和文件部分。(无相同的)
"$(+D)" "$(+F)"
分别表示所有依赖文件的目录部分和文件部分。(可以有相同的)
"$(?D)" "$(?F)"
分别表示被更新的依赖文件的目录部分和文件部分。
最后想提醒一下的是,对于"$<",为了避免产生不必要的麻烦,我们最好给$后面的那个特定字符都加上圆括号,比如,"$(< )“就要比”$<"要好一些。
还得要注意的是,这些变量只使用在规则的命令中,而且一般都是"显式规则"和"静态模式规则"(参见前面"书写规则"一章)。其在隐含规则中并没有意义。
标签:
原文地址:http://www.cnblogs.com/rexonor/p/4876267.html