make file简介

上篇文章是从网上转载过来的,内容基本上与《跟我一起写Makefile》一样,接下来的这篇文章主要对上篇中的特别点进行分析

1:Makefile使用变量

objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.o 
edit : $(objects) 
cc -o edit $(objects)

用objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.o 定义一个变量,与C语言中宏定义类似,于是如果有新的 .o 文件加入,我们只需简单地修改一下 objects 变量就可以了。

2:Makefile自动推导

只要 make 看到一个[.o]文件,它就会自动的把[.c]文件加在依赖关系中,如果 make找到一个 whatever.o,那么 whatever.c,就会是 whatever.o 的依赖文件。并且 cc -c whatever.c 也会被推导出

main.o : defs.h 
kbd.o : defs.h command.h 
command.o : defs.h command.h 
display.o : defs.h buffer.h 
insert.o : defs.h buffer.h 
search.o : defs.h buffer.h 
files.o : defs.h buffer.h command.h 
utils.o : defs.h 

上述的*.o目标文件,其依赖的*.c文件就可以省略,靠Makefile自己推导,我们只需要把要依赖的.h文件写出来就行

3:清空目标规则

        为了避免和文件重名的这种情况,我们可以使用一个特殊的标记“.PHONY”来显示地指明一个目标是“伪目标”,向 make 说明,不管是否有这个文件,这个目标就是“伪目标”。 
 
.PHONY : clean 
 
       只要有这个声明,不管是否有“clean”文件,要运行“clean”这个目标,只有“make clean”这样。于是整个过程可以这样写:

clean: 
rm edit $(objects) 
 
更为稳健的做法是: 
 
.PHONY : clean 
clean : 
-rm edit $(objects) 
 
          前面说过,.PHONY 意思表示 clean 是一个“伪目标”,。而在 rm 命令前面加了一个小减号的意思就是,也许某些文件出现问题,但不要管,继续做后面的事。当然,clean 的规则不要放在文件的开头,不然,这就会变成 make 的默认目标,相信谁也不愿意这样。不成文的规矩是——“clean 从来都是放在文件的最后”。

4:注释

          Makefile 中只有行注释,和 UNIX 的 Shell 脚本一样,其注释是用“#”字符,这个就像 C/C++中的“//”一样。如果你要在你的 Makefile 中使用“#”字符,可以用反斜框进行转义,如:“\#”。 

5:引用其它的 Makefile 

        在 Makefile 使用 include 关键字可以把别的 Makefile 包含进来,这很像 C 语言的#include,被包含的文件会原模原样的放在当前文件的包含位置。include 的语法是: include <filename> 
         filename 可以是当前操作系统 Shell 的文件模式(可以保含路径和通配符) 在 include前面可以有一些空字符,但是绝不能是[Tab]键开始。include 和<filename>可以用一个或多个空格隔开。举个例子,你有这样几个 Makefile:a.mk、b.mk、c.mk,还有一个文件叫foo.make,以及一个变量$(bar),其包含了 e.mk 和 f.mk,那么,下面的语句: 
include foo.make *.mk $(bar) 
等价于: 
include foo.make a.mk b.mk c.mk e.mk f.mk 
 
         make 命令开始时,会把找寻 include 所指出的其它 Makefile,并把其内容安置在当前的位。就好像 C/C++的#include 指令一样。如果文件都没有指定绝对路径或是相对路径的话,make 会在当前目录下首先寻找,如果当前目录下没有找到,那么,make 还会在下面的几个目录下找: 
1、如果 make 执行时,有“-I”或“--include-dir”参数,那么 make 就会在这个参数 所指定的目录下去寻找。 
2、如果目录<prefix>/include(一般是:/usr/local/bin 或/usr/include)存在的话,make 也会去找。如果有文件没有找到的话,make 会生成一条警告信息,但不会马上出现致命错误。它会继续载入其它的文件,一旦完成 makefile 的读取,make 会再重试这些没有找到,或是不能读取的文件,如果还是不行,make 才会出现一条致命信息。如果你想让 make不理那些无法读取的件,而继续执行,你可以在 include 前加一个减号“-”。 
如: -include <filename> 
其表示,无论 include 过程中出现什么错误,都不要报错继续执行。和其它版本 make
兼 容的相关命令是 sinclude,其作用和这一个是一样的。

