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文件。

 

 

伪目标:没有依赖文件,可以一口气生成多个目标文件。

linux下Makefile全解(一)

$@自动化变量:表示目标的集合,就像一个数组,一次取出一个目标。

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

posted @ 2015-01-10 20:08  苍月代表我  阅读(623)  评论(0编辑  收藏  举报