Android

Android Build System Overview

这篇文章来自于Android源代码中的build/core/build-system.html文件。由于找不到build/core/build-system.html文件的在线版本,所以将build-system.html格式化之后放在这里供您查阅。


Status: Draft (as of May 18, 2006)
Contents

1 目标

重新设计构建系统的主要目标是 (1) 使依赖关系更可靠,从而在文件需要重新构建时能够正确构建,(2) 提高构建系统的性能,避免不必要的模块重建,并使当几乎没有工作需要完成时,顶层构建所需时间尽可能短。

2 原则、用例和策略

基于上述目标,我们将支持以下总体原则和用例。这不是一个详尽的列表。

2.1 多目标

需要能够为多个目标构建 Android 平台。这意味着:

  • 构建系统将支持为主机平台构建工具,包括用于构建过程的工具和开发工具如模拟器。

  • 构建系统需要能够在 Linux(肯定是 Goobuntu,可能还有 Grhat)、MacOS 以及某种程度上的 Windows 上构建工具。

  • 构建系统需要能够在 Linux 和短期内的 MacOS 上构建操作系统。注意,这是一个有意识的决策,不再在 Windows 上构建操作系统。我们将依赖于模拟器,而不尝试使用模拟器。这是一个需求变更,因为模拟器的前景更好。

2.2 非递归 Make

为实现目标,构建系统将重写为非递归使用 make。有关更多背景,请阅读 Recursive Make Considered Harmful。如果不想阅读 PDF,这里有 Google 翻译版本

2.3 快速编译-测试周期

在开发组件(例如 C++ 共享库)时,必须能够轻松地仅重新构建该组件,而不必等待超过几秒钟的依赖检查,也不必等待不需要的组件构建。

2.4 基于环境和配置文件的设置

为设置目标和其他选项,团队中的一些人喜欢在目录中有一个配置文件,以便不需要运行环境设置脚本,而其他人则希望运行环境设置脚本,以便可以在同一个树上在不同的终端中运行构建,或者在一个终端中来回切换。我们将支持两种方式。

2.5 目标文件目录 / make clean

目标文件和其他中间文件将生成在源树之外的目录中。目标是使 make clean 成为在树根目录中的 "rm -rf"。主要目标是简化搜索源树,并使 "make clean" 更可靠。

2.6 SDK

SDK 将是一个 tarball,允许非操作系统开发人员编写应用程序。应用程序实际上将首先构建 SDK,然后针对该 SDK 构建应用程序。希望这会 (1) 使我们编写应用程序更容易,因为我们不必频繁重建操作系统,并且可以使用标准的 Java 应用程序开发工具,(2) 允许我们实际使用 SDK,帮助确保其质量。Cedric 建议(我同意)从 SDK 构建的应用程序应该用 ant 构建。请继续关注,因为我们将弄清楚具体的工作方式。

2.7 依赖关系

依赖关系应全部自动化。除非涉及自定义工具(例如 webkit 有几个),共享和静态库、.c、.cpp、.h、.java、Java 库等的依赖关系应在 Android.mk 文件中无需干预即可正常工作。

2.8 通配符源文件

将不鼓励使用通配符源文件。在某些情况下可能有用。默认的 $(wildcard *) 将不起作用,因为当前目录设置为构建树的根目录。

2.9 单目录多目标

在给定的子目录中生成多个目标是可能的。例如,libutils 生成一个目标的共享库和一个主机的静态库。

2.10 模块的 Makefile 片段

Android.mk 是控制给定模块构建的 makefile 片段的标准名称。只有顶级目录应有一个名为 "Makefile" 的文件。

2.11 使用共享库

目前,模拟器未使用共享库构建。应修复这一点,现在是一个好时机。这意味着要使共享库在 Mac OS 上正常工作。

3 附加功能

这些功能会很好,但不是承诺,只是记录在这里。

3.1 同时构建

希望能够在同一个树中同时为不同组合进行两次构建,但这是一个高目标,不是要求。同一个树中的两次构建,不同时进行必须有效。(更新:我们看来会实现同时两次构建)

3.2 删除头文件(或其他依赖)

如果删除 ".d" 文件中引用的头文件,可能会出现问题。解决此问题的简单方法是 "make clean"。应该有更好的处理方式。(来自 fadden)

一种解决方法是引入对目录的依赖。问题在于这可能会产生额外的依赖并减慢构建速度。这是一个权衡。

