深入浅出 - Android系统移植与平台开发(十)- Android编译系统与定制Android平台系统(瘋耔修改篇二)
第四章、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模拟器章节。
深入浅出 - Android系统移植与平台开发(十)- Android编译系统与定制Android平台系统(瘋耔修改篇二)的更多相关文章
- 深入浅出 - Android系统移植与平台开发(十一)- Android系统的定制(瘋耔修改篇一)
首先非常感谢原文作者为我们提供的知识库,因为有你们的贡献,我们的开发难度更显简单 原文 : http://blog.csdn.net/mr_raptor/article/details/30113 ...
- 第一章 Android系统移植与驱动开发概述
本书第一章首先简单概要地介绍了关于Android系统移植和驱动开发的相关内容. 所谓“移植”是指为特定的自己的设备,如手机定制Android的过程.自己开发一些程序(移植)装载在设备上,使得Andro ...
- Android系统移植与驱动开发----第一章
第一章 Android系统移植与驱动开发 Android源代码定制完全属于自己的嵌入式系统,但是支持的设备不多,所以要移植,而在移植的过程中使用的不得不提的是驱动开发. Android系统构架主要包括 ...
- 第一章 Andorid系统移植与驱动开发概述 - 读书笔记
Android驱动月考1 第一章 Andorid系统移植与驱动开发概述 - 读书笔记 1.Android系统的架构: (1)Linux内核,Android是基于Linux内核的操作系统,并且开源,所以 ...
- Java微信公众平台开发(十二)--微信用户信息的获取
转自:http://www.cuiyongzhi.com/post/56.html 前面的文章有讲到微信的一系列开发文章,包括token获取.菜单创建等,在这一篇将讲述在微信公众平台开发中如何获取微信 ...
- Java微信公众平台开发(十)--微信用户信息的获取
前面的文章有讲到微信的一系列开发文章,包括token获取.菜单创建等,在这一篇将讲述在微信公众平台开发中如何获取微信用户的信息,在上一篇我们有说道微信用户和微信公众账号之间的联系可以通过Openid关 ...
- 深入浅出 - Android系统移植与平台开发(六)- 为Android启动加速
作者:唐老师,华清远见嵌入式学院讲师. Android的启动速度一直以来是他的诟病,虽然现在Android设备的硬件速度越来越快,但是随着新 版本的出现,其启动速度一直都比较慢,当然,作为程序员,我们 ...
- 深入浅出 - Android系统移植与平台开发(五)- 定制手机模拟器ROM
一. 修改化定制Android4.0系统 Android系统启动时,先加载Linux内核,在Linux的framebuffer驱动里可以定制开 机界面,Linux内核启动成功后,挂载根文件系统,启动A ...
- 第一章Android系统移植与驱动开发概述--读书笔记
以前,初步学习过嵌入式Linux驱动开发的基础课程,对于驱动开发可以说是有了一点点微末的基础吧.首先我们要对Android嵌入式系统有一个初步的认识,Android系统发展到今天已经具备了完善的架构. ...
随机推荐
- Orchard 学习-手动安装Orchard
通过Orchard zip 文件手动配置网站 这篇文章将引导你如果通过Zip文件来安装Orchard. 我们会使用三种不同的方法来承载Orchard: IIS. WebMatrix and IIS E ...
- works-er
- JS修改JSON中key的方法
function modifyJosnKey(json,oddkey,newkey){ var val=json[oddkey]; delete json[oddkey]; json[newkey]= ...
- C#的垃圾回收机制及弱引用
在上一篇中,讨论了字符串常量的拘留池和不可变性:对于字符串变量,没有这个特性(或其他DotNet的非托管资源),当我们使用完后就要手动回收,即将变量的值指向null(p=null),然而堆内存中,那个 ...
- AFNetworking3.0+MBProgressHUD二次封装,一句话搞定网络提示
对AFNetworking3.0+MBProgressHUD的二次封装,使用更方便,适用性非常强: 一句话搞定网络提示: 再也不用担心网络库更新后,工程要修改很多地方了!网络库更新了只需要更新这个封装 ...
- 关于layoutSubviews以及drawRect方法
首先两个方法都是异步执行.layoutSubviews方便数据计算,drawRect方便视图重绘. layoutSubviews在以下情况下会被调用: 1.init初始化不会触发layoutSubvi ...
- html-----013----实体字符/HTML URL 编码
<!DOCTYPE> 声明 版本 年份 HTML 1991 HTML+ 1993 HTML 2.0 1995 HTML 3.2 1997 HTML 4.01 1999 XHTML 1.0 ...
- CDT 错误 Cannot run program "gcc"
Eclipse+CDT 编辑C/C++程序出错误: 出现编译错误: **** Rebuild of configuration Debug for project example **** **** ...
- requirejs实践二 加载其它JavaScript与运行
上一篇中介绍了requirejs加载JavaScript文件,在这一篇中介绍加载JavaScript后执行代码 这次是test2.html文件, <!DOCTYPE html> <h ...
- 在HTML中插入回车换行
在制作EPUB的时候,发现原来收集的html文本根本就没有换行,这个在代码里面是无法忍受的,因为看着比较混乱,全部都是在一行里面,这个就像写作文的时候,你看到的文字全部都是在一行里面显示出来的,根本就 ...