码迷,mamicode.com
首页 > 其他好文 > 详细

MakeFile 学习

时间:2015-10-14 01:34:44      阅读:312      评论:0      收藏:0      [点我收藏+]

标签:

MakeFile 学习

1、静态模式

  1. objects = foo.o bar.o 
  2. all: $(objects) 
  3. $(CC) $(CFLAGS) -o -o $@ $^ 
  4. $(objects): %.o: %.
  5. $(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”)。于是,上面的规则展开后等价于下面的规则:

  1. foo.o : foo.c 
  2. $(CC) -c $(CFLAGS) foo.c -o foo.o 
  3. bar.o : bar.c 
  4. $(CC) -c $(CFLAGS) bar.c -o bar.o 

这是一个进行了提升的列子:

  1. files = foo.elc bar.o lose.o 
  2. $(filter %.o,$(files)): %.o: %.
  3. $(CC) -c $(CFLAGS) $< -o $@ 
  4. $(filter %.elc,$(files)): %.elc: %.el 
  5. emacs -f batch-byte-compile $< 

使用了filter进行单独过滤处理。


2、特殊命令标记符号

  • -号,会标记所有后面的命令都是返回成功,也就是忽略失败。

  • @号,会在make的时候,只是执行命令,而不输出命令本身。

  • make的 -n 参数,加上这个参数之后,只会展开命令,而不真的执行,可以帮助调试脚本。

  • .PHONY:clean 用来定一个伪目标,比如这里定义了一个清理操作。

  • [Tab]键后面跟着的会被当作命令来执行。多个命令有依赖关系的时候,要写在一行,并且用分号分隔。

  • =、:=、?=、+=的区别,=可以在前面的代码用后面的变量,:=则不可以。?=被赋值的变量如果没有定义过,就是等于后面的值,如果定义过,则什么都不做。+=用于追加。

  • override 定义了一个覆盖操作。


3、make的环境变量

有两个变量,一个是SHELL,一个是 MAKEFLAGS ,这两个变量不管你是否export,其总是要传递到下层Makefile中,其他环境变量需要export 导出一下。但是make命令中的有几个参数并不往下传递,它们是“-C”,“-f”,“-h”“-o”和“-W”(有关Makefile参数的细节将在后面说明)
MAKEFILES这个环境变量,执行make的时候,会进行一个类似include的动作。一般不建议使用.


4、Makefile 的核心

里主要包含了五个东西:显式规则、隐晦规则、变量定义、文件指示和注释。

  1. 显式规则。显式规则说明了,如何生成一个或多的的目标文件。这是由Makefile的书写者明显指出,要生成的文件,文件的依赖文件,生成的命令。 
  2.  
  3. 隐晦规则。由于我们的make有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略地书写Makefile,这是由make所支持的。 
  4.  
  5. 变量的定义。在Makefile中我们要定义一系列的变量,变量一般都是字符串,这个有点你C语言中的宏,当Makefile被执行时,其中的变量都会被扩展到相应的引用位置上。 
  6.  
  7. 文件指示。其包括了三个部分,一个是在一个Makefile中引用另一个Makefile,就像C语言中的include一样;另一个是指根据某些情况指定Makefile中的有效部分,就像C语言中的预编译#if一样;还有就是定义一个多行的命令。有关这一部分的内容,我会在后续的部分中讲述。 
  8.  
  9. 注释。Makefile中只有行注释,和UNIX的Shell脚本一样,其注释是用“#”字符,这个就像C/C++中的“//”一样。如果你要在你的Makefile中使用“#”字符,可以用反斜框进行转义,如:“\#”。 

5、特殊表达式

  • 变量替换

  1. foo:=a.o b.o c.o 
  2. bar:=$(foo:.o=.c) 

理解为bar的值等于,foo里面的值将.o替换为.c之后。

  • 变量再当变量

  1. x = y 
  2. y = z 
  3. a := $($(x)

这个表达式a=的值等于z;

  • 多层变量配合函数

  1. x = variable1 
  2. variable2 := Hello 
  3. y = $(subst 1,2,$(x)
  4. z = y 
  5. a := $($($(z))) 

“$($($(z)))”扩展为“$($(y))”,而其再次被扩展为“$($(subst 1,2,$(x)))”。$(x)的值是“variable1”,subst函数把“variable1”中的所有“1”字串替换成“2”字串,于是,“variable1”变成“variable2”,再取其值,所以,最终,$(a)的值就是$(variable2)的值—— “Hello”。

  • 变量名组合

  1. first_second = Hello 
  2. a = first 
  3. b = second 
  4. all = $($a_$b

这里的“$a_$b”组成了“first_second”,于是,$(all)的值就是“Hello”。

  • “函数”和“条件语句”一同使用

  1. ifdef do_sort 
  2. func := sort 
  3. else 
  4. func := strip 
  5. endif 
  6.  
  7. bar := a d b g q
  8.  
  9. 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函数。

  • 某个目标的局部变量

  1. prog : CFLAGS = -g 
  2. prog : prog.o foo.o bar.o 
  3. $(CC) $(CFLAGS) prog.o foo.o bar.o 

在这个示例中,不管全局的$(CFLAGS)的值是什么,在prog目标,以及其所引发的所有规则中(prog.o foo.o bar.o的规则),$(CFLAGS)的值都是“-g”

5、自动化变量

  • $@
    表示规则中的目标文件集。在模式规则中,如果有多个目标,那么,"$@"就是匹配于目标中模式定义的集合。

  • $%
    仅当目标是函数库文件中,表示规则中的目标成员名。例如,如果一个目标是"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)"
    分别表示被更新的依赖文件的目录部分和文件部分。

最后想提醒一下的是,对于"$<",为了避免产生不必要的麻烦,我们最好给$后面的那个特定字符都加上圆括号,比如,"$(< )“就要比”$<"要好一些。

还得要注意的是,这些变量只使用在规则的命令中,而且一般都是"显式规则"和"静态模式规则"(参见前面"书写规则"一章)。其在隐含规则中并没有意义。

MakeFile 学习

标签:

原文地址:http://www.cnblogs.com/rexonor/p/4876267.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!