Android.mk

本页介绍了 ndk-build 所使用的 Android.mk 构建文件的语法。

概览

Android.mk 文件位于您项目的 jni/ 目录下的子目录中,用于向构建系统描述您的源文件和共享库。它实际上是一个很小的 GNU Makefile 片段,构建系统会对其解析一次或多次。Android.mk 文件对于定义 Application.mk、构建系统和环境变量未定义的项目范围设置很有用。它还可以为特定的模块覆盖项目范围的设置。

Android.mk 文件的语法允许您将源文件分组到模块中。模块可以是静态库、共享库或独立的执行文件。您可以在每个 Android.mk 文件中定义一个或多个模块,并且可以在多个模块中使用相同的源文件。构建系统仅将共享库放入您的应用软件包中。此外,静态库可以生成共享库。

除了打包库外,构建系统还会为您处理各种其他细节。例如,您无需在 Android.mk 文件中列出头文件或生成文件之间的显式依赖项。NDK 构建系统会自动为您计算这些关系。因此,您应该能够从未来 NDK 版本中新的工具链/平台支持中受益,而无需修改您的 Android.mk 文件。

此文件的语法与完整的 Android 开源项目中分发的 Android.mk 文件所使用的语法非常接近。虽然使用它们的构建系统实现不同,但它们的相似性是故意的设计决策,旨在让应用开发者更容易重用外部库的源代码。

基础

在详细探讨语法之前,先了解 Android.mk 文件包含哪些基本内容会很有用。本节使用 Hello-JNI 示例中的 Android.mk 文件来达到此目的,解释了文件中每一行的作用。

一个 Android.mk 文件必须首先定义 LOCAL_PATH 变量

LOCAL_PATH := $(call my-dir)

此变量表示源文件在开发树中的位置。此处,构建系统提供的宏函数 my-dir 返回当前目录(包含 Android.mk 文件本身的目录)的路径。

下一行声明 CLEAR_VARS 变量,其值由构建系统提供。

include $(CLEAR_VARS)

CLEAR_VARS 变量指向一个特殊的 GNU Makefile,该文件会为您清除许多 LOCAL_XXX 变量,例如 LOCAL_MODULELOCAL_SRC_FILESLOCAL_STATIC_LIBRARIES。请注意,它不会清除 LOCAL_PATH。此变量必须保留其值,因为系统会在一个全局变量的 GNU Make 执行上下文中解析所有构建控制文件。在描述每个模块之前,您必须(重新)声明此变量。

接下来,LOCAL_MODULE 变量存储您希望构建的模块的名称。在您的应用中每个模块使用此变量一次。

LOCAL_MODULE := hello-jni

每个模块名称必须唯一且不包含任何空格。构建系统生成最终共享库文件时,会自动为您分配给 LOCAL_MODULE 的名称添加适当的前缀和后缀。例如,上面显示的示例会生成一个名为 libhello-jni.so 的库。

下一行枚举源文件,用空格分隔多个文件

LOCAL_SRC_FILES := hello-jni.c

LOCAL_SRC_FILES 变量必须包含要构建到模块中的 C 和/或 C++ 源文件列表。

最后一行帮助系统将所有内容联系在一起

include $(BUILD_SHARED_LIBRARY)

BUILD_SHARED_LIBRARY 变量指向一个 GNU Makefile 脚本,该脚本收集了自最近一次 include 以来您在 LOCAL_XXX 变量中定义的所有信息。此脚本确定要构建的内容以及如何构建。

samples 目录中有更复杂的示例,其中包含注释的 Android.mk 文件,您可以查看。此外,示例:原生 activity 提供了对该示例的 Android.mk 文件的详细解释。最后,变量和宏提供了有关本节变量的进一步信息。

变量和宏

构建系统为 Android.mk 文件提供了许多可能的变量。这些变量中的许多都具有预设值。其他则由您分配。