6:在规则中使用通配符 

        如果我们想定义一系列比较类似的文件,我们很自然地就想起使用通配符。make 支持三个通配符:“*”,“?”和“[...]”通配符代替了你一系列的文件,如“*.c”表示所以后缀为 c 的文件。一个需要我们注意的是,如果我们的文件名中有通配符,如:“*”,那么可以用转义字符“\”,如“\*”来表示真实的“*”字符,而不是任意长度的字符串

7:文件搜寻 

         在一些大的工程中,有大量的源文件,我们通常的做法是把这许多的源文件分类,并存放在不同的目录中。所以,当 make 需要去找寻文件的依赖关系时,你可以在文件前加上路径,但最好的方法是把一个路径告诉 make,让 make 在自动去找。 
        Makefile 文件中的特殊变量“VPATH”就是完成这个功能的,如果没有指明这个变量,make 只会在当前的目录中去找寻依赖文件和目标文件。如果定义了这个变量,那么,make就会在当当前目录找不到的情况下,到所指定的目录中去找寻文件了。 
 VPATH = src:../headers 
        上面的的定义指定两个目录,“src”和“../headers”,make 会按照这个顺序进行搜
索。目录由“冒号”分隔。(当然,当前目录永远是最高优先搜索的地方)

       另一个设置文件搜索路径的方法是使用 make 的“vpath”关键字(注意,它是全小写的),这不是变量,这是一个 make 的关键字,这和上面提到的那个 VPATH 变量很类似,但是它更为灵活。它可以指定不同的文件在不同的搜索目录中。这是一个很灵活的功能。它的使用方法有三种: 
1、vpath <pattern> <directories> 
为符合模式<pattern>的文件指定搜索目录<directories>。 
2、vpath <pattern> 
清除符合模式<pattern>的文件的搜索目录。 
3、vpath 
清除所有已被设置好了的文件搜索目录。

      vapth 使用方法中的<pattern>需要包含“%”字符。“%”的意思是匹配零或若干字符,例如,“%.h”表示所有以“.h”结尾的文件。<pattern>指定了要搜索的文件集,而<directories>则指定了<pattern>的文件集的搜索的目录。例如:  vpath %.h ../headers 该语句表示,要求 make 在“../headers”目录下搜索所有以“.h”结尾的文件。(如果某文件在当前目录没有找到的话) 

8:自动化变量 

        所谓自动化变量,就是这种变量会把模式中所定义的一系列的文件自动地挨个取出,直至所有的符合模式的文件都取完了。这种自动化变量只应出现在规则的命令中。 
下面是所有的自动化变量及其说明: 
$@ 
       表示规则中的目标文件集。在模式规则中,如果有多个目标,那么,"$@"就是匹配于 目标中模式定义的集合。 
$% 
    仅当目标是函数库文件中,表示规则中的目标成员名。例如,如果一个目标是"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 的

        当你希望只对更新过的依赖文件进行操作时,"$?"在显式规则中很有用,例如,假设有一个函数库文件叫"lib",其由其它几个 object 文件更新。那么把 object 文件打包的比较有效率的 Makefile 规则是:  
lib : foo.o bar.o lose.o win.o 
ar r lib $? 

9:静态模式    

        静态模式可以更加容易地定义多目标的规则,可以让我们的规则变得更加的有弹性和灵活  
我们还是先来看一下语法: 
 
<targets ...>: <target-pattern>: <prereq-patterns ...> 
<commands> 
.... 
 
      targets 定义了一系列的目标文件,可以有通配符。是目标的一个集合。 
      target-parrtern 是指明了 targets 的模式,也就是的目标集模式。 
      prereq-parrterns 是目标的依赖模式,它对 target-parrtern 形成的模式再进行一次依赖目标的定义。 

看一个例子: 
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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值