Android 的编译系统

最近研究了下Android 的编译系统,下面结合编译我们自己的产品 mobot 来对整个编译系统进行必要的介绍,方便大家今 后对默认编译的修改。

 

先列出几个觉得重要的Make 文件:

build/buildspec.mk

build/envsetup.sh

build/core/main.mk

build/core/envsetup.mk

build/config.mk

 

总的来说,Android 以模块 (module/package) 的形式来组织各个系统的部件,每个模块(module/package) 的目录下都会有一个 Android.mk 。所谓 module 就是指系统的 Native Code ,而相对于Java 写的 Android application 称为 package 

 

 

 

Makefile的主要流 程 1

初始化参数设置 2

读取Product 的设定 3

读取BoardConfig 4

读取所有Module 4

产生相应的Rules ,生成 image 5

具体make 操作: 6

完整编译 6

模块编译 6

单独编译image 文件 7

一些疑问和解答: 7

 

 

 

Makefile的主要流程

以下主要流程都 在build/core/main.mk 里 安排。

 初始化相关的参数设置(buildspec.mk  envsetup.mk  config.mk)

 检测编译环境和目标环境

 决定目标product

 读取product 的配置信息及目标平台信息

 清除输出目录

 检查版本号

 读取Board 的配置

 读取所有Module 的配置

 根据配置产生必要的规则(build/core/Makefile)

 生成image

初始化参数设置

 main.mk 里,简单设置 几个主要编译路径的变量后,来到config.mk 

——————————————config.mk ——————————————

其中设置了源文件的一系列路径,包括头文件、库文件、服务、API 已经编译工具的路径。(前36 行)

从40 行开始,定义一些编译模块的生成规则:

 

这里面除了第一个CLEAR_VARS 外,其他都对应的一种模块的生成规则,每一个 module 都会来include 其中某个来生成目标模块。

例如:

Camera模块的 makefile 里( Android.mk )就包含了其中的一种生成规则BUILD_PACKAGE 

 

也就是Camera 会按照 package.mk 里的生成规则去生成目标模块。

回到config.mk ,接着会尝试读取 buildspec.mk 的设置:

 

如同注释所说,会尝试查找 buildspec.mk ,如果文件不 存在会自动使用环境变量的设置,如果仍然未定义,会按arm 默认的设置去 build 

这里的buildspec.mk 可以自己创建,也可以将原先 build/ 下的 buildspec.mk.default 直接命名为buildspec.mk 并移到根目录。

 

 

实际上,buildspec.mk 配置都被屏蔽了,我们可以根据需要直接打开和修改一些变量。在这里我们可以加入自己的目标产品信息:

ifndef TARGET_PRODUCT

TARGET_PRODUCT:=mobot

endif

以及输出目录设置:

OUT_DIR:=$(TOPDIR)mobot

读取Product 的设定

回到config.mk ,接着进行全局变量设置,进入 envsetup.mk 

——————————————envsetup.mk ——————————————

里面的大部分函数都在build/envsetup.sh 中定义。

首先,设置版本信息,(11  )  build/core/version_defaults.mk 中具体定义平台版本、 SDK 版本、Product 版本,我们可以将 BUILD_NUMBER 作为我们产品 mobot  version 信息,当然,也可以自定义一个版本变量。

回到envsetup.mk ,接着设置默认目标产品 (generic) ,这里由于我们在 buildspec.mk 里设置过TARGET_PRODUCT ,事实上这个 变量值为mobot 

然后读取product 的设置 (41  ) , 具体实现在 build/core/ product_config.mk 中,进而进入product.mk ,从 build/target/product/ AndroidProducts.mk 中读出PRODUCT_MAKEFILES ,这些makefile 各自独立定义 product ,而我们的产品 mobot 也应添加一个 makefile 文件 mobot.mk 。在mobot.mk 中我们可以加入所需编译的 PRODUCT_PACKAGES 

下面为HOST 配置信息及输出目录,最后打印相关信息:

 

读取BoardConfig

接着回到config.mk  (114  ) 这 里会搜索所有的 BoardConfig.mk ,主要有以下两个地方:

$(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)/BoardConfig.mk 