3.3 多次构建

在已知平台集合上执行构建的一般方法。这将使在测试更改时执行多平台构建变得容易,并允许大规模 "make clean"。目前需要在每次构建前更新 buildspec.mk 或环境变量。(来自 fadden)

3.4 售后市场的语言和运营商

我们最终需要添加对在 SDK 中创建语言和运营商定制的支持,但这不会立即解决。

4 使用方法

您已经阅读(或快速浏览)了这个构建系统的所有动机,现在想知道如何使用它。这里是相关信息。

4.1 第一次构建

构建文档描述了如何进行构建。

4.2 build/envsetup.sh函数

如果您将文件build/envsetup.sh导入到bash环境中(使用. build/envsetup.sh),您将获得一些有用的shell函数:

  • printconfig – 打印当前由lunch和choosecombo命令设置的配置。

  • m – 从树的顶层运行make。这很有用,因为您可以从子目录中运行make。如果设置了TOP环境变量,它会使用该变量。如果没有设置,它会从当前目录向上查找,尝试找到树的顶层。

  • crootcd到树的顶层。

  • sgrep – 在当前目录下的所有.c、.cpp、.h、.java和.xml文件中查找提供的正则表达式。

4.3 构建风格/类型

为特定产品构建时,通常希望对最终发布构建进行一些微小的变更。以下是当前定义的“风格”或“类型”(我们需要为这些确定一个真实的名称)。

风格/类型 描述
eng 这是默认风格。一个简单的“make”与“make eng”相同。droideng的别名。安装标记为:engdebuguser和/或development的模块。安装没有指定标签的非APK模块。根据产品定义文件安装APKs,此外还有标记的APKs。ro.secure=0ro.debuggable=1ro.kernel.android.checkjni=1。默认启用adb
user make user” 这是预期的最终发布版本。安装标记为user的模块。安装没有指定标签的非APK模块。根据产品定义文件安装APKs;忽略APK模块的标签。ro.adb.secure=1ro.secure=1ro.debuggable=0。默认禁用adb
userdebug make userdebug” 与user相同,除非:还安装标记为debug的模块。ro.debuggable=1。默认启用adb

如果先构建一个风格,然后再构建另一个风格,您应在两次构建之间运行“make installclean”以确保不会拾取由上一个风格安装的文件。运行“make clean”也可以,但耗时更长。

4.4 更多伪目标

有时您只想构建一个东西。以下伪目标是为了您的方便:

  • droidmake droid是正常构建。此目标存在是因为默认目标必须有一个名称。

  • allmake all构建make droid构建的所有内容,以及LOCAL_MODULE_TAGS不包括“droid”标签的所有内容。构建服务器运行此命令以确保树中所有带有Android.mk的内容都可以构建。

  • clean-$(LOCAL_MODULE)clean-$(LOCAL_PACKAGE_NAME) – 允许您有选择地清理一个目标。例如,您可以键入make clean-libutils,它将删除libutils.so和所有中间文件,或键入make clean-Home,它将仅清理Home应用程序。

  • cleanmake clean删除此配置的所有输出和中间文件。这与rm -rf out/<configuration>/相同。

  • clobbermake clobber删除所有配置的所有输出和中间文件。这与rm -rf out/相同。

  • datacleanmake dataclean删除当前组合目录内数据目录的内容。这在模拟器和仿真器上特别有用,因为持久数据在构建之间保持存在。

  • LOCAL_MODULE – 您在Android.mk中指定的任何LOCAL_MODULE都会变成一个伪目标。例如,make runtime可能是make out/linux-x86-debug/system/bin/runtime的简写(这会有效),make libkjs可能是make out/linux-x86-debug/system/lib/libkjs.so的简写(这也会有效)。

  • targetsmake targets会打印所有可以构建的LOCAL_MODULE名称的列表。

4.5 如何向构建中添加另一个组件 – Android.mk模板

您有一个新库、一个新应用程序或一个新可执行文件。对于每种常见类型的模块,在模板目录中都有相应的文件。通常,只需复制其中一个并填写自己的值即可。某些较为特殊的值未包含在模板中,而是仅在此处记录,使用自定义工具生成文件的文档也是如此。

大多数情况下,您只需寻找模板中的TODO注释并按其指示进行操作。完成后请记得删除TODO注释以保持文件整洁。模板中只有最少的文档,因为它们将被复制,当这些文档过时时,副本不会被更新。所以请继续阅读…

