编译基本命令:
$ source build/envsetup.sh $ lunch full-eng $ make -j8
第一步: 初始化编译环境变量,引入一些辅助的shell函数(launch, m,mm,mmm,cgrep,jgrep,croot,resgrep,godir,printconfig,add_launch_combo),并且将vender和device目录下的vendersetup.sh文件加载到当前终端
第二步:指定目标的编译设备及编译类型, full是android源码中已经定义好的一种产品,是为模拟器而设定,编译类型eng为工程机
编译类型说明:
名称 | 说明 |
---|---|
eng | 默认类型,该编译类型适用于开发阶段。 当选择这种类型时,编译结果将:
|
user | 该编译类型适合用于最终发布阶段。 当选择这种类型时,编译结果将:
|
userdebug | 该编译类型适合用于 debug 阶段。 该类型和 user 一样,除了:
|
Make文件说明:
由代码跟目录的makefile--> build/core/main.mk,一步一步推导开来
主要的make文件作用说明:
文件名 | 说明 |
---|---|
main.mk | 最主要的 Make 文件,该文件中首先将对编译环境进行检查,同时引入其他的 Make 文件。另外,该文件中还定义了几个最主要的 Make 目标,例如 droid,sdk,等(参见后文“Make 目标说明”)。 |
help.mk | 包含了名称为 help 的 Make 目标的定义,该目标将列出主要的 Make 目标及其说明。 |
pathmap.mk | 将许多头文件的路径通过名值对的方式定义为映射表,并提供 include-path-for 函数来获取。例如,通过$(call include-path-for, frameworks-native) 便可以获取到 framework 本地代码需要的头文件路径。 |
envsetup.mk | 配置 Build 系统需要的环境变量,例如:TARGET_PRODUCT,TARGET_BUILD_VARIANT,HOST_OS,HOST_ARCH 等。 当前编译的主机平台信息(例如操作系统,CPU 类型等信息)就是在这个文件中确定的。 另外,该文件中还指定了各种编译结果的输出路径。 |
combo/select.mk | 根据当前编译器的平台选择平台相关的 Make 文件。 |
dumpvar.mk | 在 Build 开始之前,显示此次 Build 的配置信息。 |
config.mk | 整个 Build 系统的配置文件,最重要的 Make 文件之一。该文件中主要包含以下内容:
|
definitions.mk | 最重要的 Make 文件之一,在其中定义了大量的函数。这些函数都是 Build 系统的其他文件将用到的。例如:my-dir,all-subdir-makefiles,find-subdir-files,sign-package 等,关于这些函数的说明请参见每个函数的代码注释。 |
distdir.mk | 针对 dist 目标的定义。dist 目标用来拷贝文件到指定路径。 |
dex_preopt.mk | 针对启动 jar 包的预先优化。 |
pdk_config.mk | 顾名思义,针对 pdk(Platform Developement Kit)的配置文件。 |
${ONE_SHOT_MAKEFILE} | ONE_SHOT_MAKEFILE 是一个变量,当使用“mm”编译某个目录下的模块时,此变量的值即为当前指定路径下的 Make 文件的路径。 |
${subdir_makefiles} | 各个模块的 Android.mk 文件的集合,这个集合是通过 Python 脚本扫描得到的。 |
post_clean.mk | 在前一次 Build 的基础上检查当前 Build 的配置,并执行必要清理工作。 |
legacy_prebuilts.mk | 该文件中只定义了 GRANDFATHERED_ALL_PREBUILT 变量。 |
Makefile | 被 main.mk 包含,该文件中的内容是辅助 main.mk 的一些额外内容。 |
其它主要make目标:
Make 目标 | 说明 |
---|---|
make clean | 执行清理,等同于:rm -rf out/。 |
make sdk | 编译出 Android 的 SDK。 |
make clean-sdk | 清理 SDK 的编译产物。 |
make update-api | 更新 API。在 framework API 改动之后,需要首先执行该命令来更新 API,公开的 API 记录在 frameworks/base/api 目录下。 |
make dist | 执行 Build,并将 MAKECMDGOALS 变量定义的输出文件拷贝到 /out/dist 目录。 |
make all | 编译所有内容,不管当前产品的定义中是否会包含。 |
make help | 帮助信息,显示主要的 make 目标。 |
make snod | 从已经编译出的包快速重建系统镜像。 |
make libandroid_runtime | 编译所有 JNI framework 内容。 |
makeframework | 编译所有 Java framework 内容。 |
makeservices | 编译系统服务和相关内容。 |
make <local_target> | 编译一个指定的模块,local_target 为模块的名称。 |
make clean-<local_target> | 清理一个指定模块的编译结果。 |
makedump-products | 显示所有产品的编译配置信息,例如:产品名,产品支持的地区语言,产品中会包含的模块等信息。 |
makePRODUCT-xxx-yyy | 编译某个指定的产品。 |
makebootimage | 生成 boot.img |
makerecoveryimage | 生成 recovery.img |
makeuserdataimage | 生成 userdata.img |
makecacheimage | 生成 cache.img |
添加新的模块:
在源码树中,一个模块的所有文件通常都位于同一个文件夹中。为了将当前模块添加到整个 Build 系统中,每个模块都需要一个专门的 Make 文件,该文件的名称为“Android.mk”。Build 系统会扫描名称为“Android.mk”的文件,并根据该文件中内容编译出相应的产物。
需要注意的是:在 Android Build 系统中,编译是以模块(而不是文件)作为单位的,每个模块都有一个唯一的名称,一个模块的依赖对象只能是另外一个模块,而不能是其他类型的对象。对于已经编译好的二进制库,如果要用来被当作是依赖对象,那么应当将这些已经编译好的库作为单独的模块。对于这些已经编译好的库使用 BUILD_PREBUILT 或 BUILD_MULTI_PREBUILT。例如:当编译某个 Java 库需要依赖一些 Jar 包时,并不能直接指定 Jar 包的路径作为依赖,而必须首先将这些 Jar 包定义为一个模块,然后在编译 Java 库的时候通过模块的名称来依赖这些 Jar 包。
下面,我们就来讲解 Android.mk 文件的编写:
Android.mk 文件通常以以下两行代码作为开头:
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS)
这两行代码的作用是:
- 设置当前模块的编译路径为当前文件夹路径。
- 清理(可能由其他模块设置过的)编译环境中用到的变量。
为了方便模块的编译,Build 系统设置了很多的编译环境变量。要编译一个模块,只要在编译之前根据需要设置这些变量然后执行编译即可。它们包括:
- LOCAL_SRC_FILES:当前模块包含的所有源代码文件。
- LOCAL_MODULE:当前模块的名称,这个名称应当是唯一的,模块间的依赖关系就是通过这个名称来引用的。
- LOCAL_C_INCLUDES:C 或 C++ 语言需要的头文件的路径。
- LOCAL_STATIC_LIBRARIES:当前模块在静态链接时需要的库的名称。
- LOCAL_SHARED_LIBRARIES:当前模块在运行时依赖的动态库的名称。
- LOCAL_CFLAGS:提供给 C/C++ 编译器的额外编译参数。
- LOCAL_JAVA_LIBRARIES:当前模块依赖的 Java 共享库。
- LOCAL_STATIC_JAVA_LIBRARIES:当前模块依赖的 Java 静态库。
- LOCAL_PACKAGE_NAME:当前 APK 应用的名称。
- LOCAL_CERTIFICATE:签署当前应用的证书名称。
- LOCAL_MODULE_TAGS:当前模块所包含的标签,一个模块可以包含多个标签。标签的值可能是 debug, eng, user,development 或者 optional。其中,optional 是默认标签。标签是提供给编译类型使用的。