linux下Makefile全解(一)
总的来说,在我们执行make命令的时候,系统会找到当前目录下的Makefile文件,编译这个文件中所有的源文件生成目标文件。类似于在我们用VC的时候“编译”这个过程。
makefile分为显示规则,隐晦规则,变量定义,文件指示和注释。
显示规则: 包括要生成的文件,依赖文件,生成的命令等。
隐晦规则:makefile的自动推倒功能。
变量的定义:类似于C语言的宏。
文件指示:一个makefile中包含另外一个makefile,或者指定makefile中有效部分。
注释:这里不做解释,使用符号,#.
注意:makefile中的命令是以tab键为开始的。
makefile规则最简单的也就是:
目标文件:依赖文件
编译方法
其中命令前面要有tab键。
看下通配符:主要有*,?,[...]。
vpath:文件搜寻
格式:
vpath 模式 搜寻目录
例如 vpath %.c ../headers 搜寻../headers目录下以.c结尾的文件。
当然如果模式一样的话,搜寻的目录多,可以按顺序搜索例如
vpath %.c foo
vpath % blish
vpath %.c bar
按顺序搜索foo blish bar目录下的.c文件。
伪目标:没有依赖文件,可以一口气生成多个目标文件。
$@自动化变量:表示目标的集合,就像一个数组,一次取出一个目标。
342222196407074412 342222196903274421
静态模式:
语法:
<targets ...>: <target-pattern>: <prereq-patterns ...>
<commands>
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 $@
上面的例子中,指明了我们的目标从$object 中获取,"%.o"表明要所有以".o"结尾的目标,也就是"foo.o bar.o",
也就是变量$object 集合的模式,而依赖模式"%.c"则取模式"%.o"的"%",也就是"foo bar",并为其
加下".c"的后缀,于是,我们的依赖目标就是"foo.c bar.c"。而命令中的"$<"和"$@"则是自动化变量,
"$<"表示所有的依赖目标集(也就是"foo.c bar.c"),"$@"表示目标集(也就是"foo.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 %.o,$(files))表示调用 Makefile 的 filter 函数,过滤"$filter"集,只要其中模式为"%.o"的内容。其的
它内容,我就不用多说了吧。这个例字展示了 Makefile 中更大的弹性。
自动生成依赖性:
在 Makefile 中,我们的依赖关系可能会需要包含一系列的头文件,比如,如果我们的 main.c 中有一句"#include
"defs.h"",那么我们的依赖关系应该是:
main.o : main.c defs.h
大多数的 C/C++编译器都支持一个"-M"的选页,即自动找寻源文件中包含
的头文件,并生成一个依赖关系。例如,如果我们执行下面的命令:
cc -M main.c
其输出是:
main.o : main.c defs.h
如果你使用 GNU 的 C/C++编译器,你得用"-MM"参数。
gcc -MM main.c 的输出则是:
main.o: main.c defs.h
变量高级用法
这里介绍两种变量的高级使用方法,第一种是变量值的替换。
我们可以替换变量中的共有的部分,其格式是"$(var:a=b)"或是"${var:a=b}",其意思是,把变量"var"
中所有以"a"字串"结尾"的"a"替换成"b"字串。这里的"结尾"意思是"空格"或是"结束符"。
还是看一个示例吧:
foo := a.o b.o c.o bar := $(foo:.o=.c)
这个示例中,我们先定义了一个"$(foo)"变量,而第二行的意思是把"$(foo)"中所有以".o"字串"结尾"
全部替换成".c",所以我们的"$(bar)"的值就是"a.c b.c c.c"。
另外一种变量替换的技术是以"静态模式"(参见前面章节)定义的,如:
foo := a.o b.o c.o
bar := $(foo:%.o=%.c)
这依赖于被替换字串中的有相同的模式,模式中必须包含一个"%"字符,这个例子同样让$(bar)变量的值为"a.c b.c c.c"。
第二种高级用法是二二"把变量的值再当成变量"。先看一个例子:
x = y y = z
a := $($(x))
在这个例子中,$(x)的值是"y",所以$($(x))就是$(y),于是$(a)的值就是"z"。(注意,是"x=y",而不
是"x=$(y)")
追加变量值:
我们可以使用"+="操作符给变量追加值,如:
objects = main.o foo.o bar.o utils.o objects += another.o
于是,我们的$(objects)值变成:"main.o foo.o bar.o utils.o another.o"(another.o 被追加进去了)
override 指示符:
如果有变量是通常 make 的命令行参数设置的,那么 Makefile 中对这个变量的赋值会被忽略。如果你想在 Makefile
中设置这类参数的值,那么,你可以使用"override"指示符。其语法是:
override <variable> = <value>
override <variable> := <value>
当然,你还可以追加:
override <variable> += <more text>
对于多行的变量定义,我们用 define 指示符,在 define 指示符前,也同样可以使用 ovveride 指示符,如:
override define foo bar
endef