makefile详解 定义模式规则

来源:互联网 发布:mac 安装nodejs环境 编辑:程序博客网 时间:2024/05/30 12:03
五、定义模式规则
 
你可以使用模式规则来定义一个隐含规则。一个模式规则就好像一个一般的规则,只是在规则中,目标的定义需要有"%"字符。"%"的意思是表示一个或多个任意字符。在依赖目标中同样可以使用"%",只是依赖目标中的"%"的取值,取决于其目标。 

有一点需要注意的是,"%"的展开发生在变量和函数的展开之后,变量和函数的展开发生在make载入Makefile时,而模式规则中的"%"则发生在运行时。 


1、模式规则介绍 

模式规则中,至少在规则的目标定义中要包含"%",否则,就是一般的规则。目标中的"%"定义表示对文件名的匹配,"%"表示长度任意的非空字符串。例如:"%.c"表示以".c"结尾的文件名(文件名的长度至少为3),而"s.%.c"则表示以"s."开头,".c"结尾的文件名(文件名的长度至少为5)。 

如果"%"定义在目标中,那么,目标中的"%"的值决定了依赖目标中的"%"的值,也就是说,目标中的模式的"%"决定了依赖目标中"%"的样子。例如有一个模式规则如下: 

    %.o : %.c ; <command ......>; 

其含义是,指出了怎么从所有的[.c]文件生成相应的[.o]文件的规则。如果要生成的目标是"a.o b.o",那么"%c"就是"a.c b.c"。 

一旦依赖目标中的"%"模式被确定,那么,make会被要求去匹配当前目录下所有的文件名,一旦找到,make就会规则下的命令,所以,在模式规则中,目标可能会是多个的,如果有模式匹配出多个目标,make就会产生所有的模式目标,此时,make关心的是依赖的文件名和生成目标的命令这两件事。 


2、模式规则示例 

下面这个例子表示了,把所有的[.c]文件都编译成[.o]文件. 

    %.o : %.c 
            $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@ 

其中,"$@"表示所有的目标的挨个值,"$<"表示了所有依赖目标的挨个值。这些奇怪的变量我们叫"自动化变量",后面会详细讲述。 

下面的这个例子中有两个目标是模式的: 

    %.tab.c %.tab.h: %.y 
            bison -d $< 

这条规则告诉make把所有的[.y]文件都以"bison -d <n>;.y"执行,然后生成"<n>;.tab.c"和"<n>;.tab.h"文件。(其中,"<n>;"表示一个任意字符串)。如果我们的执行程序"foo"依赖于文件"parse.tab.o"和"scan.o",并且文件"scan.o"依赖于文件"parse.tab.h",如果"parse.y"文件被更新了,那么根据上述的规则,"bison -d parse.y"就会被执行一次,于是,"parse.tab.o"和"scan.o"的依赖文件就齐了。(假设,"parse.tab.o"由"parse.tab.c"生成,和"scan.o"由"scan.c"生成,而"foo"由"parse.tab.o"和"scan.o"链接生成,而且foo和其[.o]文件的依赖关系也写好,那么,所有的目标都会得到满足) 

4、模式的匹配 

一般来说,一个目标的模式有一个有前缀或是后缀的"%",或是没有前后缀,直接就是一个"%"。因为"%"代表一个或多个字符,所以在定义好了的模式中,我们把"%"所匹配的内容叫做"茎",例如"%.c"所匹配的文件"test.c"中"test"就是"茎"。因为在目标和依赖目标中同时有"%"时,依赖目标的"茎"会传给目标,当做目标中的"茎"。 

当一个模式匹配包含有斜杠(实际也不经常包含)的文件时,那么在进行模式匹配时,目录部分会首先被移开,然后进行匹配,成功后,再把目录加回去。在进行"茎"的传递时,我们需要知道这个步骤。例如有一个模式"e%t",文件"src/eat"匹配于该模式,于是"src/a"就是其"茎",如果这个模式定义在依赖目标中,而被依赖于这个模式的目标中又有个模式"c%r",那么,目标就是"src/car"。("茎"被传递) 


5、重载内建隐含规则 

你可以重载内建的隐含规则(或是定义一个全新的),例如你可以重新构造和内建隐含规则不同的命令,如: 

    %.o : %.c 
            $(CC) -c $(CPPFLAGS) $(CFLAGS) -D$(date) 

你可以取消内建的隐含规则,只要不在后面写命令就行。如: 

    %.o : %.s 

同样,你也可以重新定义一个全新的隐含规则,其在隐含规则中的位置取决于你在哪里写下这个规则。朝前的位置就靠前。 


六、老式风格的"后缀规则" 

后缀规则是一个比较老式的定义隐含规则的方法。后缀规则会被模式规则逐步地取代。因为模式规则更强更清晰。为了和老版本的Makefile兼容,GNU make同样兼容于这些东西。后缀规则有两种方式:"双后缀"和"单后缀"。 

双后缀规则定义了一对后缀:目标文件的后缀和依赖目标(源文件)的后缀。如".c.o"相当于"%o : %c"。单后缀规则只定义一个后缀,也就是源文件的后缀。如".c"相当于"% : %.c"。 

后缀规则中所定义的后缀应该是make所认识的,如果一个后缀是make所认识的,那么这个规则就是单后缀规则,而如果两个连在一起的后缀都被make所认识,那就是双后缀规则。例如:".c"和".o"都是make所知道。因而,如果你定义了一个规则是".c.o"那么其就是双后缀规则,意义就是".c"是源文件的后缀,".o"是目标文件的后缀。如下示例: 

    .c.o: 
            $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $< 

后缀规则不允许任何的依赖文件,如果有依赖文件的话,那就不是后缀规则,那些后缀统统被认为是文件名,如: 

    .c.o: foo.h 
            $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $< 

这个例子,就是说,文件".c.o"依赖于文件"foo.h",而不是我们想要的这样: 

    %.o: %.c foo.h 
            $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $< 

后缀规则中,如果没有命令,那是毫无意义的。因为他也不会移去内建的隐含规则。 

而要让make知道一些特定的后缀,我们可以使用伪目标".SUFFIXES"来定义或是删除,如: 

    .SUFFIXES: .hack .win 

把后缀.hack和.win加入后缀列表中的末尾。 

    .SUFFIXES:              # 删除默认的后缀 
    .SUFFIXES: .c .o .h   # 定义自己的后缀 

先清楚默认后缀,后定义自己的后缀列表。 

make的参数"-r"或"-no-builtin-rules"也会使用得默认的后缀列表为空。而变量"SUFFIXE"被用来定义默认的后缀列表,你可以用".SUFFIXES"来改变后缀列表,但请不要改变变量"SUFFIXE"的值。 



0 0
原创粉丝点击