了解 64 位 build

构建系统支持在一个 build 中为两种目标 CPU 架构(64 位和 32 位)构建二进制文件。这称为多库构建过程。

对于原生静态库和共享库,构建系统设置了为两种架构构建二进制文件的规则。产品配置 (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 中查看示例。

如果您希望构建系统默认构建 32 位可执行文件和应用,请设置以下变量:

TARGET_PREFER_32_BIT := true

您可以在 Android.mk 中使用针对特定模块的变量来替换此设置。

在多库构建过程中,PRODUCT_PACKAGES 中的模块名称同时涵盖 32 位和 64 位二进制文件,只要它们是由构建系统定义的即可。对于通过依赖关系提取而来的库,只有在另一个 32 位库或可执行文件要求使用时,系统才会安装 32 位库。64 位库也遵循同样的规则。

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

Android.mk 中的模块定义

您可以使用 LOCAL_MULTILIB 变量将 build 配置为适用于 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

在多库构建过程中,改为使用 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
    指定安装路径。

生成的源代码

在多库构建过程中,在 $(local-intermediates-dir) 中生成源代码文件(或通过明确的变量在 $(intermediates-dir-for) 中生成)这种方法会变得不再可靠。这是因为 32 位和 64 位 build 都需要中间生成的源代码,而 $(local-intermediates-dir) 仅指向两个中间目录中的一个。

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

如果源代码文件在此专用目录中生成并由 LOCAL_GENERATED_SOURCES 调用,那么就意味着它在多库构建过程中是同时为 32 位和 64 位架构构建的。

预构建

在多库构建过程中,您无法使用 TARGET_ARCH(或加上 TARGET_2ND_ARCH)来告知构建系统,预构建的二进制文件是以哪种架构为目标。请改为使用 LOCAL_ 变量 LOCAL_MODULE_TARGET_ARCHLOCAL_MODULE_UNSUPPORTED_TARGET_ARCH

利用这些变量,即使构建系统正在进行 64 位多库构建,也可以选择对应的 32 位预构建二进制文件。

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

生成 ODEX 文件

对于 64 位设备,我们会默认为启动映像及任何 Java 库同时生成 32 位和 64 位 ODEX 文件。对于 APK,我们默认仅为主要的 64 位架构生成 ODEX 文件。如果某个应用将同时在 32 位和 64 位进程中启动,请使用 LOCAL_MULTILIB := both 确保同时生成 32 位和 64 位 ODEX 文件。如果应用包含任何 32 位或 64 位 JNI 库,该标记也会告知构建系统添加代码库。