除了这些变量之外,您还可以定义自己的任意变量。如果您这样做,请记住 NDK 构建系统保留以下变量名称

  • LOCAL_ 开头的名称,例如 LOCAL_MODULE
  • PRIVATE_NDK_APP 开头的名称。构建系统在内部使用这些名称。
  • 小写名称,例如 my-dir。构建系统也在内部使用这些名称。

如果您需要在 Android.mk 文件中定义自己的便利变量,我们建议在名称前加上 MY_

NDK 定义的包含变量

本节讨论构建系统在解析您的 Android.mk 文件之前定义的 GNU Make 变量。在某些情况下,NDK 可能会多次解析您的 Android.mk 文件,每次都使用其中一些变量的不同定义。

CLEAR_VARS

此变量指向一个构建脚本,该脚本会取消定义下面“开发者定义的变量”部分中列出的几乎所有 LOCAL_XXX 变量。在描述新模块之前,使用此变量包含此脚本。使用它的语法是

include $(CLEAR_VARS)

BUILD_EXECUTABLE

此变量指向一个构建脚本,该脚本会收集您在 LOCAL_XXX 变量中提供的有关模块的所有信息,并确定如何从您列出的源文件中构建目标执行文件。请注意,使用此脚本要求您至少已为 LOCAL_MODULELOCAL_SRC_FILES 分配值(有关这些变量的详细信息,请参阅模块描述变量)。

使用此变量的语法是

include $(BUILD_EXECUTABLE)

BUILD_SHARED_LIBRARY

此变量指向一个构建脚本,该脚本会收集您在 LOCAL_XXX 变量中提供的有关模块的所有信息,并确定如何从您列出的源文件中构建目标共享库。请注意,使用此脚本要求您至少已为 LOCAL_MODULELOCAL_SRC_FILES 分配值(有关这些变量的详细信息,请参阅模块描述变量)。

使用此变量的语法是

include $(BUILD_SHARED_LIBRARY)

共享库变量会使构建系统生成一个带有 .so 扩展名的库文件。

BUILD_STATIC_LIBRARY

BUILD_SHARED_LIBRARY 的变体,用于构建静态库。构建系统不会将静态库复制到您的项目/包中,但可以使用它们来构建共享库(请参阅下面的 LOCAL_STATIC_LIBRARIESLOCAL_WHOLE_STATIC_LIBRARIES)。使用此变量的语法是

include $(BUILD_STATIC_LIBRARY)

静态库变量会使构建系统生成一个带有 .a 扩展名的库。

PREBUILT_SHARED_LIBRARY

指向一个用于指定预构建共享库的构建脚本。与 BUILD_SHARED_LIBRARYBUILD_STATIC_LIBRARY 的情况不同,此处 LOCAL_SRC_FILES 的值不能是源文件。相反,它必须是预构建共享库的单一路径,例如 foo/libfoo.so。使用此变量的语法是

include $(PREBUILT_SHARED_LIBRARY)

您还可以通过使用 LOCAL_PREBUILTS 变量在另一个模块中引用预构建库。有关使用预构建的更多信息,请参阅使用预构建库

PREBUILT_STATIC_LIBRARY

PREBUILT_SHARED_LIBRARY 相同,但用于预构建静态库。有关使用预构建的更多信息,请参阅使用预构建库

目标信息变量

构建系统会根据 APP_ABI 变量指定的每个 ABI 解析 Android.mk 文件一次,该变量通常在您的 Application.mk 文件中定义。如果 APP_ABIall,则构建系统会根据 NDK 支持的每个 ABI 解析 Android.mk 文件一次。本节描述构建系统每次解析 Android.mk 文件时定义的变量。

TARGET_ARCH

构建系统在解析此 Android.mk 文件时所针对的 CPU 系列。此变量将是以下之一:armarm64x86x86_64

TARGET_PLATFORM