vendor/*/$(TARGET_DEVICE)/BoardConfig.mk 

这里的TARGET_DEVICE 就是 mobot ,就是说为了定义我们自己的产品 mobot ,我们要在build/target/board 下添加一个自己的 目录 mobot 用来加载自己 的 board 配置。

在BoardConfig.mk 中会决定是否编译 bootloader  kernel 等信息。

读取所有Module

结束全局变量配置后,回到main.mk ,马上对编译工具及版本进行检查,错误便中断编译。

142行,包含文件 definitions.mk ,这里面定义了许多变量和函数供main.mk 使用。 main.mk  446行,这里会去读取所有的 Android.mk 文件:

include $(ONE_SHOT_MAKEFILE)

这个 ONE_SHOT_MAKEFILE 是在前面提到 的mm(envsetup.mk) 函数中赋 值的:

ONE_SHOT_MAKEFILE=$M make -C $T files $@

而M=$(findmakefile), 最终实现在:

 

回到main.mk ,最终将遍历查找到的所有子目录下的 Android.mk 的路径保存到 subdir_makefiles 变量里 (main.mk 里的 470  ) 

 

我们在package/apps 下每个模块根目录都能看到 Android.mk ,里面会去定义当前本地模块的 Tag LOCAL_MODULE_TAGS ,Android 会通过这个 Tag 来决定哪些本地模块会编译进系统,通过PRODUCT  LOCAL_MODULE_TAGS 来决定哪些应用包会编译进系统。 ( 前面说 过,你也能通过buildspec.mk 来 制定你要编译进系统的模块 )

这个过 程在mian.mk  445 行开始,最后需要编译的模块路径打包到ALL_DEFAULT_INSTALLED_MODULES (602 ) 

 

 

产生相应的Rules ,生成 image

所有需要配置的准备工作都已完成,下面该决定如何生成image 输出文件了,这一过程实际上在build/core/Makefile 中处理的。

这里定义各种img 的生成方式,包括 ramdisk.img  userdata.img  system.img  update.zip recover.img 等。具体对应的 rules 可以参考下图:

http://p.blog.csdn.net/images/p_blog_csdn_net/yili_xie/EntryImages/20091214/make%20goals.png

当Make include 所有的文件,完成对所有 make 文件的解析以后就会寻找生成 对应目标 的规则,依次生成它的依赖,直到 所有满足的模块被编译好,然后使用相应的工具打包成相应的img 

 

具体make 操作:

完整编译

我们在根目录下输入make 命令即可开始完全编译。这个命令实际编译生成的默认目标是 droid:

 

也就是说,大家敲入make 实际上执行的 make droid 。而接下来大家看看 main.mk 文件里最后面的部分,会有很多伪目标,如 sdk  clean  clobber 等,这些在默认的 make droid 的命令下是不会执行的。我们可以在 make 后加上这些标签来单独实现一些操作。如:输入 make sdk  将会生成该版本对应的 SDK ,输入 make clean 会清除上次编译的输出。

模块编译

有时候我们只修改了某一个模块,希望能单独编译这个模块而不是重新完整编译一次,这时候我们要用到 build/envsetup.sh中提供的几个 bash 的帮助函数。

在 源代码根目录下执行:

.  build/envsetup.sh(.后面有空格 )

这 样大家相当于多了几个可用的命令。

这 时可以用help 命令查看帮助信息:

 

其中对模块编译有帮助的是tapas  m  mm  mmm 这几个命令。

1、 tapas——以交互方式设置 build 环境变量。

   输入:tapas

    第一步,选择目标设备:

 

    第二步,选择代码格式

第三步,选择产品平台:

 

     注意:这里,Google 源代码里默认是 generic ,而我们针对自己的产品应修改成 mobot

           具体在build/envsetup.sh 里的函数 chooseproduct() 中对相应代码进行修 改。

 

2、 m mm  mmm 使用独立模块的 make 命令。

几个命 令的功能使用help 命令查看。

举个例 子,我们修改了Camera 模块的代码,现 在需要重新单独编译这一块,这时可以使用 mmm命令,后面跟指定模块的路径 ( 注意是模块的根目录 ) 

具体如 下:

mmm packages/apps/Camera/

为了可 以直接测试改动,编译好后需要重新生成system.img

可以执 行:make snod

单独编译image 文件

一般我 们完整编译后,会生成三个重要的image 文 件: ramdisk.img  system.img  userdata.img 。当然我们可以分开单独去编译 这三个目标:

make ramdisk —— ramdisk.img

make userdataimage —— userdata.img

make systemimage  —— system.img

一些疑问和解答:

1)  什么是recovery.img 

顾名思义,recovery.img 是为了恢复系统的,相对于普通的 boot.img  recovery.img 多了一些图片文件 ( 恢复时界面的背景 )  /sbin/recovery/ 目录 ( 跟 恢复有关的二进制文件 ) ,一 些初始化文件也不相同 (init.rc  init.goldfish.rc  default.prop)

这就是为什么启 动恢复模式时会进入类似文本界面而不是图形界面。

将recovery.img 文件复制到 SD 卡中,进入 shell 下输入:

mount -a

flash_image recovery /sdcard/recovery.img

若提示“no space on device ”,可用 fastboot 模式刷

fastboot erase recovery

fastboot flash recovery recovery.img

在关机状态下按home+power 键进入 recovery 模式,根据选项选择需要的操作。

 

2)  make sdk make droid 编译有什么不同?

make sdk

其实,执行make sdk ,编译后会在目录 out/host/linux-x86 里生成 sdk 目录,这个 sdk 和官方下载的 sdk 包是一样的,可以直接使用。

make droid

make


转自:http://yueguc.iteye.com/blog/888980


阅读更多
个人分类: Android
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