GUN make (3) Makefile的规则

1. 依赖的类型

GUN make中存在两种类型的依赖:

常规依赖:依赖文件中任何一个比目标文件新,则认为规则的目标过期需要重建。

order-only依赖:当order-only依赖中的文件更新时,若目标不存在,则生成目标; 若目标存在,则不更新目标。

 

常规、order-only依赖书写规则:

TARGETS:NORMAL-PREREQUISITES | ORDER-ONLY-PREREQUISITES

使用 “ | ”分隔常规依赖和order-only依赖,如果有文件同时出现在两边,则算为常规依赖。

 

2. 文件名通配符

2.1 通配符类型

makefile中文件名可以使用通配符,有 * ,  ?  ,   [...]

通配符可以使用以下场合:

  • 使用在规则的目标,依赖中, make在读取makefile时自动对其进行匹配处理(通配符展开)。
  • 可出现在规则的命令中,通配处理是在shell执行此命令时完成的。
  • 除上述两种情况之外的其他上下文中,不能直接使用通配符。

 

2.2 wildcard函数

在规则中,通配符会被自动展开,但在变量定义和函数引用时,通配符将失效。

若此时需要通配符生效,使用wildcard函数:

$(wildcard PATTERN)

在makefile中,它被展开为已存在的,使用空格分开的,匹配模式的所有文件列表。

 

比如:

$(wildcard *.c)来获取工作目录下的所有.c文件列表。

 

3. 目录搜索

3.1 一般搜索(VPATH)

通过变量VPATH可以指定依赖文件的搜索路径,使用 空格 或在 冒号: 将多个需要搜索的目录文件分开,搜索顺序是按照目录排列顺序进行。

规则的依赖文件在当前目录不存在时,make会在此变量所指定的目录下寻找这些依赖文件。

 

比如:

VPATH = src:../headers   

指定了src 和../headers两个搜索目录,对于foo:foo.c  ,如果foo.c存在于src目录下,此规则等价于foo:src:/foo.c

 

3.2选择性搜索(vpath)

选择性搜索可以为不同的类型文件指定不同的搜索目录。

vpath中的PATTERN需要包含模式字符%, 其表示匹配一个或多个字符。表示具有相同特征的一类文件。

DIRECTORIES指定了搜索此类文件目录。

 

三种使用方法:

  • vpath PATTERN DIRECTORIES

为所有符合模式PATTERN的文件指定搜索目录DIRECTORIES,多个目录使用空格 或者 冒号: 分隔。

  • vpath PATTERN

清除之前为符合模式PATTERN 的文件文件设置的搜索路径。

  • vpath 清除所有已被设置的文件搜索路径。

 

比如:
vpath %.h ../headers 

表示makefile中出现的.h文件,如果不能在当前目录下找到,则到目录../headers 下寻找。

注意,这里的指定路径仅限于在makefile文件内容中出现的.h文件,并不能指定源文件中包含的头文件所在的路径。在.c源文件中包含的头文件路径需要使用gcc的 -I 来指定。

 

3.3 目录搜索的机制

make在解析Makefile文件执行规则时对文件路径保存或废弃所依据的算法如下:

  1. 如果规则的 目标文件 在makefile文件所在的目录下不存在,那么执行目录搜索。
  2. 如果目录搜索成功,在指定的目录下存在此目标的 规则,那么搜索到的完整的路径名就被作为临时目标文件被保存。
  3. 对于规则中所有的 依赖文件 使用相同的方法处理。
  4. 完成第三步依赖处理后,make程序就可以决定规则的目标是否需要重建,存在两种情况:
  • 规则的目标不需要重建,规则中的所有文件的完整路径名有效,已经存在的目标文件所在的目录不会被改变。
  • 规则的目标需要重建,则规则的目标文件会在工作目录下被重建,而不是在目录搜索时所得到的目录。
  • 若使用GPATH而不是VPATH指定搜索目录,则目标在重建时,会在目录搜索时所得到的目录中进行重建。

 

3.4 库文件和搜索目录

makefile可以使用 -INAME 对静态库.a和动态库.so进行目录搜索。

 