构建系统在解析此 Android.mk 文件时所针对的 Android API 级别编号。例如,Android 5.1 系统映像对应于 Android API 级别 22:android-22。有关平台名称和相应 Android 系统映像的完整列表,请参阅原生 API。以下示例显示了使用此变量的语法

ifeq ($(TARGET_PLATFORM),android-22)
    # ... do something ...
endif

TARGET_ARCH_ABI

构建系统在解析此 Android.mk 文件时所针对的 ABI。表 1 显示了每个受支持的 CPU 和架构所使用的 ABI 设置。

表 1. 不同 CPU 和架构的 ABI 设置。

CPU 和架构 设置
ARMv7 armeabi-v7a
ARMv8 AArch64 arm64-v8a
i686 x86
x86-64 x86_64

以下示例显示了如何检查 ARMv8 AArch64 是否为目标 CPU-ABI 组合

ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
  # ... do something ...
endif

有关架构 ABI 和相关兼容性问题的更多详细信息,请参阅Android ABI

未来新的目标 ABI 将具有不同的值。

TARGET_ABI

目标 Android API 级别和 ABI 的连接。当您想要针对真实设备的特定目标系统映像进行测试时,此功能特别有用。例如,检查运行 Android API 级别 22 的 64 位 ARM 设备

ifeq ($(TARGET_ABI),android-22-arm64-v8a)
  # ... do something ...
endif

模块描述变量

本节中的变量用于向构建系统描述您的模块。每个模块描述应遵循以下基本流程

  1. 使用 CLEAR_VARS 变量初始化或取消定义与模块关联的变量。
  2. 为用于描述模块的变量分配值。
  3. 使用 BUILD_XXX 变量设置 NDK 构建系统为模块使用适当的构建脚本。

LOCAL_PATH

此变量用于指定当前文件的路径。您必须在 Android.mk 文件的开头定义它。以下示例显示了如何执行此操作

LOCAL_PATH := $(call my-dir)

CLEAR_VARS 所指向的脚本不会清除此变量。因此,您只需定义它一次,即使您的 Android.mk 文件描述了多个模块。

LOCAL_MODULE

此变量存储您的模块的名称。它必须在所有模块名称中唯一,且不得包含任何空格。您必须在包含任何脚本(除了 CLEAR_VARS 的脚本)之前定义它。您无需添加 lib 前缀或 .so.a 文件扩展名;构建系统会自动进行这些修改。在您的 Android.mkApplication.mk 文件中,通过未修改的名称引用您的模块。例如,以下行会生成一个名为 libfoo.so 的共享库模块

LOCAL_MODULE := "foo"

如果您希望生成的模块的名称不是 lib + LOCAL_MODULE 的值,则可以使用 LOCAL_MODULE_FILENAME 变量来为您选择生成的模块的名称。

LOCAL_MODULE_FILENAME

此可选变量允许您覆盖构建系统用于默认生成的文件名称。例如,如果您的 LOCAL_MODULE 名称是 foo,则可以强制系统将其生成的文件命名为 libnewfoo。以下示例显示了如何实现此目的

LOCAL_MODULE := foo
LOCAL_MODULE_FILENAME := libnewfoo

对于共享库模块,此示例将生成一个名为 libnewfoo.so 的文件。

LOCAL_SRC_FILES

此变量包含构建系统用于生成模块的源文件列表。仅列出构建系统实际传递给编译器的文件,因为构建系统会自动计算任何关联的依赖项。请注意,您可以使用相对(相对于 LOCAL_PATH)和绝对文件路径。

我们建议避免使用绝对文件路径;相对路径使您的 Android.mk 文件更具可移植性。

LOCAL_CPP_EXTENSION

您可以使用此可选变量为 C++ 源文件指定除 .cpp 之外的文件扩展名。例如,以下行将扩展名更改为 .cxx。(设置必须包含点。)

LOCAL_CPP_EXTENSION := .cxx

您可以使用此变量指定多个扩展名。例如

LOCAL_CPP_EXTENSION := .cxx .cpp .cc

