Android构建系统

在如下位置描述了Android构建系统:<https://source.android.com/setup/build>
你可使用build/envsetup.sh设置一个"便利环境"来处理Android源代码。在当前shell环境中执行source build/envsetup.sh后,你能够输入hmm做为已定义函数的列表,这些函数有助于与源进行交互。html

概述

构建系统使用一些预设的环境变量和一系列"make"文件来构建Android系统并准备将其部署到平台上。java

子项目的Android构建文件叫作Android.bp和Android.mk。linux

整个存储库的源树顶部只有一个名为"Makefile"的官方文件。你设置了一些环境变量,而后键入"make"或仅键入m来构建内容。你能够在make命令行(其余目标)中添加一些选项以打开详细输出或执行其余操做。android

构建输出放置在out/hostout/target中。out/host下的东西是为你的主机平台(台式机)编译的东西。最终在out/target/product/<platform-name>下的内容会以特定方式被放到目标设备(或模拟器)。shell

目录out/target/product/<platform-name>/obj用于暂存"object"文件,这些文件是用于构建最终程序的中间二进制映像。实际落在目标文件系统中的内容存储在out/target/product/<platform-name>下的root,system和data目录中。一般,这些文件捆绑成名为system.img,ramdisk.img和userdata.img的映像文件。缓存

这与大多数Android设备上使用的文件系统分区相匹配。app

一些细节

使用什么工具

在构建期间,你将使用soong,ninja和'make'控制构建步骤。主机工具链(编译器,连接器和其余工具)和库将用于构建将在主机上运行的程序和工具。使用不一样的工具链来编译将在目标(嵌入式板,设备或模拟器)上运行的C和C++代码。这一般是在X86平台上运行的"交叉"工具链,但会为其余平台(最多见的是ARM)生成代码。内核被编译为独立的二进制文件(它不使用程序加载器或连接到任何外部库)。其余项目,例如本机程序(例如init或工具箱),守护程序或库,将连接到仿生库或其余系统库。框架

你将使用Java编译器和大量与Java相关的工具来构建大多数应用程序框架,系统服务和Android应用程序自己。最后,使用工具打包应用程序和资源文件,并建立能够安装在设备上或与模拟器一块儿使用的文件系统映像。函数

告诉系统Java工具链在哪里

在构建任何东西以前,你必须告诉Android构建系统Java SDK的位置。(安装Java SDK是构建的先决条件)。
经过设置JAVA_HOME环境变量来执行此操做。工具

指定要构建的内容

为了决定要构建什么以及如何构建,构建系统要求设置一些变量。能够从同一源代码树构建具备不一样软件包和选项的不一样产品。能够经过带有"make"变量声明的文件来设置控制此变量的变量,也能够在环境中指定该变量。

设备供应商能够建立定义文件,以描述特定板或特定产品要包含的内容。定义文件称为:buildspec.mk,它位于顶级源目录中。你能够手动编辑此选项以对选择进行硬编码。

若是你有一个buildspec.mk文件,它会设置构建所需的全部make变量,而你没必要弄乱选项。

指定选项的另外一种方法是设置环境变量。构建系统具备一种至关华丽的方法来为你管理这些选项。

要设置你的构建环境,你须要在build/envsetup.sh中加载变量和函数。经过将文件source到你的shell环境中来执行此操做,以下所示:

. build/envsetup.sh

你能够在此时输入"help"(或"hmm")以查看一些实用程序功能,这些功能可使你更轻松地使用源代码。

要选择要构建的一组东西以及要构建的项目,请使用"choosecombo"功能或"lunch"功能。"choosecombo"将一步一步地引导你完成必须选择的不一样项目,而"lunch"则容许你选择一些预设组合。

必须为构建定义的项目是:

• 产品("generic"或某些特定的芯片或平台名称)
• 构建变体("user","userdebug"或"eng")
• 是否在模拟器上运行("true"或"false")
• 构建类型("发布"或"调试")

这些不一样的构建变体的说明位于http://source.android.com/porting/build_system.html#androidBuildVariants

在这篇博客文章中,从用户角度很好地描述了构建过程:http://blog.codepainters.com/2009/12/18/first-android-platform-build/

实际构建系统

设置完毕后,实际上就可使用"make"命令来构建系统。

要构建整个内容,请在顶层目录中运行"make"。若是要构建全部内容(例如,第一次进行构建),则构建将花费很长时间。

构建技巧

查看用于构建软件的实际命令

在"make"行上使用"showcommands"目标:

make -j4 showcommands

能够将其与另外一个make目标结合使用,以查看该构建的命令。也就是说,"showcommands"自己不是目标,而只是指定构建的修饰符。

在上面的示例中,-j4与showcommands选项无关,而且用于执行4个并行运行的make会话。

