标签:
1.引言
安卓系统在根目录中只有一个Makefile文件,每个模块只有一个android.mk文件,这是Makefile文件的一个片段,为什么要这么设计呢?这种设计方式解决了什么问题呢?相信读完本文将会找到这些问题的答案。
2.问题的提出
对于一个小菜鸟来说,最先想到的方案是为每个模块写一个makefile,示例工程如下:
Project
----Makefile
----ant
----Makefile
----main.c
----bee
----Makefile
----parse.c
----parse.h
顶级目录的makefile内容如下:
MODULES = ant bee
all:
for dir in $(MODULES); do (cd $$dir; $(MAKE) all); done
ant目录下的makefile内容如下:
all: main.o
main.o: main.c ../bee/parse.h
$(CC) -I../bee -c main.c
bee目录下的makefile内容如下:
OBJ = ../ant/main.o parse.o
all: prog
prog: $(OBJ)
$(CC) -o $@ $(OBJ)
parse.o: parser.c parse.h
$(CC) -c parse.c
我们使用DAG来描述ant模块文件依赖关系:
同样的,bee模块的文件依赖关系如下:
这样我们就构建好2个模块的编译系统,只要make一下就能够得到我们想要的结果,不知道细心的读者是否发现了一个问题:main.o是依赖parse.h的,但是main.o并不清楚parse.h是如何诞生的,毕竟他们是处于两个模块的,两个makefile就像两个房间一样,他们各自身处于自己的空间当中,所以为了暴露这个问题,我们增加如下情景:
bee目录的parse.h和parse.c文件是通过yacc工具自动生成的,也就是我们在bee/Makefile文件增加以下内容来生成parse.h和parse.c文件。依赖关系现在如下:
假如我们修改了parse.y文件,然后在工程的根目录下执行make指令,得到的结果是否是我们想要的呢?答案是否定的,且听我细细道来。
make指定一旦执行,就会分别进入每个模块分别进行编译,即执行里面的makefile,那么这里首先进入ant模块,由于仅仅修改parse.y文件,所以main.o不会更新,完蛋啦,因为实际上parse.y更新,parse.h就要更新,进而main.o也是需要更新的,但这里却没有更新,也就是说,prog使用了陈旧的main.o。
问题出在哪里?还是每个模块一个makefile的方案是不对的。
每个模块一个makefile就需要依次编译每个模块,但是模块间又太过于松散,也就是一个模块中的目标可能无法感知依赖的变化,比如ant模块无法感知其依赖的变化(依赖由bee模块生成),一旦先编译了ant模块,那么就会出现我们不想要的结果。
3.改进实现
找到原因之后,那么如何解决呢?其实就是增加模块之间的耦合度,本质上就是让模块之间能够互相感知变化,下面将改进上面的设计,从而帮助我们理解安卓编译系统的设计思想。
改进以后的工程结构如下:
示例代码地址如下:
http://download.csdn.net/detail/getnextwindow/9063217
根目录下面只有一个Makefile文件,ant和bee模块下只有一个makefile片段,depend.sh自动生成头文件依赖的脚本。
Makefile实现如下:
MODULES :=ant bee
CFLAGS +=$(patsubst %,-I %,$(MODULES))
LIBS :=
SRC :=
include $(patsubst %,%/module.mk,$(MODULES))
OBJ:=$(patsubst %.c,%.o,$(filter %.c,$(SRC)))
prog:$(OBJ)
$(CC) -o $@ $(OBJ) $(LIBS)
include $(OBJ:.o=.d)
%.d: %.c
depend.sh `dirname $*.c` $(CFLAGS) $*.c >$@
.PHONY :clean
clean:
rm -f prog $(OBJ) $(OBJ:.o=.d)
bee模块的module.mk文件如下:
SRC += bee/parse.y
LIBS += -ly
%.c %.h: %.y
$(YACC) -d $*.y
mv y.tab.c $*.c
mv y.tab.h $*.h
现在来分析新设计是如何解决前面的问题的,假如我们现在仅仅修改了parse.y文件。
一旦开始执行make命令,会将所有include指令中的文件加载进来,然后才开始根据所有规则产生目标文件。加载进来bee模块的module.mk以后,就会更新parse.c和parse.h,接着就会更新依赖parse.c和parse.h的目标文件,即parse.o、parse.d和main.o,所以这里main.o感知到了变化。
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:
原文地址:http://blog.csdn.net/getnextwindow/article/details/48103559