LOCAL_CPP_FEATURES

您可以使用此可选变量指示您的代码依赖于特定的 C++ 功能。它会在构建过程中启用正确的编译器和链接器标志。对于预构建二进制文件,此变量还声明二进制文件依赖于哪些功能,从而有助于确保最终链接正确工作。我们建议您使用此变量,而不是直接在 LOCAL_CPPFLAGS 定义中启用 -frtti-fexceptions

使用此变量可让构建系统为每个模块使用适当的标志。使用 LOCAL_CPPFLAGS 会使编译器为所有模块使用所有指定的标志,而无论实际需要如何。

例如,要指示您的代码使用 RTTI(运行时类型信息),请写入

LOCAL_CPP_FEATURES := rtti

要指示您的代码使用 C++ 异常,请写入

LOCAL_CPP_FEATURES := exceptions

您还可以为该变量指定多个值。例如

LOCAL_CPP_FEATURES := rtti features

您描述这些值的顺序无关紧要。

LOCAL_C_INCLUDES

您可以使用此可选变量指定相对于 NDK root 目录的路径列表,以便在编译所有源文件(C、C++ 和 Assembly)时将其添加到包含搜索路径中。例如

LOCAL_C_INCLUDES := sources/foo

甚至

LOCAL_C_INCLUDES := $(LOCAL_PATH)/<subdirectory>/foo

在通过 LOCAL_CFLAGSLOCAL_CPPFLAGS 设置任何相应的包含标志之前定义此变量。

构建系统在启动 ndk-gdb 进行原生调试时也会自动使用 LOCAL_C_INCLUDES 路径。

LOCAL_ASFLAGS

构建 .s.S 文件时将传递给 Clang 的标志。

LOCAL_ASMFLAGS

构建 .asm 文件时将传递给 yasm 的标志。

LOCAL_CFLAGS

构建 C、C++ 和某些汇编(.s.S,但不包括 .asm)源文件时将传递给 Clang 的标志。这样做对于指定额外的宏定义或编译选项很有用。使用 LOCAL_CPPFLAGS 仅指定 C++ 的标志。使用 LOCAL_CONLYFLAGS 仅指定 C 的标志。

尽量不要在 Android.mk 文件中更改优化/调试级别。构建系统可以使用 Application.mk 文件中的相关信息自动为您处理此设置。这样做可以使构建系统生成在调试过程中使用的有用数据文件。

可以通过写入以下内容来指定额外的包含路径

LOCAL_CFLAGS += -I<path>,

但是,最好为此目的使用 LOCAL_C_INCLUDES,因为这样做也可以使用 ndk-gdb 进行原生调试的可用路径。

LOCAL_CONLYFLAGS

编译 C 源文件时将传递给 Clang 的标志。与 LOCAL_CFLAGS 不同,编译 C++ 或汇编源文件时不会将 LOCAL_CONLYFLAGS 传递给 Clang。

LOCAL_CPPFLAGS

构建 C++ 源文件将传递的一组可选编译器标志。它们将出现在编译器命令行的 LOCAL_CFLAGS 之后。使用 LOCAL_CFLAGS 指定 C 和 C++ 的标志。

LOCAL_STATIC_LIBRARIES

此变量存储当前模块依赖的静态库模块列表。

如果当前模块是共享库或执行文件,此变量将强制这些库链接到生成的二进制文件中。

如果当前模块是静态库,此变量仅指示依赖当前模块的其他模块也将依赖列出的库。

LOCAL_SHARED_LIBRARIES

此变量是此模块在运行时依赖的共享库模块列表。此信息在链接时是必需的,并且需要将相应信息嵌入到生成的文件中。

LOCAL_WHOLE_STATIC_LIBRARIES

此变量是 LOCAL_STATIC_LIBRARIES 的变体,表示链接器应将关联的库模块视为整个归档。有关整个归档的更多信息,请参阅 GNU ld 文档中关于 --whole-archive 标志的内容。

