了解 64 位构建

构建系统支持在同一构建中为两个目标 CPU 架构(64 位和 32 位)构建二进制文件。这称为multilib 构建

对于本机静态库和共享库,构建系统会设置规则来为这两种架构构建二进制文件。产品配置 ( PRODUCT_PACKAGES ) 与依赖关系图一起确定构建和安装到系统映像的二进制文件。

对于可执行文件和应用程序,构建系统默认仅构建 64 位版本,但您可以使用全局BoardConfig.mk变量或模块范围变量覆盖此设置。

产品配置

BoardConfig.mk包含以下变量来配置第二个 CPU 架构和 ABI:

  • TARGET_2ND_ARCH
  • TARGET_2ND_ARCH_VARIANT
  • TARGET_2ND_CPU_VARIANT
  • TARGET_2ND_CPU_ABI
  • TARGET_2ND_CPU_ABI2

您可以在build/target/board/generic_arm64/BoardConfig.mk中看到一个示例。

在 multilib 构建中, PRODUCT_PACKAGES中的模块名称涵盖 32 位和 64 位二进制文​​件,只要它们是由构建系统定义的。对于通过依赖项引入的库,仅当另一个 32 位库或可执行文件需要时才安装 32 位库。 64 位库也是如此。

但是, make命令行上的模块名称仅涵盖 64 位版本。例如,在运行lunch aosp_arm64-eng后, make libc仅构建 64 位 libc。要构建 32 位 libc,您需要运行make libc_32

Android.mk 中的模块定义

您可以使用LOCAL_MULTILIB变量为 32 位/64 位配置您的构建并覆盖全局TARGET_PREFER_32_BIT变量。

LOCAL_MULTILIB设置为以下之一:

  • "both"构建 32 位和 64 位。
  • "32"仅构建 32 位。
  • "64"仅构建 64 位。
  • "first"仅针对第一个架构(32 位设备中的 32 位和 64 位设备中的 64 位)构建。
  • ""是默认值。构建系统根据模块类和其他LOCAL_变量(例如LOCAL_MODULE_TARGET_ARCHLOCAL_32_BIT_ONLY )决定构建哪个架构。

如果要为特定架构构建模块,请使用以下变量:

  • LOCAL_MODULE_TARGET_ARCH
    将此变量设置为架构列表,例如arm x86 arm64 。如果正在构建的体系结构在该列表中,则当前模块包含在构建系统中。
  • LOCAL_MODULE_UNSUPPORTED_TARGET_ARCH
    此变量与LOCAL_MODULE_TARGET_ARCH相反。如果正在构建的体系结构不在该列表中,则当前模块包含在构建系统中。

这两个变量有一些小的变体:

  • LOCAL_MODULE_TARGET_ARCH_WARN
  • LOCAL_MODULE_UNSUPPORTED_TARGET_ARCH_WARN

如果由于列出的体系结构而跳过当前模块,构建系统会发出警告。

要为特定体系结构设置构建标志,请使用体系结构特定的LOCAL_变量。特定于体系结构的LOCAL_变量是具有体系结构后缀的普通LOCAL_变量,例如:

  • LOCAL_SRC_FILES_arm, LOCAL_SRC_FILES_x86,
  • LOCAL_CFLAGS_arm, LOCAL_CFLAGS_arm64,
  • LOCAL_LDFLAGS_arm, LOCAL_LDFLAGS_arm64,

仅当当前正在为该架构构建二进制文件时才应用这些变量。

有时,根据二进制文件当前是为 32 位还是 64 位构建的,设置标志会更容易。使用带有_32_64后缀的LOCAL_变量,例如:

  • LOCAL_SRC_FILES_32, LOCAL_SRC_FILES_64,
  • LOCAL_CFLAGS_32, LOCAL_CFLAGS_64,
  • LOCAL_LDFLAGS_32, LOCAL_LDFLAGS_64,

安装路径

以前,您可以使用LOCAL_MODULE_PATH将库安装到默认位置以外的位置。例如, LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw

在 multilib 构建中,请改用LOCAL_MODULE_RELATIVE_PATH

LOCAL_MODULE_RELATIVE_PATH := hw

使用这种格式,64 位和 32 位库都安装在正确的位置。

如果您将可执行文件构建为 32 位和 64 位,请使用以下变量之一来区分安装路径:

  • LOCAL_MODULE_STEM_32, LOCAL_MODULE_STEM_64
    指定安装的文件名。
  • LOCAL_MODULE_PATH_32, LOCAL_MODULE_PATH_64
    指定安装路径。

生成的源

在 multilib 构建中,如果您将源文件生成到$(local-intermediates-dir) (或带有显式变量$(intermediates-dir-for) ),它就不能可靠地工作。这是因为 32 位和 64 位构建都需要中间生成的源,但$(local-intermediates-dir)仅指向两个中间目录之一。

构建系统提供了一个专用的、对多库友好的中间目录,用于生成源代码。您可以调用$(local-generated-sources-dir)$(generated-sources-dir-for)来获取目录的路径。它们的用途类似于$(local-intermediates-dir)$(intermediates-dir-for)

如果在此专用目录中生成源文件并由LOCAL_GENERATED_SOURCES拾取,则它在 multilib 构建中为 32 位和 64 位构建。

预制件

在 multilib 构建中,您不能使用TARGET_ARCH (或与TARGET_2ND_ARCH一起使用)来告诉构建系统预构建二进制目标的体系结构。相反,使用LOCAL_变量LOCAL_MODULE_TARGET_ARCHLOCAL_MODULE_UNSUPPORTED_TARGET_ARCH

使用这些变量,构建系统可以选择相应的 32 位预构建二进制文件,即使它正在处理 64 位 multilib 构建。

如果您想使用所选架构来计算预构建二进制文件的源路径,请调用$(get-prebuilt-src-arch)

ODEX 文件生成

对于 64 位设备,默认情况下,我们会为启动映像和任何 Java 库生成 32 位和 64 位 ODEX 文件。对于 APK,默认情况下我们只为主要的 64 位架构生成 ODEX。如果应用程序将在 32 位和 64 位进程中启动,请使用LOCAL_MULTILIB := both以确保生成 32 位和 64 位 ODEX 文件。如果应用程序有任何 32 位或 64 位 JNI 库,该标志也会告诉构建系统包含它们。