制定目标

这是可用于构建系统不一样部分的不一样make目标的列表:

make sdk - 构建属于SDK的工具(adb,fastboot等)
make snod - 从当前软件二进制文件构建系统映像
make services
make runtime
make droid - make droid是正常的构建。
make all - 构建全部内容,不管是否包含在产品定义中
make clean - 删除全部构建的文件(准备进行新的构建)。与rm -rf out/<configuration>/相同
make modules - 显示能够构建的子模块的列表(全部LOCAL_MODULE定义的列表)
make <local_module> - 构建一个特定的模块(请注意,这与目录名称不一样。它是Android.mk文件中的LOCAL_MODULE定义)
make clean <local_module> - 清理特定模块
make bootimage TARGET_PREBUILT_KERNEL=/path/to/bzImage - 使用自定义bzImage建立新的启动映像

辅助宏和函数

当你获取envsetup.sh时,会安装一些辅助宏和函数。它们记录在envesetup.sh的顶部,可是这里是其中一些信息:

hmm - 列出帮助内容
lunch <product_name>-<build_variant> - 加载产品和构建变体配置(驱动程序文件,设备特定的配置等)。
tapas [<App1> <App2> ...] [arm | x86 | mips | armv5 | arm64 | x86_64 | mips64] [eng | userdebug | user] - 该命令用于构建未捆绑的应用程序。若是你不提供构建版本,则默认为eng。
provision - 烧录具备全部必需分区的设备。选项将传递给fastboot。

构建宏和函数

croot - 将目录更改成树的顶部
m - 从树的顶部执行"make"(即便当前目录位于其余位置)
mm - 构建当前目录中的全部模块
mmm <dir1> ... - 构建提供的目录中的全部模块,但不构建其依赖项。要限制正在构建的模块,请使用如下语法:mmm dir /:target1,target2
mma - 构建当前目录中的全部模块及其依赖项。
mmma <dir1> ... - 构建提供的目录中的全部模块及其依赖项。

Grep宏和函数

