- make: 编译源码,生成相应的系统镜像文件。
- make snod: 重新生成一个system.img系统镜像文件
- make kernel: 编译内核(可选)一般根据envsetup.sh文件内容而论
- m: Makes from the top of the tree(编译全部模块)。
- mm: Builds all of the modules in the current directory(编译当前目录下的所有模块)。
- mmm: Builds all of the modules in the supplied directories(编译指定目录下的所有模块)。
我们可以通过启动模拟器来验证我们是否编译正确 ,注意,我们最好在system.img所在的目录下进行如下动作
~$ emulator -kernel ~/android2.2/prebuilt/android-arm/kernel/kernel-qemu -ramdisk ramdisk.img -debug all -data userdata-qemu.img -system system.img -sysdir . -show-kernel -skin 800x480
如果能正确启动则说明完全编译成功啦。
完全编译完后我们就可以使用make sdk命令做一次SDK的编译拉,步骤如下:
~$ cd ~/android/src
~$ make sdk
注意:如果需要build SDK,随着版本的不同,我们所需的环境也不同,编译android2.2之前的版本需要安装sun-java5-jdk, 而不是sun-java6-jdk,否则会出现如下错误:(略)
sdk编译成功后会在~/android /src/out/host/linux-x86/sdk/ 生成sdk的文件目录和压缩包:
android-sdk_eng.anjoy_linux-x86
android-sdk_eng.anjoy_linux-x86.zip
并在~/android /src/out/target/product/generic(generic是默认的产品名)下打包所有的映像文件:
generic-img-eng.anjoy.zip
生成的SDK目录结构为:
/home/anjoy/android/src/out/host/linux-x86/sdk/android-sdk_eng.anjoy_linux-x86:
总计 32
drwxrwx--- 6 anjoy anjoy 4096 2011-06-27 17:48 .
drwxr-x--- 3 anjoy anjoy 4096 2011-06-27 17:48 ..
drwxrwx--- 2 anjoy anjoy 4096 2011-06-27 17:48 add-ons
drwxrwx--- 14 anjoy anjoy 4096 2011-06-27 17:48 docs
-rw-rw---- 1 anjoy anjoy 172 2011-06-27 17:50 documentation.html
drwxrwx--- 3 anjoy anjoy 4096 2011-06-27 17:48 platforms
-rw-rw---- 1 anjoy anjoy 225 2011-06-27 17:50 RELEASE_NOTES.txt
drwxrwx--- 3 anjoy anjoy 4096 2011-06-27 17:50 tools
想很方便的使用生成的SDK只需要在.bashrc中增加:
export PATH=$PATH:/home/anjoy/android/src/out/host/linux-x86/sdk/android-sdk_eng.anjoy_linux-x86/tools
2.2、模块化编译
注意:在模块化编译之前我们一定要把envsetup.sh 脚本source 一下,或者你直接把envsetup.sh文件所在的路径配置到你个人的bashrc文件里面,这样你就不要每次都作source动作拉。
envsetup.sh 提供了一些的bash函数定义,当运行了envsetup.sh后就可以使用help 命令来查看:
~$ help
Invoke ". build/envsetup.sh" from your shell to add the following functions to your environment:
- croot: Changes directory to the top of the tree.
- m : Makes from the top of the tree.
- mm : Builds all of the modules in the current directory.
- mmm : Builds all of the modules in the supplied directories.
- cgrep: Greps on all local C/C++ files.
- jgrep: Greps on all local Java files.
- resgrep: Greps on all local res/*.xml files.
- godir: Go to the directory containing a file.
...
..
其中对模块的编译有帮助的是tapas、m、mm、mmm这几个命令。
其中mmm 后面要跟模块的根目录,不是所有的目录下都有子模块,那些含有Android.mk 文件目录才是模块的根目录,模块名可以从Android.mk 的LOCAL_MODULE 或者LOCAL_PACKAGE_NAME 变量中得到。
单独编译某模块,需要在mmm后面指定模块路径,例如编译application中的Launcher2:
mmm packages/apps/Launcher2/
或者在src目录下直接运行make module name:
cd ~/android/src
make Launcher2
2.3、增量编译的步骤
a、假如我们修改了某个模块下的代码,那么我们只需要从新编译这个模块就可以拉,而不需要整个工程的编译。
b、编译所修改的代码所在模块,例如:
cd ~/android/src
mmm packages/apps/Launcher2
c、在~/android/src中运行:
cd ~/android/src
make snod
d、该命令生成一个新的系统映像system.img,将这个系统映像拷贝至sdk下:
cd ~/android/src
cp out/target/product/generic/system.img /
out/host/linux-x86/sdk/android-sdk_eng.anjoy_linux-x86/tools/lib/images/
OK,这样就完成了Android源码的编译以及SDK的生成拉
提醒:如果你是Ubuntu10.04系统 32位机上安装编译Android2.3源码,其步骤和注意事项如下:
1.安装JDK6
对于Android2.3 系统,不要安装JDK5 ,应该安装最新的JDK6 。
如果安装了JDK6,Android会自动按64位编译,如果系统是32位的,会有编译错误,后面会说如何修改这个错误。
sudo add-apt-repository "deb http://archive.canonical.com/ lucid partner"
sudo add-apt-repository "deb-src http://archive.canonical.com/ubuntu lucid partner"
sudo apt-get update
sudo apt-get install sun-java6-jdk
sudo update-java-alternatives -s java-6-sun
安装完后,需要手动设置JAVA_HOME, JRE_HOME , CLASS_PATH为JDK6 的安装路径。
2.进行编译android2.3
~$ cd ~/android2.3
~$ source build/envsetup.sh
~$ make
在make的时候会提示出错:
************************************************************
You are attempting to build on a 32-bit system.
Only 64-bit build environments are supported beyond froyo/2.2.
************************************************************
因为Android2.3默认是64位的系统上编译,需要手动修改build/core/main.mk,把这个判断部分注释掉:
#ifneq (64,$(findstring 64,$(build_arch)))
#$(warning ************************************************************)
#$(warning You are attempting to build on a 32-bit system.)
#$(warning Only 64-bit build environments are supported beyond froyo/2.2.)
#$(warning ************************************************************)
#$(error stop)
#endif
重新make,如果是安装了JDK6版本,会又报错:
Docs droiddoc: out/target/common/docs/api-stubs
Could not load ‘clearsilver-jni’
java.library.path = out/host/linux-x86/lib
make: *** [out/target/common/docs/api-stubs-timestamp] Error 45
make: *** Waiting for unfinished jobs….
Could not load ‘clearsilver-jni’
java.library.path = out/host/linux-x86/lib
make: *** [out/target/common/docs/doc-comment-check-timestamp] Error 45
我们只需要修改这几个文件,该回到32位编译环境即可:
# external/clearsilver/cgi/Android.mk
# external/clearsilver/java-jni/Android.mk
# external/clearsilver/util/Android.mk
# external/clearsilver/cs/Android.mk
把上面这些文件内容的编译选项-m64 改成-m32 即可
重新make,大概不到一个小时就make完了。
OK,大工告成
android系统正以迅雷不及掩耳之势冲击着智能手机与平板电脑市场,它颠覆了传统手机的概念,将手机与平板电脑进行了一次大洗牌,最可贵的是他的开放性(虽不是完全开放)吸引了一大批工程师去改造它,完善它,任何人都可以下载到它的源代码一睹它的真面目。这一节讲讲这样从头配置一个属于你的android系统,至于如何获取android源代码这里就不讲了。本文是在假设你已经从android官网上获取了其源代码的基础上讲解的。
1.Create a company directory in //vendor/.
mkdir vendor/<company_name>
这一步是先在vendor(供货商) 下新建一个目录,用你公司名字命名,没有的公司的就随便编一个吧(:
2.Create a products directory beneath the company directory you created in step 1.
mkdir vendor/<company_name>/products/
同上,创建一个目录,用你产品的名字命名吧
3.Create a product-specific makefile, called vendor/<company_name>/products/<first_product_name>.mk, that includes at least the following code:
$(call inherit-product, $(SRC_TARGET_DIR)/product/generic.mk)
#
# Overrides
PRODUCT_NAME := <first_product_name>
PRODUCT_DEVICE := <board_name>
在/products/ 目录下建立一个mk文件,内容格式如上所示,拿个mini6410.mk的例子给大家看看:
$(call inherit-product, $(SRC_TARGET_DIR)/product/generic.mk)
# Overrides
PRODUCT_MANUFACTURER := FriendlyARM
PRODUCT_BRAND := FriendlyARM
PRODUCT_NAME := mini6410
PRODUCT_DEVICE := mini6410
***************************************************
mini6410.mk的路径为/Android-2.2/vendor/friendly-arm/products/mini6410.mk l;这也验证了上述1,2两步。
4.在上述*.mk文件中添加可选的定义,这个就不多说了。
5.In the products directory, create an AndroidProducts.mk file that point to (and is responsible for finding) the individual product make files.
#
# This file should set PRODUCT_MAKEFILES to a list of product makefiles
# to expose to the build system. LOCAL_DIR will already be set to
# the directory containing this file.
#
# This file may not rely on the value of any variable other than
# LOCAL_DIR; do not use any conditionals, and do not look up the
# value of any variable that isn't set in this file or in a file that
# it includes.
#
PRODUCT_MAKEFILES := /
$(LOCAL_DIR)/first_product_name.mk /
按照这个模板添加就是了。
6.Create a board-specific directory beneath your company directory that matches the PRODUCT_DEVICE variable <board_name> referenced in the product-specific make file above. This will include a make file that gets accessed by any product using this board.
mkdir vendor/<company_name>/<board_name>
在你公司的目录下添加一个目录,名字命名为板子的名字,如:Android-2.2/vendor/friendly-arm/mini6410,其中mini6410就是开发板的名字,这个目录下的文件比较重要。接下来为了好叙述,就借用mini6410的例子吧。
7.在Android-2.2/vendor/friendly-arm/mini6410目录下创建BoardConfig.mk文件
先看看这个文件的内容是怎样的:
- # config.mk
- #
- # Product-specific compile-time definitions.
- #
- # The generic product target doesn't have any hardware-specific pieces.
- TARGET_CPU_ABI := armeabi
- TARGET_NO_BOOTLOADER := true
- TARGET_NO_KERNEL := true
- TARGET_PROVIDES_INIT_RC := true
- # Customized map
- TARGET_PRELINKER_MAP := vendor/friendly-arm/products/prelink-linux-arm-FA.map
- # Hardware 3D
- TARGET_HARDWARE_3D := false
- # Audio
- BOARD_USES_ALSA_AUDIO := true
- BUILD_WITH_ALSA_UTILS := true
- # Camera
- BOARD_CAMERA_LIBRARIES := libcamera
- BOARD_S3CJPEG_LIBRARIES := libs3cjpeg
- # Wi-Fi
- BOARD_HAVE_LIBWIFI := true
- #BOARD_WPA_SUPPLICANT_DRIVER := WEXT
- BOARD_WPA_SUPPLICANT_DRIVER := CUSTOM
- #CONFIG_DRIVER_NL80211 := true
- WPA_BUILD_SUPPLICANT := true
- #WPA_SUPPLICANT_VERSION := VER_0_6_X
- CONFIG_CTRL_IFACE := y
- # Bluetooth
- BOARD_HAVE_BLUETOOTH := true
- # GPS
- BOARD_GPS_LIBRARIES :=libgps
BoardConfig.mk文件是干嘛的呢,从上面的例子代码中你也许能猜出来,BoardConfig.mk是用来定制你的设备具有什么功能的,比如说是否支持摄像头,GPS导航等一些板级定制。该文件是我们定制android系统中比较重要的一个文件。
8.修改系统属性。
该项不是必须的,但大部分情况下我们深度定制系统时都要修改系统属性。
如何修改呢,在/Android-2.2/vendor/friendly-arm/mini6410/下创建一个system.prop文件,内如如下所示:
# system.prop for
# This overrides settings in the products/generic/system.prop file
#
# rild.libpath=/system/lib/libreference-ril.so
# rild.libargs=-d /dev/ttyS0
9.在/Android-2.2/vendor/friendly-arm/products添加AndroidProducts.mk文件,该文件下可包含多个board_name.mk文件,即多个设备。代码如下所示:
PRODUCT_MAKEFILES := /
$(LOCAL_DIR)/first_product_name.mk /
$(LOCAL_DIR)/second_product_name.mk
10.在/Android-2.2/vendor/friendly-arm/mini6410下添加Android.mk文件,该文件至少包含以下内容:
- # make file for new hardware from
- #
- LOCAL_PATH := $(call my-dir)
- #
- # this is here to use the pre-built kernel
- ifeq ($(TARGET_PREBUILT_KERNEL),)
- TARGET_PREBUILT_KERNEL := $(LOCAL_PATH)/kernel
- endif
- #
- file := $(INSTALLED_KERNEL_TARGET)
- ALL_PREBUILT += $(file)
- $(file): $(TARGET_PREBUILT_KERNEL) | $(ACP)
- $(transform-prebuilt-to-target)
- #
- # no boot loader, so we don't need any of that stuff..
- #
- LOCAL_PATH := vendor/<company_name>/<board_name>
- #
- include $(CLEAR_VARS)
- #
- # include more board specific stuff here? Such as Audio parameters.
到此为止,初步定制基本完成,该配置部分的架构如下图所示:
1、For config
这类文件主要来配置product,board,以及根据你的Host和Target选择相应的工具以及设定相应的通用编译选项:
build/core/config.mk summary of config
build/core/envsetup.mk generate dir config and so on
build/target/product product config
build/target/board board config
build/core/combo build flags config
这里解释下这里的board和product。borad主要是设计到硬件芯片的配置,比如是否提供硬件的某些功能,比如说GPU等等,或者芯片支持浮点运算等等。product是指针对当前的芯片配置定义你将要生产产品的个性配置,主要是指APK方面的配置,哪些APK会包含在哪个product中,哪些APK在当前product中是不提供的。
config.mk是一个总括性的东西,它里面定义了各种module编译所需要使用的HOST工具以及如何来编译各种模块,比如说 BUILT_PREBUILT就定义了如何来编译预编译模块。envsetup.mk主要会读取由envsetup.sh写入环境变量中的一些变量来配置编译过程中的输出目录,combo里面主要定义了各种Host和Target结合的编译器和编译选项。
2、 Module Compile
这类文件主要定义了如何来处理Module的Android.mk,以及采用何种方式来生成目标模块,这些模块生成规则都定义在config.mk里面,我们可以看看:
CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk
BUILD_HOST_STATIC_LIBRARY:= $(BUILD_SYSTEM)/host_static_library.mk
BUILD_HOST_SHARED_LIBRARY:= $(BUILD_SYSTEM)/host_shared_library.mk
BUILD_STATIC_LIBRARY:= $(BUILD_SYSTEM)/static_library.mk
BUILD_RAW_STATIC_LIBRARY := $(BUILD_SYSTEM)/raw_static_library.mk
BUILD_SHARED_LIBRARY:= $(BUILD_SYSTEM)/shared_library.mk
BUILD_EXECUTABLE:= $(BUILD_SYSTEM)/executable.mk
BUILD_RAW_EXECUTABLE:= $(BUILD_SYSTEM)/raw_executable.mk
BUILD_HOST_EXECUTABLE:= $(BUILD_SYSTEM)/host_executable.mk
BUILD_PACKAGE:= $(BUILD_SYSTEM)/package.mk
BUILD_HOST_PREBUILT:= $(BUILD_SYSTEM)/host_prebuilt.mk
BUILD_PREBUILT:= $(BUILD_SYSTEM)/prebuilt.mk
BUILD_MULTI_PREBUILT:= $(BUILD_SYSTEM)/multi_prebuilt.mk
BUILD_JAVA_LIBRARY:= $(BUILD_SYSTEM)/java_library.mk
BUILD_STATIC_JAVA_LIBRARY:= $(BUILD_SYSTEM)/static_java_library.mk
BUILD_HOST_JAVA_LIBRARY:= $(BUILD_SYSTEM)/host_java_library.mk
BUILD_DROIDDOC:= $(BUILD_SYSTEM)/droiddoc.mk
BUILD_COPY_HEADERS := $(BUILD_SYSTEM)/copy_headers.mk
BUILD_KEY_CHAR_MAP := $(BUILD_SYSTEM)/key_char_map.mk
除了CLEAR_VARS是清楚本地变量之外,其他所有的都对应了一种模块的生成规则,每一个本地模块最后都会include其中的一种来生成目标模块。大部分上面的.mk都会包含base_rules.mk,这是对模块进行处理的基础文件,建议要写本地模块的都去看看,看明白了为什么 Android.mk要这么写就会大致明白了。
3、Local Module
本地模块的Makefile文件就是我们在Android里面几乎上随处可见的Android.mk。Android进行编译的时候会通过下面的函数来遍历所有子目录中的Android.mk,一旦找到就不会再往层子目录继续寻找(所有你的模块定义的顶层Android.mk必须包含自己定义的子目录中的Android.mk)。
subdir_makefiles += /
$(shell build/tools/findleaves.sh --prune="./out" $(subdirs) Android.mk)
不同类型的本地模块具有不同的语法,但基本上是相通的,只有个别变量的不同,如何添加模块在前面的帖子已经说过了,大家可以参考。
Android通过LOCAL_MODULE_TAGS来决定哪些本地模块会不会编译进系统,通过PRODUCT和LOCAL_MODULE_TAGS来决定哪些应用包会编译进系统,如果用户不指定LOCAL_MODULE_TAGS,默认它的值是user。此外用户可以通过buildspec.mk来指定你需要编译进系统的模块。
用户也可以通过mm来编译指定模块,或者通过make clean-module_name来删除指定模块。
4、Package
这主要指的是build/core/Makefile这个文件,它定义了生成各种img的方式,包括ramdisk.img userdata.img system.img update.zip recover.img等。我们可以看看这些img都是如何生成的,对应着我们常用的几个make goals:
在实际的过程中,我们也可以自己编辑out目录下的生成文件,然后手工打包相应生成相应的img,最常用的是加入一些需要集成进的prebuilt file。
所有的Makefile都通过build/core/main.mk这个文件组织在一起,它定义了一个默认goals:droid,当我们在TOP目录下敲Make实际上就等同于我们执行make droid。当Make include所有的文件,完成对所有make我文件的解析以后就会寻找生成droid的规则,依次生成它的依赖,直到所有满足的模块被编译好,然后使用相应的工具打包成相应的img。
基本上Android building system就是以这样一种方式组织在一起的了,下面说一点闲散的东西。首先是如何来加快Android的编译过程,因为每次Android都要遍历所有的Android.mk,不管是编译整个工程还是只编译某个模块。所以可以将遍历的结果保存下来,下次直接从文件读就好了,但是这里容易出错,所以一定要确认是否正确包含了所有的.mk,当新加入文件的时候确认将原来保存的文件删除。下面是我写的加快编译的一个makefile,将下面的语句替换掉 main.mk中的相应部分就可以了:
FROM:
subdir_makefiles += /
$(shell build/tools/findleaves.sh --prune="./out" $(subdirs) Android.mk)
TO:
ifneq ($(ONE_SHOT_MAKEFILE),)
else
ifneq ($(CASH_MK),true)
subdir_makefiles += /
$(shell build/tools/findleaves.sh --prune="./out" $(subdirs) Android.mk)
else
subdir-makefiles-cash := $(shell cat build/subdir_mk_cash)
ifeq ($(subdir-makefiles-cash),)
$(warning No .mk cash ,create now !)
subdir_makefiles += /
$(shell build/tools/findleaves.sh --prune="./out" $(subdirs) Android.mk)
mk-to-file := $(shell echo $(subdir_makefiles) > build/subdir_mk_cash)
else
$(warning Using cash mk !)
subdir_makefiles := $(shell cat build/subdir_mk_cash)
endif
endif
endif
通过CASH_MK=true来打开快速编译的功能,因为没有对错误进行检测的操作,所以使用的时候一定要特别小心。
最后一个是扩展SDK API的问题,Android可以编译出自己的SDK,并扩展相应的SDK API,现在没有仔细的研究,只了解一个粗暴的方法就是在frameworks/base/core/java中添加相应的类。