您的位置:首页 > 其它

makefile自动生成依赖

2015-01-04 16:13 204 查看
Makefile中,可能需要书写一些规则来描述一个.o目标文件和头文件的依赖关系.

例如,如果在main.c中使用"#include defs.h",那么我们可能需要如下那样的一个规则来描述当头文件"defs.h"被修改以后执行make,目标"main.o"应该被重建.

main.o: defs.h


这样,在一个比较大型的工程中.就需要在Makefile中书写很多条类似于这样的规则.并且,当在源文件中加入或删除头文件后,也需要小心地去修改Makefile.

这是一件很费力、也很费时并且容易出错误的工作.为了避免这个令人讨厌的问题,现代的c编译器提供了通过查找源文件中的"#include"来自动产生这种依赖的功能."GCC"支持一个"-M"的选项来实现此功能."GCC"将自动找寻源文件中包含的头文件,并生成一个依赖关系.

例如,如果"main.c"只包含了头文件"defs.h",那么在Linxu下执行下面的命令:

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


既然编译器已经提供了自动产生依赖关系的功能,那么我们就不需要去动手写这些规则的依赖关系了.

但是需要明确的是:在"main.c"中包含了其他的标准库的头文件,其输出的依赖关系中也包含了标准库的头文件.

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

需要注意的是,在使用"GCC"自动产生依赖关系时,所产生的规则中明确的指明了目标是"main.o"文件.

通过.c文件直接产生可执行文件时,作为过程文件的"main.o"的中间过程文件在使用完之后将不会被删除.

在旧版本的make中,使用编译器此项功能通常的做法是:在Makefile中书写一个伪目标"depend"的规则来定义自动产生依赖关系文件的命令.

输入"make depend"将生成一个称为"depend"的文件,其中包含了所有源文件的依赖规则描述.Makefile使用"include"指示符包含这个文件.

在新版本的make中,推荐的方式是为每一个源文件产生一个描述其依赖关系的makefile文件.对于一个源文件"NAME.c",

对应的这个makefile文件为"NAME.d"."NAME.d"中描述了文件"NAME.o"所要依赖的所有头文件.采用这种方式,

只有源文件在修改之后才会重新使用命令生成新的依赖关系描述文件"NAME.o".我们可以使用如下的模式规则来自动生成每一个.c文件对应的.d文件:

%.d: %.c
$(CC) -M $(CPPFLAGS) $< > $@.tmp; /
sed 's,/($*/)/.o[ :]*,/1.o $@ : ,g' < $@.tmp > $@; /
rm -f $@.tmp


此规则的含义是:所有的.d文件依赖于同名的.c文件.

第一行;使用c编译器自自动生成依赖文件($<)的头文件依赖关系,并输出成为一个临时文件.

如果$(CC)为GNU的C编译工具,产生的依赖关系的规则中,依赖头文件包括了所有的使用的系统头文件和用户定义的头文件.

如果需要生成的依赖描述文件不包含系统头文件,可使用"-MM"代替"-M".

第二行;使用sed处理第二行已产生的那个临时文件并生成此规则的目标文件.这里sed完成了如下的转换过程.

例如对已一个.c源文件.将编译器产生的依赖关系:

main.o : main.c defs.h
转成:
main.o main.d : main.c defs.h


这样就将.d加入到了规则的目标中,其和对应的.o文件文件一样依赖于对应的.c源文件和源文件所包含的头文件.

当.c源文件或者头文件被改变之后规则将会被执行,相应的.d文件同样会被更新.

使用上例的规则就可以建立一个描述目标文件依赖关系的.d文件.我们可以在Makefile中使用include指示符将描述将这个文件包含进来.

在执行make时,Makefile所包含的所有.d文件就会被自动创建或者更新.Makefile中对当前目录下.d文件处理可以参考如下:

sources = foo.c bar.c
sinclude $(sources:.c=.d)


例子中,变量"sources"定义了当前目录下的需要编译的源文件.

变量引用变换"$(sources:.c=.d)"的功能是根据需要.c文件自动产生对应的.d文件,并在当前Makefile文件中包含这些.d文件.

.d文件和其它的makefile文件一样,make在执行时读取并试图重建他们.其实这些.d文件也是一些可被make解析的makefile文件.

需要注意的是include指示符的书写顺序,因为在这些.d文件中已经存在规则.当一个Makefile使用指示符include这些.d文件时,

应该注意它应该出现在终极目标之后,以免.d文件中的规则被是Makefile的终极规则.关于这个前面我们已经有了比较详细的讨论.

一个简单的makefile示例如下:

CC = gcc
SOURCES = $(wildcard *.c)
OBJS = $(patsubst %.c,%.o, $(SOURCES))
DEPS = $(patsubst %.c,%.d, $(SOURCES))
TARGET = main

$(TARGET):$(OBJS)
$(CC) -o $@ $^

%.d: %.c
$(CC) -MM $(CPPFLAGS) $< > $@.tmp; \
sed 's,/($*/)/.o[ :]*,/1.o $@ : ,g' < $@.tmp > $@; \
rm -f $@.tmp

sinclude $(DEPS)

clean:
rm -f $(OBJS) $(DEPS) $(TARGET)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: