第四章、Android编译系统与定制Android平台系统

 

4.1Android编译系统

Android的源码由几十万个文件构成,这些文件之间有的相互依赖,有的又相互独立,它们按功能或类型又被放到不同目录下,对于这个大的一个工程,Android通过自己的编译系统完成编译过程。

4.1.1 Android编译系统介绍

Android和Linux一样,他们的编译系统都是通过Makefile工具来组织编译源码的。Makefile工具用来解释和执行Makefile文件,在Makefile文件里定义好工程源码的编译规则,通过make命令即可以完成对整个工程的自动编译。因此分析makefile文件是理解编译系统的关键。

在Android中,下面几个主要的makefile文件构成了Android编译系统。

图x-x Android编译系统组成

 

①   Makefile:编译系统的入口Makefile文件,它只有一行代码,包含build/core/main.mk

②   build/core/main.mk:主要Makefile,定义了Android编译系统的主线

③   build/core/config.mk:根据用户输入的编译选项导出配置变量,影响编译目标

④   build/core/envsetup.mk:定义大量全局变量,用户编译配置

⑤   build/core/product_config.mk:根据用户选择的目标产品,定义编译结果输出目录

⑥   device/*/$(TARGET_DEVICE)/BoardConfig.mk:根据用户选择的目标产品找到对应的设备TARGET_DEVICE,加载设备的板级配置

⑦   build/core/definitions.mk:定义编译过程中用到的大量变量和宏,是编译系统的函数库

⑧   MODULES_DIR/Android.mk :每个模块的规则定义文件,它出现在每个要编译的目录下,如图x-x所示,我们可以自己向Android系统中添加自己的模块,来达到定制系统的目的。


图x-x 模块中的Android.mk文件

⑨   build/core/Makefile:Android编译目标规则定义文件,最终编译结果在该文件中定义,如system.img、ramdisk.img、boot.img、userdata.img等

4.1.2 Android.mk文件

在Android源码中,大量的源码按照功能通过目录来分类,同一功能的代码通常被编译成一个目标文件,目标文件不仅仅包含可执行C/C++应用程序,还包含动态库、静态库、Java类库、Android应用程序等,在Android编译系统中,每个被编译的目标文件被称为一个模块(module),在每个模块的源码目录中必须创建一个Android.mk文件作为编译规则,这些Android.mk文件在编译时被编译系统中的findleaves.py脚本包含进去。

@build/core/main.mk

489 subdir_makefiles := \

490    $(shell build/tools/findleaves.py --prune=out --prune=.repo --prune=.git$(subdirs) Android.mk)                              

491

492 include $(subdir_makefiles)

注:findleaves.py由Python语言编译的脚本,Python是一种执行效率比较高的面向对象的脚本,上述脚本意思是返回subdirs目录下的Android.mk文件,但是会跳过out、.reop、.git目录。

通常编译一个模块时编译器需要知道以下内容:

Ø 编译什么文件?(指定源码目录和源码文件)

Ø 编译器需要哪些编译参数?

Ø 编译时需要哪些库或头文件?

Ø 如何编译?(编译成动态库、静态库、二进制程序、Android应用还是Java库?)

Ø 编译目标

Android.mk的语法不同于Makefile,Android.mk语法更简洁,用户只需在Android.mk中定义出一些编译变量,Android的编译系统会根据Android.mk文件中变量的值进行编译。

比如Zygote进程app_process模块中的Android.mk如下面代码所示:

@ frameworks/base/cmds/app_process/Android.mk

  1LOCAL_PATH:= $(call my-dir)              #指定源码目录

  2include $(CLEAR_VARS)                     #包含清除编译变量的mk文件,防止影响本次编译

  3

  4LOCAL_SRC_FILES:= \                      #指定被编译源码

  5     app_main.cpp

  6

  7LOCAL_SHARED_LIBRARIES := \               #指定编译Zygote时用到的其它动态库

  8     libcutils \

  9     libutils \

 10     libbinder \

 11     libandroid_runtime

 12

 13LOCAL_MODULE:= app_process                #指定被编译模块的名字

 14

 15include $(BUILD_EXECUTABLE)                  #指定编译方式,编译成可执行程序

再比如Camera应用程序中的Android.mk:

@ packages/apps/Camera/Android.mk

  1LOCAL_PATH:= $(call my-dir)                        #指定源码目录

  2include $(CLEAR_VARS)                              #包含清除编译变量的mk文件,防止影响本次编译

  3

  4LOCAL_MODULE_TAGS := optional                      #指定应用程序标签

  5

  6LOCAL_SRC_FILES := $(call all-java-files-under, src)      #指定被编译源码

  7

  8LOCAL_PACKAGE_NAME := Camera                   #指定Android应用程序名

  9LOCAL_SDK_VERSION := current                        #指定该应用程序依赖的SDK版本

 10

 11LOCAL_PROGUARD_FLAG_FILES := proguard.flags    #指定混淆编译配置文件

 12

 13include $(BUILD_PACKAGE)                        #指定模块编译方式,这儿编译成Android应用程序

 14

 15 # Usethe following include to make our test apk.

 16include $(call all-makefiles-under,$(LOCAL_PATH))        # 包含当前目录下子目录中的Android.mk文件,向下编译

通过上面两个例子可以看出来,Android.mk文件结构很简单,每个模块的Android.mk文件必须完成以下操作:

Ø 指定当前模块的目录

通过调用$(call my-dir)命令包(一些Makefile的集合),来获得当前模块目录。

Ø 清除所有的LOCAL_XX变量

通过include命令包含clear_vars.mk文件来清除所有的LOCAL_XX变量,防止影响本次编译结果,clear_vars.mk文件由变量CLEAR_VARS来定义

Ø 指定源码文件

通过LOCAL_SRC_FILES变量指定源码文件,对于C/C++文件,要将它们全部列出来赋值给LOCAL_SRC_FILES(见上面程序代码),对于Java源码,可以通过调用命令包$(callall-java-files-under, src)来实现,它会在src目录下查找所有的Java文件,将其罗列出来。

Ø 指定编译细节

在编译时可能需要修改编译器参数、需要链接其它的库、需要其它路径下的头文件等编译细节。

Ø 指定目标模块名

如果是C/C++库、可执行程序或Java类库,通过LOCAL_MODULE指定最终编译出来的模块名,如果是Android应用程序,通过LOCAL_PACKAGE_NAME变量来指定。

Ø 指定目标模块类型

模块最终都要进行编译,通过include 命令包含一些预定义好的变量来指定模块最终的类型,这些变量分别对应一个makefile文件,包含了模块类型的编译过程。主要的预定义编译变量如下:

编译变量

功能

BUILD_SHARED_LIBRARY

将模块编译成共享库

BUILD_STATIC_LIBRARY

将模块编译成静态库

BUILD_EXECUTABLE

将模块编译成可执行文件

BUILD_JAVA_LIBRARY

将模块编译成Java类库

BUILD_PACKAGE

将模块编译成Android应用程序包

注:上述编译变量的定义在build/core/definitions.mk中。

在Android.mk中,主要编译变量如下表所示:

编译变量

功能

LOCAL_PATH

指定编译路径

LOCAL_MODULE

指定编译模块名

LOCAL_SRC_FILES

指定编译源码列表

LOCAL_SHARED_LIBRARIES

指定使用的C/C++共享库列表

LOCAL_STATIC_LIBRARIES

指定使用的C/C++静态库列表

LOCAL_STATIC_JAVA_LIBRARIES

指定使用的Java库列表

LOCAL_CFLAGS

指定编译器参数

LOCAL_C_INCLUDES

指定C/C++头文件路径

LOCAL_PACKAGE_NAME

指定Android应用程序名

LOCAL_CERTIFICATE

指定签名认证

LOCAL_JAVA_LIBRARIES

指定使用的Java库列表

LOCAL_SDK_VERSION

指定编译Android应用程序时的SDK版本

注:其它的编译变量见附录。

4.1.3实验:编译HelloWorld应用程序

【实验内容】

在Ubuntu系统中使用eclipse开发环境编写简单的HelloWorld应用程序,然后使用Android编译系统进行编译,最终将HelloWorld应用程序作为系统应用集成到Android系统中。

【实验目的】

通过实验,学员掌握在Android源码的编译系统中编译Android应用程序、库、可执行程序,了解Android系统应用程序的定制过程,最终在Android模拟器中,运行自己通过编译系统编译的Android应用程序。

【实验平台】

拥有Android源码的Ubuntu操作系统(可以在Windows系统中虚拟Ubuntu系统)。

【实验步骤】

1.      打开eclipse开发环境,创建一个Android应用程序:HelloWorld:

$ cd ~/android/eclipse

$./eclipse &

 

2.      将新创建的HelloWorld工程拷贝到源码目录中的packages/apps目录下:

$ cp -rf HelloWorld/~/android/android_source/packages/apps

在HelloWorld工程目录下删除由eclipse开发环境自动生成的文件和目录,仅保留如图x-x所示工程目录结构:


3.      编译HelloWorld工程的Android.mk文件,我们可以仿照Android里自带的应用程序的Android.mk文件,例如Camera工程中的Android.mk文件:

将Camera工程中的Android.mk文件拷贝到HelloWorld工程中:

$ cp  ../Camera/Android.mk./

修改Android.mk文件,删除没必要的编译变量:

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

 

LOCAL_MODULE_TAGS := optional

 

LOCAL_SRC_FILES := $(call all-java-files-under,src)

 

LOCAL_PACKAGE_NAME := HelloWorld

LOCAL_SDK_VERSION := current

 

include $(BUILD_PACKAGE)

4.      编译HelloWorld工程:

Ø 切换到Android源码目录下:

$ cd ~/android/android_source/

Ø 加载编译函数:

$ source build/envsetup.sh

Ø 选择编译目标项:

$ lunch generic-eng

Ø 通过mmm命令编译HelloWorld工程:

$ mmm packages/apps/HelloWorld/

Ø 编译生成模拟器映像system.img:

$ make snod

注:我们也可以直接通过make命令来编译HelloWorld工程并生成system.img映像文件,但是这种方式耗时比较长,所以我们使用上面的编译方式,能节省实验时间,关于Android源码编译的细节,请查看2.3.2编译Android章节。

 

5.      启动模拟器,查看HelloWorld应用程序运行效果:

$ ./run_emulator.sh

注:run_emulator.sh是快速运行模拟器的脚本,详细说明请查看2.5定制Android模拟器章节。




更多相关文章

  1. 熟悉Android打包编译的流程
  2. android体系结构
  3. Android应用程序进程启动过程的源代码分析
  4. Android(安卓)AOSP基础(三)Android系统源码的整编和单编
  5. 在Windows中的安装Android(安卓)NDK开发环境
  6. android 问题总结
  7. Android编译环境
  8. Android(安卓)AOSP基础(三)Android系统源码的整编和单编
  9. Android工程中R.java文件的重新生成——注意资源文件的错误

随机推荐

  1. android点滴3
  2. android用异步操作AsyncTask编写文件查看
  3. android 教程
  4. Android记事本的开发
  5. Android(安卓)安装步骤
  6. 可循环显示图像的Android(安卓)Gallery组
  7. android实现渐变效果
  8. android Menu 菜单使用总结
  9. android 监听EditText 复制粘贴等操作
  10. Android(安卓)NetworkLocationProvider a