当多个静态库之间存在循环依赖时,此变量很有用。当您使用此变量构建共享库时,它将强制构建系统将静态库中的所有目标文件添加到最终二进制文件中。但是,生成可执行文件时并非如此。

LOCAL_LDLIBS

此变量包含用于构建共享库或可执行文件的附加链接器标志列表。它使您可以使用 -l 前缀传递特定系统库的名称。例如,以下示例告诉链接器生成一个在加载时链接到 /system/lib/libz.so 的模块

LOCAL_LDLIBS := -lz

有关此 NDK 版本中您可以链接的暴露系统库列表,请参阅原生 API

LOCAL_LDFLAGS

构建系统在构建共享库或可执行文件时使用的其他链接器标志列表。例如,要在 ARM/X86 上使用 ld.bfd 链接器

LOCAL_LDFLAGS += -fuse-ld=bfd

LOCAL_ALLOW_UNDEFINED_SYMBOLS

默认情况下,当构建系统在尝试构建共享库时遇到未定义的引用,它将抛出未定义符号错误。此错误可以帮助您捕获源代码中的错误。

要禁用此检查,请将此变量设置为 true。请注意,此设置可能导致共享库在运行时加载失败。

LOCAL_ARM_MODE

默认情况下,构建系统以 thumb 模式生成 ARM 目标二进制文件,其中每条指令宽 16 位,并与 thumb/ 目录中的 STL 库链接。将此变量定义为 arm 会强制构建系统以 32 位 arm 模式生成模块的目标文件。以下示例显示了如何执行此操作

LOCAL_ARM_MODE := arm

您还可以通过在源文件名后附加 .arm 后缀来指示构建系统仅以 arm 模式构建特定源文件。例如,以下示例告诉构建系统始终以 ARM 模式编译 bar.c,但根据 LOCAL_ARM_MODE 的值构建 foo.c

LOCAL_SRC_FILES := foo.c bar.c.arm

LOCAL_ARM_NEON

此变量仅在您针对 armeabi-v7a ABI 时才重要。它允许在 C 和 C++ 源文件中使用 ARM Advanced SIMD (NEON) 编译器内联函数,以及在汇编文件中使用 NEON 指令。

请注意,并非所有基于 ARMv7 的 CPU 都支持 NEON 指令集扩展。因此,您必须执行运行时检测才能在运行时安全地使用此代码。有关更多信息,请参阅Neon 支持CPU 功能

另外,您可以使用 .neon 后缀指定构建系统仅编译支持 NEON 的特定源文件。在以下示例中,构建系统使用 thumb 和 neon 支持编译 foo.c,使用 thumb 支持编译 bar.c,并使用 ARM 和 NEON 支持编译 zoo.c

LOCAL_SRC_FILES = foo.c.neon bar.c zoo.c.arm.neon

如果您同时使用这两个后缀,则 .arm 必须在 .neon 之前。

LOCAL_DISABLE_FORMAT_STRING_CHECKS

默认情况下,构建系统使用格式字符串保护来编译代码。如果 printf 风格的函数中使用了非常量格式字符串,这样做会强制发生编译器错误。此保护默认开启,但您可以通过将此变量的值设置为 true 来禁用它。除非有充分的理由,否则我们不建议这样做。

LOCAL_EXPORT_CFLAGS

此变量记录了一组 C/C++ 编译器标志,这些标志会添加到通过 LOCAL_STATIC_LIBRARIESLOCAL_SHARED_LIBRARIES 变量使用此模块的任何其他模块的 LOCAL_CFLAGS 定义中。

例如,考虑以下一对模块:foobar,其中 bar 依赖于 foo

include $(CLEAR_VARS)
LOCAL_MODULE := foo
LOCAL_SRC_FILES := foo/foo.c
LOCAL_EXPORT_CFLAGS := -DFOO=1
include $(BUILD_STATIC_LIBRARY)


