`
isiqi
  • 浏览: 16026631 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

Android Makefile and build system 分析与梳理

 
阅读更多

前言:预计未来一致两年内移动互联网将会有很大的发展,必将孕育很多的机会,而 Google 推出的 Android 手机操作系统无疑将是移动互联网中的明星。由于其是开源系统,很有必要对此进行深入研究。

工欲善其事,必先利其器。 Makefile 无疑是打开系统架构的一扇窗户。但因 Android Makefile (build system) 文件众多,架构复杂,分析起来较为困难。本文梳理了 build system 的大致脉络,希望对 build system 感兴趣的同学们有所帮助。

1. Android Makefile & build system 概述

Makefile 文件用来告诉 make 命令需要怎么样的去编译和链接程序。在编译时,需要根据编译环境和编译目标选择编译工具,编译参数,以及选择编译安装哪些模块。同时 Makefile 指定了构建目标所需的依赖性以及生成规则。 Android 中,主要的 Makefile 文件存在于 build/core/ 目录下,它的表现形式为多个后缀为 mk 的文件组成,也称为 build system Android build system 主要有两大部分构成:配置部分,目标构建部分。 Build system 的主流程文件为 build/core/main.mk 文件。

Android build system 在设计中考虑了如下方面,具有良好的扩展性。

a) 增添子模块编译

b) CPU 架构 ARM/PPC(maybe)/X86(maybe)

c) 多语言编译 – C/C++/Java

d) 多目标 – static lib/share lib/execute/Java/Java library

e) 多发布版本

本文也将就围绕这些特性做进一步分析。

2. Build system 配置部分

配置部分主要完成以下几个工作:

a) 基于 Android 产品的配置( product config ):选择构建安装的运行程序 (user package)

b) 设置 target 等相关变量 TARGET_ARCH, TARGET_OS, TARGET_BUILD_TYPE, TARGET_PREBUILT_TAG

c) 根据编译环境设置 host 等相关变量 HOST_OS, HOST_ARCH, HOST_BUILD_TYPE, HOST_PREBUILT_TAG

d) 编译 target 上运行程序所需的工具链及编译参数设置,如 linux-arm-cc cflag include 目录等。

e) 编译 host 上运行程序所需的工具链及编译参数设置。

下图简要介绍了 Android build system 的配置部分的主要构成及相互关系。

android_makefile_config_overview

多发布版本的支持

Android 会被不同的厂商所采用,他们内置的 packages( 应用程序 ) 相应也会有差别。 AndroidProducts.mk 文件即为 Android build system 提供给厂商的接口文件。通过此文件即可定义所需编译和安装的 packages (也即应用程序)。缺省选项是 generic 。为了更容易的扩展, Android 定义了基本 package(core.mk) 和通用 package(generic.mk) ,通用 package 包含基本 package 。同时 Android 还实现了一个继承函数( inherit-product )。通过继承通用 package ,可以很容易的配置所需编译和安装的 package

CPU 架构的扩展

Config.mk 文件中会设置 combo_target 为不同的变量,然后 include select.mk 文件。在 select.mk 文件中,会根据 OS CPU 架构选择相应的 mk 文件,在这些相应的 mk 文件中,又定义了编译目标程序所需的工具链及编译参数。目前从 combo 目录下看, target 上不支持 PPC 架构。但如果要想支持 PPC 架构的话,只需在 combo 目录下创建 PPC mk 文件,在其中定义工具链和参数即可。

3. build system 目标构建部分

目标构建部分的主要工作就是选择所需构建的目标,确定它们所需依赖的目标,然后根据规则来构建最终的目标。说起来简单,可是在实际中就需要考虑很多问题了。

a) 作为一个设计优秀的 Framework ,如何方便的添加子模块?

b) Android 系统中,有多种编程语言的存在,它们的编译工具各不相同。即使同一种语言,如 C 语言,也存在 host target 的差别,编译器也不同。如何选择不同的工具进行模块的构建?

c) Android 系统中,存在不同种类的构建目标:有可执行文件, static library, dynamic library java library java 。如何构建这些不同的目标?

下图简要介绍了 Android build system 的构建部分的主要构成及相互关系

android_makefile_target_overview

main.mk 中,非常关键的一个步骤就是找到 TOP 目录下所有 Android.mk 文件,并 include 它们。在 Include 的过程中,就会确定子模块的构建目标,类型,和规则。

Android.mk 就是 build system 提供给子模块的借口文件。 Android.mk 有下面几个关键词:

LOCAL_SRC_FILES – 指定模块的源文件

LOCAL_MODULE – 指定所需构建的目标名

include 构建类型对应的文件 例如想构建在 target 上运行的可执行文件,那就执行语句 include $(BUILD_EXECUTABLE) 。通过此语句可有如下结果: a) 指定构建目标的类型 b )确定构建此类型所需的工具及参数。

通过定义自己的 Android.mk 文件,再修改上述等变量,即可轻松的把自身模块放入至 build system 中。

Main.mk 文件 471 行: include $(subdir_makefiles)

subdir_makefiles TOP 目录下所有 Android.mk 文件的集合。语句虽短,可确是整个 build system 中最为重要的一条语句。无论有多少子模块,无论构建模块的目标类型,无论它是什么语言所写,就这一条语句,完成了这些纷繁复杂的工作。

是否似曾相识? Android.mk 就类似于 build system 提供的基类, LOCAL_MODULE LOCAL_SRC_FILES include 构建类型文件等类似于基类提供的虚函数。通过继承基类 (Android.mk) ,重写虚函数(重新定义 LOCAL_ 等变量),遍历子类集合调用虚函数( include $(subdir_makefiles) ),完美的解决了本节开头的问题。为 Android build system 提供了良好的可扩展性。

后记:

设计模式,架构并不仅存于 OO 的语言中 (Java/C++) 。即便如 Makefile 的类脚本语言,也可写出如此之架构。设计的思想在于人,而不取决于他所用的工具。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics