在分析u-boot的makefile时,发现了自动生成依赖的这个方法,今天分析了一 下。已知自动生成依赖的规则在顶层目录的rules.mk文件里面约定: rules.mk: --------- #########################################################################
_depend:$(obj).depend
$(obj).depend:$(src)Makefile $(TOPDIR)/config.mk $(SRCS) @rm -f $@ @for f in $(SRCS); do / g=`basename $$f | sed -e 's//(.*/)/./w//1.o/'`; / $(CC) -M $(HOST_CFLAGS) $(CPPFLAGS) -MQ $(obj)$$g $$f >> $@ ; / done
######################################################################### ---------
在大多数子目录中,子目录的Makefile文件中都包含上述规则来自动生成依赖。我们以 u-boot/board/smdk2410 为例: # cd /u-boot/board/smdk2410 [root@localhost smdk2410]# ls config.mk flash.c lowlevel_init.S Makefile smdk2410.c u-boot.lds [root@localhost smdk2410]# vim Makefile Makefile: --------- include $(TOPDIR)/config.mk
LIB = $(obj)lib$(BOARD).a
COBJS := smdk2410.o flash.o SOBJS := lowlevel_init.o
SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) OBJS := $(addprefix $(obj),$(COBJS)) SOBJS := $(addprefix $(obj),$(SOBJS))
$(LIB): $(obj).depend $(OBJS) $(SOBJS) $(AR) $(ARFLAGS) $@ $(OBJS) $(SOBJS)
clean: rm -f $(SOBJS) $(OBJS)
distclean: clean rm -f $(LIB) core *.bak .depend
#########################################################################
# defines $(obj).depend target include $(SRCTREE)/rules.mk
sinclude $(obj).depend
######################################################################### ---------
已知:
$(obj)时间上为空,所以上面任何文件加上这个前缀实际上都没有用,表示在当前目录下面。 $(TOPDIR) == $(SRCTREE) 就是u-boot顶层目录。
现在开始看这个Makefile,可知其终极目标为 LIB即$(obj)lib$(BOARD).a即libsmdk2410.a 而$(LIB)分别依赖于.depend,$(OBJS),$(SOBJS)
当make按规则去生成$(LIB)时,它首先要去查看.depend文件,初次make的时候,.depend文件 还没有生成,所以make下一步就会查找.depend的生产规则并生成一个.depend文件。乍一看 Makefile好像没有.depend这个次级目标,但是别急,关键在于:
include $(SRCTREE)/rules.mk 这句相当于把rules.mk原方不动的展开,并插入在自己的位置上。
我们再回头看看rules.mk文件,可以发现该文件有.depend目标。 所以.../smdk2410目录下面的Makefile在make的驱动下,会按照rules.mk里面约定的规则生成 .depend文件,并把该文件放入.../smdk2410目录。
再次贴上rules.mk: --------- $(obj).depend:$(src)Makefile $(TOPDIR)/config.mk $(SRCS) @rm -f $@ @for f in $(SRCS); do / g=`basename $$f | sed -e 's//(.*/)/./w//1.o/'`; / $(CC) -M $(HOST_CFLAGS) $(CPPFLAGS) -MQ $(obj)$$g $$f >> $@ ; / done ---------
其中.depend的依赖$(src)Makefile,$(TOPDIR)/config.mk的作用对于研究自动生成依赖的 这个问题意义并不重要,只是导入$(HOST_CFLAGS),$(CPPFLAGS)这些变量(我暂时说服自己)。 关键看$(SRCS),在这个地方$(SRCS)代表着当前目录下的源文件,包括: flash.c lowlevel_init.S smdk2410.c
.depend文件的生成规则为一个for循环,也就是找出上述各个源文件的依赖关系并放入 .depend文件。
需要注意的是,这个规则的语法确实太麻烦,我至今没有看清楚,不过不要紧,知道它是把上述 各个源文件的依赖关系取出放入到.depend文件就行。要想弄得更清楚的话,要好好看看sed 命令的用法,这里不讨论了。
生成的.depend 文件的内容如下(给出概略形式):
.depend --------- flash.o: flash.c xxx.h xxx.h ... smdk2410.o: smdk2410.c xxx.h xxx.h ... lowlevel_init.o: lowlevel_init.s xxx.h xxx.h ... ---------
我们再回到.../smdk2410下面的Makefile,看终极目标$(LIB)的另外两个依赖: $(OBJS),$(SOBJS) 也就是flash.o,smdk2410.o 和 lowlevel_init.o
似乎我们在.../smdk2410下面的Makefile里面看不到上述目标,但是不要急,看看该Makefile的 最后一行:sinclude $(obj).depend 也就是说把flash.o,smdk2410.o 和 lowlevel_init.o的依赖关系包含过去了.
通过上述分析,我们知道终极目标$(LIB)的所有依赖关系及次级目标都理清楚了,Make命令最终 可以递归的把$(LIB)生成。
之所以称为"自动生成依赖",我们可以看到:flash.o,smdk2410.o 和 lowlevel_init.o的依赖 关系都是make自己来完成的,不需要我们手动改写。即使我们的某个源文件的依赖关系发生了变 化,则.depend文件的时间戳会比某个源文件的时间戳早,则make会重新生成.depend文件!这样 就减轻了繁琐的人工劳动。
最后,我们再来一个超级简单的例子: =========
[root@localhost maketest]# ls -a . .. app.c Makefile print.c print.h rules.mk
app.c: --------- int main() { PrintStr("Hello world !"); return 0; }
---------
print.h: --------- void PrintStr(char *);
---------
print.c: --------- #include<stdio.h> #include"print.h" void PrintStr(char *s) { puts(s); return; }
---------
Makefile: --------- OBJS := app.o print.o SRCS := $(OBJS:.o=.c)
Tar: .depend $(OBJS) gcc -o $@ $(OBJS)
clean: rm -f $(OBJS)
include rules.mk sinclude .depend ---------
rules.mk: --------- .depend: $(SRCS) @rm -f $@ @for f in $(SRCS); do / g=`basename $$f | sed -e 's//(.*/)/./w//1.o/'`; / $(CC) -MM -MQ $$g $$f >> $@ ; / done ---------
make之后: [root@localhost maketest]# ls -a . .. app.c app.o .depend Makefile print.c print.h print.o rules.mk Tar
[root@localhost maketest]# cat .dependapp.o: app.cprint.o: print.c print.h (编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|