cgrep <PATTERN> 在全部本地C/C++文件上显示。
ggrep <PATTERN> 在全部本地Gradle文件上显示。
jgrep <PATTERN> 在全部本地Java文件上使用。
resgrep <PATTERN> 在全部本地res/*。xml文件上进行锁定。
mangrep <PATTERN> 在全部本地AndroidManifest.xml文件上进行扫描。
mgrep <PATTERN> 在全部本地Makefile文件上进行抓紧。
sepgrep <PATTERN> 在全部本地Sepolicy文件上进行锁定。
sgrep <PATTERN> 在全部本地源文件上进行抓紧。
godir <文件名> 转到包含文件的目录

加快构建

你能够在make中使用'-j'选项,以同时启动多个make执行线程。

根据个人经验,你应该指定比计算机上具备处理器多2个线程。若是你有2个处理器,请使用'make -j4';若是它们是超线程的(意味着你有4个虚拟处理器),请尝试'make -j6。

你还能够指定使用"ccache"编译器缓存,这将在你首次构建内容后加快处理速度。为此,请在你的shell命令行中指定"export USE_CCACHE = 1"。(请注意,ccache包含在存储库的预构建部分中,没必要单独安装在主机上。)

对于最新的Android版本,没有预建的ccache,而且须要根据此commit,使用CCACHE_EXEC将路径设置为本地二进制文件。

仅构建单个程序或模块

若是使用build/envsetup.sh,则可使用某些已定义的函数来仅构建树的一部分。使用"mm"或"mmm"命令执行此操做。

"mm"命令在当前目录(和子目录,我相信)中进行填充。使用"mmm"命令,你能够指定目录或目录列表,而后将其构建。
要安装你的更改,请从树的顶部开始"make snod"。"make snod"从当前的二进制文件构建新的系统映像。

设置模块特定的构建参数

Android系统中的某些代码能够按照其构建方式进行自定义(与构建变体以及发行版和调试选项分开)。你能够设置变量来控制各个构建选项,方法是在环境中进行设置,或者将其直接传递给"make"(或称为"make"的"m ..."函数)。

例如,能够经过设置INIT_BOOTCHART变量来构建支持bootchart日志记录的'init'程序。(有关为何你可能要执行此操做,请参见在Android上使用Bootchart。)

你可使用如下任一方法来完成:

touch system/init/init.c
export INIT_BOOTCHART=true
make

或者

touch system/init/init.c
m INIT_BOOTCHART=true

Makefile技巧

这些是你能够在本身的Android.mk文件中使用的东西的一些提示。

创建助手功能

在文件build/core/definitions.mk中定义了不少构建帮助器函数

尝试列出详尽的清单。grep define build/core/definitions.mk

经过如下方式调用它们:或不带参数:$(call <FUNCTION>, <PARAM-1>, <PARAM-2>)$(call <FUNCTION>)

如下是一些可能有趣的功能:

print-vars - 打印全部Makefile变量,以进行调试(而不是它们的值)。
emit-line - 在构建期间将线输出到文件
dump-words-to-file - 将单词列表输出到文件
copy-one-file - 将文件从一个地方复制到另外一个地方(目标是否在目的地?)
all-subdir-makefiles - 从当前目录开始递归调用全部文件(用法:)。Android.mkinclude $(调用all-subdir-makefiles)

构建变量

$(ANDROID_BUILD_TOP) - AOSP文件系统根文件夹
$(LOCAL_PATH)- 一般为当前目录。由开发人员/用户在每一个Android.mk文件中设置。
它会在文件树下的其余文件中被覆盖(例如,使用时)。Android.mk include $(call all-subdir-makefiles)

解决方法:

SAVED_LOCAL_PATH := $(call my-dir)
 include $(call all-subdir-makefiles)
 LOCAL_PATH:= $(SAVED_LOCAL_PATH)

将文件直接添加到输出区域

你可使用add-prebuilt-files函数将文件直接复制到输出区域,而无需构建任何内容。

prebuilt/android-arm/gdbserver/Android.mk中提取的如下行将文件列表复制到输出区域的EXECUTABLES目录中:

$(call add-prebuilt-files, EXECUTABLES, $(prebuilt_files))

添加新程序以进行构建

将新程序添加到Android源代码树的步骤

• 在"外部"下创建目录
• 例如ANDROID/external/myprogram
• 建立你的C/cpp文件。
• 建立Android.mk做为external/ping/Android.mk的克隆
• 更更名称ping.c和ping以匹配你的C/cpp文件和程序名称
• 在external/zlib以后将ANDROID/build/core/main.mk中的目录名称添加为external/myprogram(至少从Android 7.1起再也不须要)
• 从源代码树的根开始
• 你的文件将显示在构建输出区域和系统映像中。
• 若是要将文件单独复制到目标(而不执行整个安装),则能够从构建输出区域的out/target/product/...下复制文件。

有关更多详细信息,请参见http://www.aton.com/android-native-development-using-the-android-open-source-project/

构建内核

内核是普通Android构建系统的"外部"(实际上,默认状况下,Android Open Source Project中不包括该内核)。可是,AOSP中有一些用于构建内核的工具。若是要构建内核,请今后页面开始:http : //source.android.com/source/building-kernels.html

若是你正在为模拟器构建内核,则可能还须要查看:http : //stackoverflow.com/questions/1809774/android-kernel-compile-and-test-with-android-emulator

并且,Ron M写道(在2012年5月21日在android-kernel邮件列表中):

这篇文章很老-但就AOSP而言,什么都没有改变,因此若是有人对QEMU感兴趣并遇到此问题,请执行如下操做:
实际上,为AOSP提供的QEMU目标构建内核是一种不错的,更短的方法:

  1. cd到你的内核源目录(仅金鱼2.6.29在模拟器中可用)
  2. $ {ANDROID_BUILD_TOP} /external/qemu/distrib/build-kernel.sh -j = 64 --arch = x86 --out = $ YourOutDir
  3. emulator -kernel ${YourOutDir}/kernel-qemu # run emulator:

步骤#2 调用toolbox.sh包装程序脚本,该脚本可在SSE禁用gcc警告的状况下工做-在GCC <4.5时发生(如AOSP预先构建的X86工具链中同样)。

若是它是X86,该脚本会添加"-mfpmath = 387 -fno-pic",从而消除了上面看到的编译错误。

为了更好地控制构建过程,可使用"toolbox.sh"包装器并设置一些其余内容,而无需修改脚本文件。

下面是构建相同模拟器的示例:

# Set arch
export ARCH=x86
# Have make refer to the QEMU wrapper script for building android over x86 
(eliminates the errors listed above)
export 
CROSS_COMPILE=${ANDROID_BUILD_TOP}/external/qemu/distrib/kernel-toolchain/android-kernel-toolchain-
# Put your cross compiler here. I am using the AOSP prebuilt one in this example
export 
REAL_CROSS_COMPILE=${ANDROID_BUILD_TOP}/prebuilt/linux-x86/toolchain/i686-android-linux-4.4.3/bin/i686-android-linux-
# Configure your kernel - here I am taking the default goldfish_defconfig
make goldfish_defconfig
# build
make -j64
# Run emulator:
emulator -kernel arch/x86/boot/bzImage -show-kernel

这适用于2.6.29 goldfish 分支。

译自https://elinux.org/Android_Build_System