搜索的依赖库文件名由 .LIBPATTERNS指定,其一般是多个包含模式字符%的字,多个字之间使用空格分开。

按照 .LIBPATTERNS出现的字顺序,用NAME逐个代替字的模式字符,得到库文件名,根据这个库文件名在搜索目录下搜索。

 

默认情况下, .LIBPATTERNS值为 lib%.so  lib%.a ,所以一般先搜索libNAME.so库,再搜索libNAME.a库。

 

4. Makefile中的目标

4.1 伪目标

伪目标使用:

.PHONY:clean               //使用.PHONY声明伪目标clean
clean:
    rm *.o temp

伪目标优点:

  • 当工作目录下不存在clean这个文件的时候,输出make clean时,对应规则一定会执行。但是如果当前工作目录下存在clean这个文件时,当输入make clean,由于这个规则没有依赖文件,所以目标被认为是最新的而不去执行规则所定义的命令。
  • 当一个目标被声明为伪目标的时候,make在执行此规则时不会试图去查找隐含规则来创建它。

 

4.2 强制目标

强制目标的目标是一个不存在的文件名,并且没有命令和依赖。

在执行该强制目标时,目标总是被认为是最新的。因此,如果强制目标作为依赖,导致该规则一定会执行。

 

比如:

clean:FORCE                    //强制目标作为依赖
    rm $(objects)
FORCE:                         //强制目标(没有依赖和命令)

 

4.3 多目标

多目标规则意味着所有的目标具有相同的依赖文件。

多目标使用情况:

aaa bbb:text.g
    generate text.g -$(subst output,$@) > $@

等价于:
aaa:text.g
    generate text.g -$(subst output,$@) > aaa 

bbb:text.g
    generate text.g -$(subst output,$@) > bbb

 

4.4 多规则目标

对于一个多规则的目标,重建此目标的命令只能出现在一个规则中。

如果多个规则同时给出重建此目标的命令,make将使用最后一个规则中所定义的命令。

 

4.5 静态模式

静态模式规则:

规则存在多个目标,并且不同的目标可以根据目标文件的名字来自动构造出依赖文件。并且依赖文件必须是类似的而不是完全相同的。


4.5.1 语法:

TARGETS...:TARGET-PATTERN:PREREQ-PATTERN...

    COMMANDS
    ...

TARGETS列出了此规则的一系列目标文件。

TARGET-PATTERN和PREREQ-PATTERNS说明了如何为每一个目标文件生成的依赖文件。从目标模式TARGET-PATTERN的目标名字中抽取一部分字符串(称为 茎),使用茎代替依赖模式PREREQ-PATTERNS中相应部分来产生对应目标的依赖文件。

 

比如:

objects=foo.o bar.o
all:$(objects)
$(objects):%o:%c
    $(CC) -c $(CFLAGS) $< -o $@

规则中 %o:%c 描述了所有的 .o 文件的依赖文件为对应的 .c 文件。

对目标foo.o取其茎 foo 代替对应的依赖模式%.c中的模式字符%之后可得到目标的依赖文件foo.c。

 

上边的规则描述了以下两个具体的规则:

foo.o:foo.c
    $(CC) -c $(CFLAGS) foo.c -o foo.o
bar.o:bar.c
    $(CC) -c $(CFLAGS) bar.c -o bar.o

 

4.5.2 静态模式和隐含规则区别

  • 隐含规则可以被用在 任何 和它相匹配的目标上。当存在多个隐含规则和目标模式相匹配时,只执行其中一个规则,具体执行哪个取决于定义规则的顺序。
  • 静态模式规则只能用在规则中 明确 指出的那些文件的重建过程中。如果一个目标存在两个规则,则make执行会提示错误。

 

4.6 自动产生依赖

gcc 通过 -M 选项自动寻找源文件中包含的头文件,并生成文件的依赖。

当不需要依赖关系中考虑标准库头文件时,使用 -MM 参数。

 

比如,main.c中只包含了头文件def.h,则:

gcc -M main.c
其输出是:
main.o:main.c def.h

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值