include $(CLEAR_VARS)
LOCAL_MODULE := bar
LOCAL_SRC_FILES := bar.c
LOCAL_CFLAGS := -DBAR=2
LOCAL_STATIC_LIBRARIES := foo
include $(BUILD_SHARED_LIBRARY)

在此处,构建系统在构建 bar.c 时将标志 -DFOO=1-DBAR=2 传递给编译器。它还将导出的标志添加到您模块的 LOCAL_CFLAGS 前面,以便您可以轻松覆盖它们。

此外,模块之间的关系是传递的:如果 zoo 依赖于 bar,而 bar 又依赖于 foo,则 zoo 也会继承从 foo 导出的所有标志。

最后,构建系统在本地构建时(即构建导出标志的模块)不使用导出的标志。因此,在上述示例中,它在构建 foo/foo.c 时不会将 -DFOO=1 传递给编译器。要在本地构建,请改用 LOCAL_CFLAGS

LOCAL_EXPORT_CPPFLAGS

此变量与 LOCAL_EXPORT_CFLAGS 相同,但仅用于 C++ 标志。

LOCAL_EXPORT_C_INCLUDES

此变量与 LOCAL_EXPORT_CFLAGS 相同,但用于 C 包含路径。在某些情况下非常有用,例如 bar.c 需要包含模块 foo 的头文件。

LOCAL_EXPORT_LDFLAGS

此变量与 LOCAL_EXPORT_CFLAGS 相同,但用于链接器标志。

LOCAL_EXPORT_LDLIBS

此变量与 LOCAL_EXPORT_CFLAGS 相同,告诉构建系统将特定系统库的名称传递给编译器。在您指定的每个库的名称前加上 -l

请注意,构建系统会将导入的链接器标志附加到您模块的 LOCAL_LDLIBS 变量的值之后。这是由于 Unix 链接器的工作方式。

当模块 foo 是静态库并且包含依赖于系统库的代码时,此变量通常很有用。然后可以使用 LOCAL_EXPORT_LDLIBS 来导出依赖项。例如

