剖析安卓build系统的设计思想以及案例模拟
2015-08-30 12:05
441 查看
1.引言
安卓系统在根目录中只有一个Makefile文件,每个模块只有一个android.mk文件,这是Makefile文件的一个片段,为什么要这么设计呢?这种设计方式解决了什么问题呢?相信读完本文将会找到这些问题的答案。
2.问题的提出
对于一个小菜鸟来说,最先想到的方案是为每个模块写一个makefile,示例工程如下:
顶级目录的makefile内容如下:
ant目录下的makefile内容如下:
bee目录下的makefile内容如下:
我们使用DAG来描述ant模块文件依赖关系:
![](http://img.blog.csdn.net/20150830105035147)
同样的,bee模块的文件依赖关系如下:
![](http://img.blog.csdn.net/20150830105133682)
这样我们就构建好2个模块的编译系统,只要make一下就能够得到我们想要的结果,不知道细心的读者是否发现了一个问题:main.o是依赖parse.h的,但是main.o并不清楚parse.h是如何诞生的,毕竟他们是处于两个模块的,两个makefile就像两个房间一样,他们各自身处于自己的空间当中,所以为了暴露这个问题,我们增加如下情景:
bee目录的parse.h和parse.c文件是通过yacc工具自动生成的,也就是我们在bee/Makefile文件增加以下内容来生成parse.h和parse.c文件。依赖关系现在如下:
![](http://img.blog.csdn.net/20150830105653553)
假如我们修改了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://img.blog.csdn.net/20150830111610626)
示例代码地址如下:
http://download.csdn.net/detail/getnextwindow/9063217
根目录下面只有一个Makefile文件,ant和bee模块下只有一个makefile片段,depend.sh自动生成头文件依赖的脚本。
Makefile实现如下:
bee模块的module.mk文件如下:
现在来分析新设计是如何解决前面的问题的,假如我们现在仅仅修改了parse.y文件。
一旦开始执行make命令,会将所有include指令中的文件加载进来,然后才开始根据所有规则产生目标文件。加载进来bee模块的module.mk以后,就会更新parse.c和parse.h,接着就会更新依赖parse.c和parse.h的目标文件,即parse.o、parse.d和main.o,所以这里main.o感知到了变化。
安卓系统在根目录中只有一个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感知到了变化。
相关文章推荐
- iphone开发之表格组件UITableView的使用(二)如何分组展示数据并添加组头和组尾描述
- easyui使用mergeCells合并单元格后第一行行高过大
- iOS开发 - UIAlertController 弹框提醒
- 考评系统学到的UI设计理念
- UIWindow和UIView
- UI设计规范
- iOS8新特性(2)——UIPopoverController和UIPresentationController
- iOS8新特性(1)——UIAlertController
- 编写广播时出现Exported receiver does not require permission
- 学习YUI.Ext 第一天:EXT简介(一)
- HOWTO: Install, Build and Use openCV (MacOSX 10.10)
- POJ 2524 Ubiquitous Religions(宗教种类:并差集)
- adbd cannot run as root in production builds
- iphone开发之表格组件UITableView的使用(一)使用时的具体步骤介绍
- UUID.randomUUID().toString 简单解释
- CodeForces 441A Valera and Antique Items
- iOS开发 - UICollectionViewLayout 自定义布局
- iOS开发 - UICollectionViewFlowLayout 流水布局
- UIday02~04:UITextField UIButton UIdelegate 自定义视图 容器视图控制器
- POJ 3458 && HDU 1683 Colour Sequence(水~)