转载自断背背
原文地址:http://blog.csdn.net/duanbeibei/article/details/2910845
问题1:我对shell script不懂
%.d: %.c
@set -e; rm -f $@; /
$(CC) -MM $< > $@.$$$$; /
sed 's,/($*/)/.o[ :]*,/1.o $@ : ,g' < $@.$$$$ > $@; /
rm -f $@.$$$$
这一段看起来比较吃力
问题2:我怎么觉得第一种方案也不错呢。熟悉再回头看吧
【正文开始】
Makefile生成自动依赖的方法有两种:
1. 将所有.o文件的依赖关系写入单独文件,然后在Makefile中调用该文件
2. 每个.c文件对应一个.d文件,将依赖关系写入.d文件中
一、对于第一种方法,Makefile的写法如下:
#file start
CC = gcc
SRCS := $(wildcard *.c)
OBJS := $(patsubst %.c,%.o, $(SRCS))
all: main
main: $(OBJS)
$(CC) -o main $(OBJS)
.depend: $(SRCS)
@$(CC) -MM $(SRCS) > $@
sinclude .depend
clean:
rm -f *.o .depend main
#file end
说明:
(1) OBJS := $(patsubst %.c,%.o, $(SRCS))
将$(SRC)中的.c文件列表替换成对应的.o文件,在这里不能用“*.c”“*.o”来代替,试想在.o文件还不存在的情况下,规则语句“main: $(OBJS)”就会被解析成“main:*.o”,main依赖于“*.o”,“*.o”对应的规则又去哪找呢
(2) .depend: $(SRCS)
为的是.c文件更改时重新生成.depend文件
(3) @$(CC) -MM $(SRCS) > $@
行首的”@”符号表示在执行make时不显示该符号后的shell命令;
$@:表示当前目标文件,即”.depend”
假设main.c文件只引用了main.h头文件,那么这条命令的输出结果为:
main.o: main.c main.h
(4) sinclude .depend
将生成的依赖关系文件引入到当前Makefile。
Makefile中include的调用方式:
a) 首先在指定的目录下搜索被调用文件(该例没有加路径,则为当前目录)
b) 如果没有找到,则从-I所指定的include目录查找,如果还没找到,则从“/usr/gnu/include”“/usr/local/include”等目录查找
c) 最终结果还是没找到,则Makefile会试图寻找匹配规则来生成对应文件,例如本例中的规则为:
.depend: $(SRCS)
@$(CC) -MM $(SRCS) > $@
则根据该规则生成.depend文件。
程序首次编译时肯定不存在.depend文件,但这是makefile也不需要该文件,因为首次编译肯定连接的都是最新文件。也就是说首次编译时生成的.depend文件其实没用上,而是留作以后有了改动,比如更改了.h文件中的宏变量,则此时可根据.depend中的依赖关系只生成对应的.o文件了
d) 如果没有对应规则或其它原因导致生成文件失败,就要看你用的是include还是sinclude了,两者的区别:
| 异常 | 错误 |
include | 输出异常信息(例如首次编译时找不到.depend文件) | Makefile终止执行(例如找不到匹配规则而无法生成文件) |
cinclude | 不输出异常信息 | 忽略该错误,makefile继续执行 |
(5) 此方法过时?
很遗憾,在<< GNU make>>手册中说该方法过时了,原因描述如下:
InGNU make, the feature of remaking makefiles makes this practice obsolete—you need nevertell make explicitly to regenerate the prerequisites, because it always regenerates any makefile that is out of date.
这段话的关键句“because it always regenerates any makefile that is out of date”甚是无法理解,要的不就是这种效果么,有文件更新的话对其进行重新编译,对的啊,不懂!
正是由于这个搞不懂的原因才有了第二种方法
二、为每个.c文件生成对应的.d文件,Makefile写法如下:
#file start
SOURCES = $(wildcard *.c)
OBJS := $(patsubst %.c,%.o, $(SOURCES))
all: main
%.d: %.c
@set -e; rm -f $@; /
$(CC) -MM $< > $@.$$$$; /
sed 's,/($*/)/.o[ :]*,/1.o $@ : ,g' < $@.$$$$ > $@; /
rm -f $@.$$$$
sinclude $(SOURCES:.c=.d)
main:$(OBJS)
$(CC) -o main $(OBJS)
clean:
rm -f *.o test *.d
#file end
上面提到的原因中“you need nevertell make explicitly to regenerate the prerequisites”,其实在这里也是手动指定的啊:“$(CC) -MM $< > $@.$$$$”,另外为每个.c文件都生成.d文件似乎还麻烦了些,没明白手册是什么意思。
【正文结束】