include $(CLEAR_VARS)
LOCAL_MODULE := foo
LOCAL_SRC_FILES := foo/foo.c
LOCAL_EXPORT_LDLIBS := -llog
include $(BUILD_STATIC_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := bar
LOCAL_SRC_FILES := bar.c
LOCAL_STATIC_LIBRARIES := foo
include $(BUILD_SHARED_LIBRARY)

在此示例中,构建系统在构建 libbar.so 时将 -llog 放在链接器命令的末尾。这样做会告诉链接器,因为 libbar.so 依赖于 foo,所以它也依赖于系统日志库。

LOCAL_SHORT_COMMANDS

当您的模块具有大量源文件和/或依赖的静态或共享库时,将此变量设置为 true。这样做会强制构建系统对包含中间目标文件或链接库的归档使用 @ 语法。

此功能在 Windows 上很有用,因为命令行最多只接受 8191 个字符,这对于复杂项目来说可能太小。它还会影响单个源文件的编译,几乎所有编译器标志也都会放在列表文件中。

请注意,任何除 true 之外的值都将恢复为默认行为。您还可以在 Application.mk 文件中定义 APP_SHORT_COMMANDS,以强制您的项目中的所有模块都采用此行为。

我们不建议默认启用此功能,因为它会使构建速度变慢。

LOCAL_THIN_ARCHIVE

构建静态库时,将此变量设置为 true。这样做将生成一个瘦归档,一个不包含目标文件但包含指向通常包含的实际目标文件的文件路径的库文件。

这对于减小构建输出的大小很有用。缺点是此类库无法移动到其他位置(其中的所有路径都是相对的)。

有效值为 truefalse 或空。可以在您的 Application.mk 文件中通过 APP_THIN_ARCHIVE 变量设置默认值。

LOCAL_FILTER_ASM

将此变量定义为一个 shell 命令,构建系统将使用该命令过滤从为 LOCAL_SRC_FILES 指定的文件中提取或生成的汇编文件。定义此变量将导致发生以下情况

  1. 构建系统从任何 C 或 C++ 源文件生成一个临时汇编文件,而不是将它们编译成目标文件。
  2. 构建系统对任何临时汇编文件以及 LOCAL_SRC_FILES 中列出的任何汇编文件执行 LOCAL_FILTER_ASM 中的 shell 命令,从而生成另一个临时汇编文件。
  3. 构建系统将这些过滤后的汇编文件编译成目标文件。

例如

LOCAL_SRC_FILES  := foo.c bar.S
LOCAL_FILTER_ASM :=

foo.c --1--> $OBJS_DIR/foo.S.original --2--> $OBJS_DIR/foo.S --3--> $OBJS_DIR/foo.o
bar.S                                 --2--> $OBJS_DIR/bar.S --3--> $OBJS_DIR/bar.o

"1" 对应于编译器,"2" 对应于过滤器,"3" 对应于汇编器。过滤器必须是一个独立的 shell 命令,其第一个参数是输入文件的名称,第二个参数是输出文件的名称。例如

myasmfilter $OBJS_DIR/foo.S.original $OBJS_DIR/foo.S
myasmfilter bar.S $OBJS_DIR/bar.S

NDK 提供的函数宏

本节介绍 NDK 提供的 GNU Make 函数宏。使用 $(call <function>) 评估它们;它们返回文本信息。

my-dir

此宏返回最后包含的 makefile 的路径,通常是当前 Android.mk 的目录。my-dirAndroid.mk 文件的开头定义 LOCAL_PATH 时很有用。例如

LOCAL_PATH := $(call my-dir)

由于 GNU Make 的工作方式,此宏实际返回的是构建系统在解析构建脚本时包含的最后一个 makefile 的路径。因此,在包含其他文件后,不应调用 my-dir

例如,考虑以下示例

LOCAL_PATH := $(call my-dir)

# ... declare one module

include $(LOCAL_PATH)/foo/`Android.mk`

LOCAL_PATH := $(call my-dir)

# ... declare another module

这里的问题是,第二次调用 my-dirLOCAL_PATH 定义为 $PATH/foo 而不是 $PATH,因为这是其最近包含的文件所指向的位置。

您可以通过将其他包含放在 Android.mk 文件中的其他所有内容之后来避免此问题。例如

LOCAL_PATH := $(call my-dir)

# ... declare one module

LOCAL_PATH := $(call my-dir)

# ... declare another module

# extra includes at the end of the Android.mk file
include $(LOCAL_PATH)/foo/Android.mk

如果无法以这种方式组织文件,请将第一次 my-dir 调用的值保存到另一个变量中。例如

MY_LOCAL_PATH := $(call my-dir)

LOCAL_PATH := $(MY_LOCAL_PATH)

# ... declare one module

include $(LOCAL_PATH)/foo/`Android.mk`

LOCAL_PATH := $(MY_LOCAL_PATH)

# ... declare another module

all-subdir-makefiles

返回当前 my-dir 路径下所有子目录中 Android.mk 文件的列表。

您可以使用此函数向构建系统提供深层嵌套的源目录层次结构。默认情况下,NDK 仅查找包含 Android.mk 文件的目录中的文件。

this-makefile

返回当前 makefile(构建系统从中调用该函数)的路径。

parent-makefile

返回包含树中父级 makefile 的路径(包含当前 makefile 的 makefile 的路径)。

grand-parent-makefile

返回包含树中祖父级 makefile 的路径(包含当前 makefile 的 makefile 的路径)。

import-module

允许您通过模块名称查找并包含模块的 Android.mk 文件的函数。一个典型的示例如下

$(call import-module,<name>)

在此示例中,构建系统会在您的 NDK_MODULE_PATH 环境变量引用的目录列表中查找标记为 <name> 的模块,并自动为您包含其 Android.mk 文件。