4.5.1 应用程序

使用templates/apps文件。

此模板相当容易理解。有关详细信息,请参阅下面的变量。

4.5.2 Java库

使用templates/java_library文件。

这里有趣的是LOCAL_MODULE的值,它将成为jar文件的名称。(实际上,目前我们还没有制作jar文件,只是.class文件的目录,但该目录的名称根据您在LOCAL_MODULE中输入的内容命名)。此名称将出现在依赖您的java库的模块的LOCAL_JAVA_LIBRARIES变量中。

4.5.3 C/C++可执行文件

使用templates/executable文件或templates/executable_host文件。

此模板有几个您通常不需要的额外选项。请删除不需要的选项,并移除TODO注释。这样可以使其余部分更易于阅读,如果以后再次需要,可以随时参考模板。

默认情况下,在目标上这些文件构建到/system/bin中,在主机上构建到/host/bin中。这些可以通过设置LOCAL_MODULE_PATHLOCAL_MODULE_RELATIVE_PATH来覆盖。有关更多信息,请参阅将目标放置在其他位置

4.5.4 共享库

使用templates/shared_library文件或templates/shared_library_host文件。

请记住,在目标上,我们使用共享库,在主机上,我们使用静态库,因为可执行文件的大小不是一个大问题,这简化了SDK的分发。

4.5.5 静态库

使用templates/static_library文件或templates/static_library_host文件。

请记住,在目标上,我们使用共享库,在主机上,我们使用静态库,因为可执行文件的大小不是一个大问题,这简化了SDK的分发。

4.5.6 使用自定义工具

如果您有一个工具为您生成源文件,可以让构建系统正确处理依赖关系。以下是几个示例。$@是make内置变量,表示“当前目标”。红色部分是需要您更改的部分。

您需要在声明LOCAL_PATHLOCAL_MODULE之后放置这些内容,因为$(local-generated-sources-dir)$(local-host-generated-sources-dir)宏使用这些变量来确定文件的放置位置。

4.5.6.1 示例1

这里有一个生成的文件,名为chartables.c,不依赖任何东西。它由$(HOST_OUT_EXECUTABLES)/dftables构建。请注意倒数第二行创建了对该工具的依赖关系。

intermediates:= $(local-generated-sources-dir)  
GEN := $(intermediates)/chartables.c  
$(GEN): PRIVATE_CUSTOM_TOOL = $(HOST_OUT_EXECUTABLES)/dftables $@  
$(GEN): $(HOST_OUT_EXECUTABLES)/dftables  
    $(transform-generated-source)  
LOCAL_GENERATED_SOURCES += $(GEN)
4.5.6.2 示例2

这里作为一个假设示例,我们使用cat将文件转换。假装它做了些有用的事情。请注意我们使用名为PRIVATE_INPUT_FILE的目标特定变量来存储输入文件的名称。

intermediates:= $(local-generated-sources-dir)  
GEN := $(intermediates)/file.c  
$(GEN): PRIVATE_INPUT_FILE := $(LOCAL_PATH)/input.file  
$(GEN): PRIVATE_CUSTOM_TOOL = cat $(PRIVATE_INPUT_FILE) &gt; $@  
$(GEN): $(LOCAL_PATH)/input.file  
    $(transform-generated-source)  
LOCAL_GENERATED_SOURCES += $(GEN)
4.5.6.3 示例3

如果您有多个名称相似的文件,并且使用相同的工具,可以将它们组合在一起。(这里.lut.h文件是生成的,.cpp文件是输入文件)

intermediates:= $(local-generated-sources-dir)  
GEN := $(addprefix $(intermediates)/kjs/, \  
            array_object.lut.h \  
            bool_object.lut.h \  
        )  
$(GEN): PRIVATE_CUSTOM_TOOL = perl libs/WebKitLib/WebKit/JavaScriptCore/kjs/create_hash_table $&lt; -i &gt; $@  
$(GEN): $(intermediates)/%.lut.h : $(LOCAL_PATH)/%.cpp  
    $(transform-generated-source)  
LOCAL_GENERATED_SOURCES += $(GEN)
0 0 投票数
文章评分
订阅评论
提醒
guest

0 评论
最旧
最新 最多投票
内联反馈
查看所有评论
0
希望看到您的想法,请您发表评论x