GNU make的工做分为两个阶段。在第一阶段,make读取makefile文件、内置变量及其值、隐含规则和具体规则、构造全部目标的依赖关系以及全部目标各自的依赖等。在第二阶段,make决定须要从新构造的目标并使用必要的规则进行工做。shell
make工做第一阶段发生的扩展是当即扩展,直接把变量和函数扩展为makefile文件语句的一部分。make工做第二阶段发生的扩展称为延时扩展。数据库
make[option] [target]express
-Cdir :在读入makefile以前,把路径切换到dir下。若是同时使用几个‘-C’选项,则eachis interpreted relative to the previous one。app
-d :在正常处理后打印调试信息。ide
-e :设置环境变量的优先权高于makefile文件变量的优先权。函数
-ffile :将file设置为makefile文件。ui
-i :忽略在执行重建文件命令时产生的全部错误。spa
-Idir :指定搜寻makefile文件的路径。若是同时使用几个‘-I’选项,则按照次序搜寻这些路径。命令行
-k :在出现错误后,尽量的继续执行。也就是说当一个目标建立失败后,全部依靠它的目标文件将不能重建,而这些目标的其它依赖则可继续处理。debug
-n :打印要执行的命令,但却不执行它们。
-ofile :即便文件file比它的依赖旧,也不重建该文件。
-p :打印数据库,其中的数据来自读入makefile文件的结果;打印以后执行。
make –qp 打印数据库后不执行。
make –p –f/dev/null 打印预约义的规则和变量的数据库。
-q :不打印也不执行命令。若是全部目标都已经更新到最新,make的退出状态是0;若是一部分须要更新,退出状态是1;若是make遇到错误,退出状态是2。
-r :禁止使用预约义的隐含规则,同时也清除了缺省的后缀列表和后缀规则。注意缺省的变量仍然有效。
-R :禁止使用内建的规则变量。‘-R’自动使‘-r’生效。
-s :不回显执行的命令。
-S :使‘-k’失效。除非在递归调用make时,经过变量MAKEFLAGS从上层make继承‘-k’,或环境中设置了选项‘-k’,不然没有必要使用该选项。
-t :标记文件已经更新到最新,但实际却没有更新它们。
-w :打印执行makefile文件时涉及的全部工做目录。
-Wfile :Pretendthat the file has been just modified。在和‘-n’一块儿使用时,将代表更改该文件会发生什么。若是没有和‘-n’一块儿使用,那么它和在运行make以前对该文件使用 touch命令的结果几乎同样,但使用该选项make只是在想象中更改该文件的时间戳。
缺省状况下,make按顺序寻找makefile文件:GNUmakefile、makefile和Makefile。若是使用非标准名字的 makefile文件,可使用‘-f’参数指定makefile文件。若是使用多个‘-f’参数,全部的makefile文件按顺序发生做用。一旦使用 了‘-f’参数,将再也不自动检查是否存在标准名字的makefile文件。
include指令告诉make暂停读取当前的makefile文件,先读完include指定的makefile文件后再继续。include指令在makefile文件占单独一行,其格式以下:
includefilename
行首的多余空格是容许的,注意不能以Tab开始。由于,以Tab开始的行,make认为是命令行。多个文件名之间也以空格隔开,多余的空格被忽略。文件名能够包含变量及函数调用,它们在处理时由make进行扩展。
若是定义了环境变量MAKEFILES,make认为该变量的值是一列附加的makefile文件名,文件名之间由空格隔开,而且这些 makefile文件应该首先读取,读取方式和include指令的方式基本相同。值得注意的是,缺省最终目标不会出如今这些makefile文件中,而 且若是一些makefile文件没有找到也不会出现任何错误信息。
正常状况下,虽然目标/依赖文件名中不含有路径,其实这种文件名的路径部分是空值,表明的是当前目录(./)。若是咱们要在文件名中给出路径,则有两种方法:
一、绝对路径,必须以‘/’开头;
二、相对路径,非‘/’开头的全部路径。
变量VPATH定义了一组搜索路径。若是一个文件在文件名给出的路径中不存在,就在(VPATH+文件名中的路径)的路径中搜索该文件。
在VPATH定义中,路径的名字由冒号或空格分开。
vpath容许对符合某一格式的文件名指定一个搜寻路径,路径由冒号或空格隔开。pattern是一个包含‘%’的字符串,例如:
vpath%.h $(INCDIR)
若是有多个vpath和一个文件名匹配,则make按次序搜索这些vpath指定的路径。
清除和该格式相关联的搜寻路径。
清除前面全部由vapth指定的搜寻路径。
1. 若是目标文件是根据文件名搜索获得的,此时$@表明文件名。
2. 若是目标文件是经过搜索其它路径获得的,此时$@表明文件名。可是若是搜索路径出如今变量GPATH中,$@将表明(搜索路径+文件名)。
3. 若是目标文件没有被搜索到,意味着须要执行规则命令来建立该目标文件,此时$@表明文件名。
4. 若是依赖文件是根据文件名搜索获得的,并且该依赖文件不须要被更新,此时$<表明文件名。
5. 若是依赖文件是经过搜索其它路径获得的,并且该依赖文件不须要被更新,此时$<表明(搜索路径+文件名)。
6. 若是依赖文件没有被搜索到或是须要被更新,此时$<表明的是当它做为目标文件被建立或更新的规则命令中的$@。
makefile的基本单位是规则。每一条规则说明一个目标,除了描述该目标所依赖的文件,还要指明生成和更新该目标所需的命令。规则的格式为:
targetsruleop [prerequisites] [;recipe]
{<tab>recipe}
targets :目标文件列表。
ruleop :分割目标文件与依赖文件的符号,常见的是‘:’也可使用其它一些符号。
‘::’用于一个目标有多个规则的情形;
‘:^’将依赖文件和目标文件已有的依赖文件合起来,成为新的依赖文件列表;
‘:-’清除目标文件原有的依赖文件,将新的依赖文件做为目标的依赖文件列表;
‘:!’对每一个更新过的依赖文件都执行一次命令菜单;
‘:|’只在隐含规则中使用。
prerequisites:目标所依赖的文件列表。
recipe:命令菜单,从新生成目标文件的命令,能够在tab以后加上如下符号。
-:忽略本命令行的错误返回,继续执行。不然,make会中止执行;
+:make始终执行本命令行;
@:执行本命令行时不在标准输出上显示。
makefile文件的一些书写规则:
1.每个命令行的开头都要是一个tab;
2.命令行之间能够插入任意多个空行,这些空行也要以tab开头;
3.第一条命令能够直接跟在依赖文件列表后面,用‘;’隔开;
4.若是一行过长,能够在到达右边界以前放入一个“\”符号,并且“\”和新的一行之间不能有空白;
5.注释以‘#’开始,以换行符结束,若是其它地方用到‘#’,要用双引号引用;
6.makefile中涉及的文件名容许使用通配符。
规则不论其形式如何,都按相同的方式扩展:
immediate: immediate ; deferred
deferred
目标和依赖部分都当即扩展,命令一般都是延时扩展。
通常状况下规则的次序可有可无,但决定缺省最终目标时倒是例外。缺省最终目标是没有指定最终目标时make指定的最终目标。缺省最终目标是 makefile文件中的第一条规则的目标。若是第一条规则有多个目标,只有第一个目标被认为是缺省最终目标。因此,咱们编写makefile文件时,通 常将第一个规则的目标定为编译所有程序(设定一个称为‘all’的目标)。
有两种例外的状况:以‘.’开始的目标不是缺省最终目标;格式规则定义的目标不是缺省最终目标。
格式规则是指定多个目标并可以根据每一个目标名构造对应的依赖名的规则。要使用格式规则,目标文件名必须匹配目标格式,并且符合依赖格式的文件必须存在或能够建立。
格式规则的语法格式:
targets...: target-pattern: dep-patterns ...
commands
...
目标能够含有通配符。target-pattern表示目标格式,dep-patterns表示依赖格式,一般都包含字符‘%’。目标格式匹配目标时,‘%’表明的字符串称为径(stem)。每一个依赖名使用径代替‘%’。在格式规则中使用的‘%’扩展是在全部变量和函数扩展之后进行的,而全部的变量和函数扩展都是在makefile文件读入时完成的。
当目标格式中不包含‘/’,目标文件名中的路径名部分首先被去除,而后再进行匹配,最后路径名将会加在产生的依赖前面。
在依赖格式中不包含‘%’也是合法的,此时对全部目标来讲,依赖是相同的。
OBJ= hello1.o hello2.o
all:$(OBJ)
$(OBJ):%.o: %.c
……
上面的规则展开后等价于下面两条规则:
hello1.o: hello1.c
……
hello1.o: hello2.c
……
每个目标必须和目标格式匹配,若是不符则产生警告。若是您有一系列文件,其中仅有一部分和格式匹配,您可使用filter函数把不符合的文件移走。
FILE= test. c test1.o test2.o
$(filter %.o, $(FILE) ): %.o: %.c
……
若是一个目标文件符合对于多个格式规则,使用最先出现的格式规则。本身编写的格式规则比预约义的隐含规则优先。
格式规则只能用于规则中指定的目标。而隐含规则能够应用于任何与它匹配的目标,前提是这些目标没有与之对应的规则,并且隐含规则中对应的依赖也能够被搜寻到。若是有多条隐含规则适合,仅执行其中一条规则,按照隐含规则定义的顺序进行选择。
若是根据依赖推断出某一个目标文件须要更新,而对应的规则却没有给出命令,这时make就会从隐含规则中查找符合该目标格式的隐含规则,并根据该隐 含规则生成对应的依赖文件(注意隐含规则使用的依赖文件名是隐含规则根据目标格式本身生成的,而不是使用目标文件原有的依赖文件),而后用隐含规则中的命 令来更新改目标文件。
若是一条规则的其中一个依赖文件没有经过路径搜索找到,则make会尝试使用隐含规则来建立该文件,若是没有对应的隐含规则能够建立该文件,就会返回error。
能够在makefile文件中重载这些隐含规则。也能够取消预约义的隐含规则,只要不在后面写命令就能够了。make命令的参数‘-r’也能把缺省的后缀列表清空,从而删除全部预约义的隐含规则。
若是预约义的隐含规则的依赖出如今后缀列表中,则该预约义的隐含规则也称为后缀规则。若是更改了后缀列表,那些依赖的后缀没有出如今新后缀列表中的预约义的隐含规则将被禁止。
后缀是特殊目标.SUFFIXES的依赖名。例如:
.SUFFIXES: # 删除缺省的后缀列表
.SUFFIXES:.cpp .obj #把.cpp和.obj添加到后缀列表中。
有时生成一个文件须要使用多个隐含规则组成的序列,这样的隐含规则序列称为隐含规则链。同一条隐含规则不能在隐含规则链中出现两次或两次以上。
一般状况下,任何在makefile文件中说起的目标和依赖都不是中间文件。可是,咱们能够特别指定一些文件为中间文件,只需将这些文件指定为特殊目标.INTERMEDIATE的依赖。若是.INTERMEDIATE没有依赖文件,它将不会发生做用。
为了阻止自动删除中间文件,能够将须要保留的中间文件指定为特殊目标.SECONDARY的依赖。.SECONDARY的依赖被处理为中间文件,但它们永远不能自动删除。若是.SECONDARY没有依赖文件,则全部的目标都将被处理为中间文件。
也能够将一个隐含规则的目标格式做为特殊目标.PRECIOUS的依赖,这样就能够保留那些由该隐含规则建立的中间文件。
后缀规则已经被格式规则代替,分为单后缀和双后缀规则。
双后缀规则: 等同于格式规则:
.c.o: %.o: %.c
…… ……
单后缀规则: 等同于格式规则:
.c %: %.c
…… ……
后缀规则不能有任何属于它们本身的依赖,而格式规则能够有依赖文件。例如:
%.o:%.c hello.h
……
没有命令的后缀规则没有意义,它们并不像没有命令的格式规则那样移去之前的规则。
假设一个项目最后须要产生两个可执行文件,并且这两个文件是相互独立的,可使用假想目标来达到这种效果。一个假想目标跟一个正常的目标几乎是同样的,只是这个目标文件是不存在的。例如在makefile的最开始输入:
default: exec1 exec2
make把default作为它的主要目标,每次执行时都会尝试把default更新。可既然这个文件并不存在,make就会尝试运用该规则建立default,就检查它的依赖exec1,exec2是否须要更新,若是须要,就把它们更新,从而达到咱们的目的。
假想目标也能够用来描述一组动做。例如,须要把全部make产生的文件删除,你能够在makefile里设立这样一个规则:
clean:
rm *.o
使用命令“make clean”,make就会把clean作为它的主要目标,执行rm命令。可是若是恰巧存在一个名字为clean的文件,由于在这个规则里没有任何依赖文 件,因此这个目标文件必定是最新的了,因此即便用户使用命令“make clean”,也不会有任何事情发生。解决方法是标明全部的假想目标为.PHONY,这就告诉make不用检查它们是否存在,也不用查找任何隐含规则,直接假设指定的目标须要被更新。例如在makefile里加入下面这行规则:
.PHONY: clean
当假想目标A是假想目标B的依赖,则A将做为B的子程序,并且是先执行A中的命令,再执行B中的命令。例如,这里‘make cleanall’用来删除全部文件:
.PHONY:cleanall cleanobj cleansrc cleanheader
cleanall:cleanobj cleansrc clearnheader
cleanobj:
rm *.o
cleansrc:
rm *.c
cleanheader:
rm *.h
若是一个规则只有目标,没有依赖,也没有命令,并且该规则的目标也不存在,则make认为只要该规则运行,其目标就已被更新。这意味着全部以这种规则的目标为依赖的规则,它们的命令将总被执行。
cleanobj: FORCE
rm*.o
FORCE:
目标FORCR知足上面的条件,因此以其为依赖的目标clean将总执行命令。
还有一个办法能够强制执行一条规则中的命令,只要该规则的目标是假想目标,并且该假想目标没有依赖,并且该假想目标是主要目标的依赖,这样的话该规则的命令就必定会被执行。
.PHONY:all cleanobj
all:cleanobj ……
……
cleanobj:
rm *.o
.DEFAULT
.DEFAULT指定一些命令,这些命令应用于那些没能找到规则的目标。
具备多个目标的规则等同于多条独立的规则,这些规则除了目标不一样以外,其他部分彻底相同,意味着全部的目标有相同的依赖,相同的命令应用于全部目标,能够在命令中使用‘$@’区分实际的目标名称。
当一个目标出如今多条规则中时,全部的规则必须是同一类型:要么都是双冒号规则,要么都是普通规则。
若是它们都是双冒号规则,则它们之间都是相互独立的。双冒号规则实际就是将具备相同目标的多条规则相互分离,每一条双冒号规则都独立的运行,就像这些规则的目标不一样同样。每个双冒号规则都应该指定命令,若是没有指定命令,则会使用隐含规则。
若是它们都是普通规则。则在全部规则中说起的依赖将合并在一个依赖列表中。若是该目标比任何一个依赖旧,命令将被执行来重建该目标。可是若是有一条以上的规则为该目标文件指定命令,make将使用最后给出的规则,同时打印错误信息。
对每个源程序文件name.c有一个名为name.d的文件和它对应,该文件中列出了name.o所依赖的文件。根据name.c生成name.d的格式规则:
DEPEND=dependencies
depend:
@set -e;\
$(CC) -MM $(SRC)>$(DEPEND)
而后就可使用include命令直接将DEPEND文件读入。
include$(DEPEND)
用replacement string替换符合regularexpression的字符串,用法中的‘/’能够用任何其它字符代替,在下面的例子中咱们就使用了‘,’。
flags is:
n Substitute for just the nth occurrence ofthe regular expression.
g Globally substitute.
| sed 's,.∗\.c[ :]*,\1.o:,g'>
能够将输入中以.c结尾的字符串都置换为以.o的字符串,而后再输出。
Defines a sub-expression re. A subsequent reference of ‘\n’,where n is a number in the range 1–9。若是re是一个regularsub-expression,则‘\n’扩展为第n个re匹配的字符串。若是re不是一个regular sub-expression,则‘\n’扩展为第n个re自己。
Matches the single-character regularexpression or sub-expression immediately preceding it zero or more times. If *is the first character of a regular expression or sub-expression, it matchesitself.
Matches any single character in char-class.To include a ] in char class, it must be the first character. A range ofcharacters may be specified by separating the begin and end characters of therange with ‘-’, for example, a-z specifies the lowercase characters.
规则中的命令由一系列shell命令行组成,它们按顺序执行。除第一条命令行能够用分号附属在目标-依赖行后面外,全部的命令行必须以Tab开始。空白行与注释行可在命令行中间出现,处理时它们被忽略。可是必须注意,以Tab开始的空白行不是空白行,它是而命令。
能够在makefile文件中将make做为一个命令使用。例如,假设有一个子目录subdir,该目录中有它本身的makefile文件,能够按下述方式编写:
subsystem:
cd subdir && $(MAKE)
或者:
subsystem:
$(MAKE) -C subdir
注意递归调用make的命令老是使用变量MAKE。
缺省方式下,只有环境变量或在命令行中定义的变量才能传递给内层make。若是要将主makefile中的变量输出给子make,用export指令,格式以下:
exportvariable ……
要将阻止一些变量输出给子make,用unexport指令,格式以下:
unexportvariable ……
能够同时定义并输出一个变量:
exportvariable = value
若是您要将全部的变量都输出,您能够单独使用export。这就告诉make把export和unexport没有说起的变量通通输出,但 unexport说起的变量仍然不能输出,并且名字中含有字母、数字和下划线之外字符的变量将不能输出,这些变量只能使用export指令才能输出。
须要注意的是,有两个变量,一个是SHELL,一个是MAKEFLAGS,这两个变量无论是否export,其老是要传递到下层makefile中。
参数‘-C’,‘-f’,‘-o’和‘-W’即便在MAKEFLAGS中也不能向下传递。在命令行中使用的参数也将经过MAKEFLAGS传递给子make。若是你不想往下层传递参数,你能够:
subsystem:
cd subdir && $(MAKE) MAKEFLAGS=
变量MAKELEVEL的值在向下层传递时发生变化。该变量的值是字符型,它用十进制数表示层的深度。‘0’表明顶层make,‘1’表明子make,‘2’表明子-子-make,以此类推。
若是您使用几层make递归调用,使用‘-w’能够显示每一个make开始处理以及处理完成的目录。当使用‘-C’选项时,‘-w’选项已经自动打开。
可使用define指令定义固定次序的命令。若是前缀字符(@,-,和+)在引用固定次序的命令行中使用,则该前缀字符将应用到固定次序的每一行中。固定次序实际是一个变量,所以它的名字不能和其它的变量名冲突。
definename
……
endef
使用:
$(name)
在makefile文件读入时,除规则命令中的变量、‘=’右边的变量、以及使用define定义的变量此时不扩展外,makefile文件其它各个部分的变量和函数都将扩展。
变量名不能含有‘:’、‘#’、‘=’;前导或结尾空格。变量名是区分大小写的。
make将忽略环境变量SHELL的值,因此若是要使用变量SHELL,咱们必须本身定义。
变量名中也能够包含变量引用和函数调用,它们在读入时扩展。
除了空格,‘=’前面不能有tab或其它任何符号,不然都会被make看成变量名的一部分。‘=’后面的字符串能够包含任意字符,但会去除前面的全部空格和tab。
注意:变量值包含全部的结尾空格。
变量的定义能够出如今三个地方:
1.在makefile中定义;
2.在make命令行中定义。因为命令行中用空格做为不一样参数的分隔符,所以当变量值中含有空格时,要用引号将整个变量值包含起来。
3.载入环境变量定义。
make命令行变量定义>makefile中变量定义>shell中变量定义>内定义变量定义
递归调用扩展型变量。适用于那些须要根据上下文才能肯定值的变量的定义。
若是该变量值包含对其它变量的引用,这些引用在变量替换时才被扩展。若是在定义中使用函数,则函数只有在完成变量替换时才会执行。
仅在变量尚未定义的状况下有效。
简单扩展型变量,在定义的时候变量的值就肯定了。适用于那些可以在一开始就肯定值的变量的定义。
若是该变量值包含对其它变量的引用,这些引用在定义的时候就已经展开。若是在定义中使用函数,则函数在定义的时候就已经执行。
变量原来的值加上一个空格,再加上后面的字符串,做为新的变量值。
若是变量在之前没有定义过,则‘+=’的做用和‘=’相同。若是变量在之前定义过,‘+=’的做用依赖于原始定义的特点。
make中变量的值通常是全局性的,特定目标变量的值是个例外:
target... : variable-assignmen
或这样:
target... : override variable-assignmen
variable-assignmen使用任何赋值方式都是有效的:=、:=、+=、?=。在命令行中定义的变量值优先,而使用override定义的变量值优先。
当定义一个特定目标变量时,该变量值对特定目标target ...的全部依赖有效,除非这些依赖用它们本身的特定目标变量值将该变量重载。
使用特定格式变量的值,能够为匹配指定格式的目标定义变量。
pattern... : variable-assignment
或这样:
pattern... : override variable-assignment
这里的pattern是‘%’格式。
variable-assignmen使用任何赋值方式都是有效的:=、:=、+=、?=。在命令行中定义的变量值优先,而使用override定义的变量值优先。
$(变量名)
当变量只有单个字符时,能够省略括号。
${SRC:oldend=newend}
若是SRC中某个字以字符串“oldend”的结尾,则将“oldend”替换为“newend”。
例如:OBJ=${SRC:.c=.o}
${SRC:oldpattern=newpattern}
pattern中包含‘%’,将SRC中的oldpattern替换为newpattern,‘%’表明的部分不改变。
例如:OBJ=$(SRC:$(SRCDIR)/%.c=$(OBJDIR)/%.o)
$@ 目标文件名,若是目标是形如libname(member)的库成员,$@等于库名libname。
$% 目标文件名,若是目标是形如libname(member)的库成员,$%等于成员名member。注意此时$%再也不遵循目录搜索的规则,只能表明member。
$> 目标文件名,只能用于目标文件是库成员的情形,$>等于库名libname。
$* 若是目标名以一种内建的后缀结尾,$*为目标名去掉其后缀的部分。若是目标名不之内建的后缀结尾,则$*在该规则中设置为空值。
用于表示依赖文件的内建变量不区分库名和成员名,仍然表明整个libname(member)。
$< 第一个依赖文件名。
$? 全部依赖文件中比目标文件新的文件列表。
$^ 目标文件在本规则中的全部依赖文件,省略了重复的依赖。
$+ 目标文件在本规则中的全部依赖文件,保留了重复的依赖。
$& 目标文件在全部规则中的全部依赖文件;
如下两个内定义变量对以上变量通用(#能够是@,*,%,>,&,^,+,<,?):
$(#D) $#的路径部分,结尾‘/’已经移走。若是$?不包含‘/’,则值是‘.’。
$(#F) $#的文件名部分
$$@ 目标文件名,若是目标是形如libname(member)的库成员,$$@等于库名libname。
$$% 目标文件名,若是目标是形如libname(member)的库成员,$$%等于成员名member。
$$* 若是目标名以一种内建的后缀结尾,
∗为目标名去掉其后缀的部分。如果目标名不以内建的后缀结尾,则
*在该规则中设置为空值。
$$> 目标文件名,只能用于目标文件是库成员的情形,等于库名libname。
d 仅展开路径,不包括文件名
b 展开文件名,不包括扩展名
f 展开文件名,包括扩展名
FILE=/user/myprog/main.c
$(FILE:d) = /user/myprog
$(FILE:b) = main
$(FILE:f) = main.c
$(FILE:db) = /user/myprog/main
$(FILE:df) = /user/myprog/main.c
文件名前面没有任何目录的文件被认为是位于当前工做目录下,路径名为‘.’。
make中的通配符是*、?和[…]。通配符在规则中(目标、依赖和命令)能够正常使用,但在变量定义中或在函数的参数中通配符通常不能正常使用。
objects= *.o
变量objects的值实际就是字符串“*.o”。
若是通配符前面是反斜杠‘\’,则该通配符失去通配能力。
在指令行前面容许有多余的空格,可是不容许有Tab。若是一行以Tab开始,那么该行将被认为是规则的命令行。
对于没有else指令的条件语句的语法为:
conditional-directive
……
endif
完整的条件语句的语法为:
conditional-directive
……
else
……
endif
扩展参数arg一、arg2中的全部变量引用,而且比较它们。
函数调用的格式以下:
$(functionarg1, arg2, ...)
或这样:
${functionarg1, arg2, ...}
参数和函数名之间是用空格或Tab隔开。每个参数通过变量替换或函数调用处理,最终获得参数的值。注意变量替换是按照变量在参数中出现的次序依次进行的。
逗号,空格和不成对出现的圆括号、大括号不能做为文本出如今参数中,若是须要使用这些字符,首先定义变量comma和space:
comma:=,
empty:=
space:=$(empty)$(empty)
在文本text中使用to替换每一处from。
寻找text中符合pattern的字,并用replacement替换它们。这里的pattern中包含‘%’。若是replacement中也含有‘%’,就用和pattern中‘%’匹配的部分代替。
去掉前导和结尾空格,并将字中间的多个空格压缩为单个空格。
在text中搜寻string,若是找到返回值是string,不然返回值为空。
返回在text中由空格隔开且匹配pattern...的字,并将不符合pattern...的字移出。
filter的反函数。
将text中的字按字母排序,并取掉重复的字。输出的是由空格隔开的字的列表。
函数的参数是一组文件名,文件名之间用空格隔开(前导和结尾空格被忽略)。列表中的每个文件名都采用相同的方式转换,并且结果用单个空格串联在一块儿。
抽取每个文件名的路径部分,文件名的路径部分包括从文件名的开始到最后一个斜杠(含斜杠)以前的一切字符。若是文件名中没有斜杠,路径部分是“./”。
抽取每个文件名中除路径部分外一切字符(文件名)。若是一个文件名仅包含路径部分(以‘/’结束),则结果为空。
抽取每个文件名的后缀。若是文件名没有后缀,则结果为空。
抽取每个文件名中除后缀外一切字符。
将suffix附加在每个文件名的后面。
将preffix附加在每个文件名的前面。
两个参数的第一个字串联起来造成结果的第一个字,两个参数的第二个字串联起来造成结果的第二个字,以此类推。若是一个参数比另外一个参数的字多,则多余的字原封不动的拷贝到结果中。
返回text中的第n个字。n的合法值从1开始。若是n超出范围,则返回空值。
返回text中从第s个字开始到第e个字结束的字。s、e的合法值从1开始。若是s超出范围,则返回空值;若是e超出范围,则返回从第s个字开始到text结束的全部字;若是s比e大,不返回任何值。
返回text中字的数目。例如能够获得text中的最后一个字:
$(word$(words text),text)
返回第一个字。
pattern是一个文件名格式,能够包含通配符,也能够包含有目录。wildcard函数将返回和pattern相符合的全部文件名。例如能够获得全部的源文件:
SRC=$(wildcard$(SRCDIR)/*.c)
$(foreachvar,list,text)
把list中的字逐一取出赋给变量var,而后再执行text。每一次text会返回一个字。text所返回的每一个字会以空格分隔,当整个循环结束时,foreach函数的返回值由text所返回的全部字组成(以空格分隔)。
find_files= $(wildcard $(dir)/*)
dirs:= /src /inc
files:= $(foreach dir,$(dirs),$(find_files))
在定义变量find_file时,使用了=,所以该变量是递归调用型变量,这样find_file的值中的函数将在变量替换时执行。
$(ifcondition,then-part[,else-part])
首先把condition的前导/结尾空格去掉,而后扩展。若是扩展结果非空,则condition为真;若是扩展结果为空,则condition为假。
若是condition为真,计算then-part的值,并将该值做为整个函数的返回值。
若是condition为假,计算else-part的值,并将该值做为整个函数的返回值;若是else-part不存在,函数返回空值。
$(callvariable,param1,param2,...)
将每个param赋值给临时变量$(1)、$(2)等;变量$(0)的值是变量variable。在给临时变量赋值之前首先扩展param。
variable是一个变量名,而不是对该变量的引用。若是变量名是内建函数名,则该内建函数将被执行。
call函数的目的就是经过在变量variable中使用临时变量$(1)、$(2)等来完成必定的功能,临时变量$(1)、$(2)等就是经过call函数进行赋值的。例如:
reverse= $(2) $(1)
foo= $(call reverse,a,b)
$(originvariable)
函数origin的结果以下:
undefined :variable没有定义。
default :variable是缺省定义。若是从新定义了一个缺省变量,将返回下面的值。
environment :variable是环境变量定义,选项‘-e’没有打开。
file :variable在makefile中定义。
command line :variable在命令行中定义。
override :variable在makefile中用override指令定义。
automatic :variable是自动变量,定义它是为了执行每一个规则中的命令。
environment override:variable是环境变量定义,选项‘-e’打开。
虽然在规则的命令中使用的就是shell命令,可是若是想利用shell命令的输出结果,就须要使用shell函数。shell函数的参数就是shell命令,该函数把shell命令的输出做为函数的返回值:
contents:= $(shell cat hello.c)
当一个库做为目标时,和普通目标文件的使用相同,并可使用各类建立库的方法来建立或更新目标库。
当一个库做为依赖时,可使用
1.库文件的文件名(能够含有路径)。
2.‘-lname’。make首先将‘-lname’替换为libname.so,并在当前路径下、VPATH指定的路径下、与vpath匹配的 路径下,以及/lib,/usr/lib和/usr/local/lib下进行搜索。若是没有找到libname.so文件,接着将‘-lname’替换 为libname.a,仍在上述目录下进行搜索。具体替换的方式能够经过变量.LIBPATTERNS设置,缺省值是“lib%.so lib%.a”。注意name中不能包含路径名。
若是使用第二种方法,最好可以保证库可以被找到并且不须要被更新,此时$<表明的是(搜索路 径+libname.so/libname.a)。若是库没有被搜索到或是须要被更新,则根据目录搜寻原则,此时$<表明的是把‘-lname’做 为目标文件建立或更新的规则命令中的$@。可是若是‘-lname’做为目标,‘-lname’就不会再进行上述的名字替换。这样的话根据目录搜索的原 则$@可能会表明:-lname或(搜索路径+-lname)。因此原规则(库做为依赖的规则)中的$<将失去它的做用,对编写规则的命令很不利。
因此若是库做为依赖有可能找不到或者须要被更新时,最好使用第一种形式。
库成员也能够用做目标或依赖。使用‘libname(member1 member2 …)’的格式。这种格式只能在目标和依赖中使用,不能出如今规则的命令中。
当库成员做为目标时,更新库成员的命令必须使用ar。例如:
mylib.a(hello.o):hello.o
ar cr mylib.a hello.o
$@等于库名libname,$@的取值遵循目录搜索规则。而$%等于成员名member,$%的取值再也不遵循目录搜索的规则,$%只能表明member。
当库成员做为依赖时,$<等于libname(member),$@的取值遵循目录搜索规则,有一点除外:若是依赖文件没有被搜索到或是须要 被更新,此时$<表明再也不是当它做为目标文件被建立或更新的规则命令中的$@,而是将$@中的libname替换为 libname(member)。
SHELL=/bin/sh # 设置shell
VPATH= #设置全部文件搜索的路径(或者在下面用vpath设置)
GPATH= #一般和VPATH(或者vpath)设置成一致的值
.SUFFIXES: # 清除原有的后缀列表
.SUFFIXES:.c .o # 设置makefile中隐含规则使用的后缀
CC= #使用的编译器(gcc/g++)
CFLAGS= #编译器的参数(-MM)
# 若是是debug版本就包含该变量的定义;若是是release版本就不包含该变量的定义。
DEBUG=1
ifdef DEBUG
SUFFIX:=.dbg
CFLAGS+= -g
else
SUFFIX:=
CFLAGS+= -O2
endif
EXECNAME:= # 生成的可执行文件的文件名
DEPEND:= # 存放关联信息的文件
# 下面三项将会应用于全部的源程序文件。
# 若是某源程序文件须要其它库或头文件的支持,则须要对该源程序文件进行单独处理。
LIB:= # 支持库,书写格式:-lname(对应的库为libname.so或libname.a)
INCDIR:= # 搜索头文件的目录
LIBDIR:= # 搜索库文件的目录
# 下面三个目录是肯定的
SRCDIR:= #全部存放源文件的目录
OBJDIR:= #全部存放目标文件的目录(一般全部的目标文件存放在同一个目
# 录下。要是存放在多个目录,还须要在makefile中指定各个目标
# 文件分别存放到哪一个目录。)
BINDIR:= #存放可执行文件的目录(通常也只有一个目录,理由同上。)
vpath %.c SRCDIR # 设置源程序文件的搜索目录
vpath %.h INCDIR # 设置头文件的搜索目录
vpath %.o OBJDIR # 设置目标文件的搜索目录
#如下的程序默认OBJDIR和BINDIR都只有一个目录
# SRC的值是全部源程序的文件名(包含路径)
SRC=$(foreach DIR,$(SRCDIR),$(wildcard$(DIR)/*.c))
# OBJ的值是全部目标文件的文件名(包含路径)
OBJ=$(addprefix $(OBJDIR)/,$(patsubst %.c,%.o$(SUFFIX),$(notdir$(SRC))))
# BIN的值是可执行文件的文件名(包含路径)
BIN=$(BINDIR)/$(EXECNAME)$(SUFFIX)
.PHONY:default compile install uninstallclean depend tags
# 默认目标,也就是主要目标。
# 若是默认目标的依赖是一个假想目标,该假想目标的命令就必定会被执行。
defaultall: depend compile tags
depend:
@set -e;\
$(CC) -MM $(CFLAGS) -I$(INCDIR)$(SRC) \
# sed的功能是在目标文件前面加上路径名,在后面加上后缀。
| sed 's,.∗\.o[ :]*,$(OBJDIR)/\1.o$(SUFFIX):,g' \
>$(DEPEND)
include $(DEPEND)
compile:$(OBJ)
# 动态连接,在install时须要拷贝动态连接库到合适的目录。
@$(CC) -o $(BIN) $(OBJ) -W1,-Bdynamic$(LIBDIR) $(LIB)
# 静态连接,在install时不须要拷贝静态态连接库。
@$(CC) -o $(BIN) $(OBJ) -W1,-Bstatic$(LIBDIR) $(LIB)
# 生成目标文件的隐含规则
$(OBJDIR)/%.o$(SUFFIX): %.c
@$(CC) -c -o $@ $(CFLAGS)$(filter %$<,$(SRC))
install:
将可执行程序、库文件等拷贝到预约的目录下。
uninstall:
clean:
@rm -rf $(OBJDIR)
@rm -f $(DEPEND)
tags:
@ctags $(INC) $(SRC)
ctags
功能说明:为源程序文件产生一个tag file。
语法:ctags[--append=yes|no][--links=yes|no][-L 列表文件][-f tag文件名][文件\目录…]
-L 列表文件中指定的文件生成tag文件
-f 设定生成的tag文件的名字(默认是tags)
--append 用生成的tag重写tag文件(默认是no)或者是将生成的tag添加到tag文件中
--links 是否添加symbol links(默认是yes)
--recurse 是否递归处理目录。若是[文件\目录…]为空,并且也没有用-L选项指定列表文
件,则默认递归处理当前目录。
===========================================================================================
SHELL=/bin/sh # 设置shell
VPATH= # 设置全部文件搜索的路径(或者在下面用vpath设置)
GPATH= # 一般和VPATH(或者vpath)设置成一致的值
.SUFFIXES: # 清除原有的后缀列表
.SUFFIXES:.c .o # 设置makefile中隐含规则使用的后缀
CC= # 使用的编译器(gcc/g++)
CFLAGS= # 编译器的参数(-MM)
# 若是是debug版本就包含该变量的定义;若是是release版本就不包含该变量的定义。
DEBUG=1
ifdef DEBUG
SUFFIX:= .dbg
CFLAGS+= -g
else
SUFFIX:=
CFLAGS+= -O2
endif
EXECNAME:= # 生成的可执行文件的文件名
DEPEND:= # 存放关联信息的文件
# 下面三项将会应用于全部的源程序文件。
# 若是某源程序文件须要其它库或头文件的支持,则须要对该源程序文件进行单独处理。
LIB:= # 支持库,书写格式:-lname(对应的库为libname.so或libname.a)
INCDIR:= # 搜索头文件的目录
LIBDIR:= # 搜索库文件的目录
# 下面三个目录是肯定的
SRCDIR:= # 全部存放源文件的目录
OBJDIR:= # 全部存放目标文件的目录(一般全部的目标文件存放在同一个目
# 录下。要是存放在多个目录,还须要在makefile中指定各个目标
# 文件分别存放到哪一个目录。)
BINDIR:= # 存放可执行文件的目录(通常也只有一个目录,理由同上。)
vpath %.c $(SRCDIR) # 设置源程序文件的搜索目录
vpath %.h $(INCDIR) # 设置头文件的搜索目录
vpath %.o $(OBJDIR) # 设置目标文件的搜索目录
#如下的程序默认OBJDIR和BINDIR都只有一个目录
# SRC的值是全部源程序的文件名(包含路径)
SRC=$(foreach DIR,$(SRCDIR),$(wildcard $(DIR)/*.c))
# OBJ的值是全部目标文件的文件名(包含路径)
OBJ=$(addprefix $(OBJDIR)/,$(patsubst %.c,%.o$(SUFFIX),$(notdir $(SRC))))
# BIN的值是可执行文件的文件名(包含路径)
BIN=$(BINDIR)/$(EXECNAME)$(SUFFIX)
.PHONY:default compile install uninstall clean depend tags
# 默认目标,也就是主要目标。
# 若是默认目标的依赖是一个假想目标,该假想目标的命令就必定会被执行。
default: depend compile tags
depend:
@set -e;\
$(CC) -MM $(CFLAGS) -I$(INCDIR) $(SRC) \
# sed的功能是在目标文件前面加上路径名,在后面加上后缀。
| sed 's,.∗\.o[ :]*,$(OBJDIR)/\1.o$(SUFFIX):,g' \
>$(DEPEND)
include $(DEPEND)
compile:$(OBJ)
# 动态连接,在install时须要拷贝动态连接库到合适的目录。
@$(CC) -o $(BIN) $(OBJ) -W1,-Bdynamic $(LIBDIR) $(LIB)
# 静态连接,在install时不须要拷贝静态态连接库。
@$(CC) -o $(BIN) $(OBJ) -W1,-Bstatic $(LIBDIR) $(LIB)
# 生成目标文件的隐含规则
$(OBJDIR)/%.o$(SUFFIX): %.c
@$(CC) -c -o $@ $(CFLAGS) $(filter %$<,$(SRC))
install:
将可执行程序、库文件等拷贝到预约的目录下。
uninstall:
clean:
@rm -rf $(OBJDIR)
@rm -f $(DEPEND)
tags:
@ctags $(INC) $(SRC)
================================Makefile的一个模板(Simple)============================================================
SHELL:=/bin/sh
.SUFFIXES:
.SUFFIXES:.cpp .o
CC:=g++
CFLAGS+=
INCDIR:=. ./subdir
INCPATH:=$(addprefix-I,$(INCDIR))
SRCDIR:=. ./subdir
SRC:=$(foreachDIR,$(SRCDIR),$(wildcard $(DIR)/*.cpp))
OBJ:=$(patsubst %.cpp,%.o,$(SRC))
BIN:=run
.PHONY:build clean
build:$(OBJ)
@$(CC) -o $(BIN) $(OBJ)
%.o:%.cpp
@$(CC) $(INCPATH) -c$(CFLAGS) -o $@ $<
clean:
@rm -f $(BIN)
@rm -f $(OBJ)
================================Makefile的一个模板============================================================
SHELL:=/bin/sh
.SUFFIXES:
.SUFFIXES:.cpp .o
CC:=g++
CFLAGS+=
EXECNAME:=run
DEPEND:=depend
# external libs (libname.so or libname.a), in format:-lname
LIB:=
LIBDIR:=
INCDIR:=.
SRCDIR:=.
OBJDIR:=.
BINDIR:=.
# initialize
SRC:=$( foreach DIR, $(SRCDIR), $(wildcard $(DIR)/*.cpp) )
OBJ:=$( addprefix $(OBJDIR)/, $(patsubst %.cpp, %.o, $(notdir $(SRC) ) ) )
BIN:=$(BINDIR)/$(EXECNAME)
.PHONY:default build depend clean
default:depend build
depend:
@set -e;\
$(CC) -MM -I$(INCDIR) $(SRC)\
| sed 's, .∗\.o[ :]*, $(OBJDIR)/\1.o:, g'\
>$(DEPEND)
include $(DEPEND)
build:$(OBJ)
@$(CC) -o $(BIN) $(OBJ) $(LIBDIR) $(LIB)
# default rules for obj files
$(OBJDIR)/%.o:%.cpp
@$(CC) -c -o $@ $(CFLAGS) $( filter %$<, $(SRC) )
clean:
@rm -f $(DEPEND)
@rm -f $(BIN)
@rm -f $(OBJ)