andriod 相关,懒得总是翻枪

来源:互联网 发布:阿里云代理商技术 编辑:程序博客网 时间:2024/04/28 07:47

Android.mk

本页内容

  1. 概览
  2. 基础知识
  3. 变量和宏
  4. 模块描述变量

本页介绍用于将 C 和 C++ 源文件粘合至 Android NDK 的 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_FILES 和 LOCAL_STATIC_LIBRARIES。 请注意,它不会清除 LOCAL_PATH。此变量必须保留其值,因为系统在单一 GNU Make 执行环境(其中所有变量都是全局的)中解析所有构建控制文件。 在描述每个模块之前,必须声明(重新声明)此变量。

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

LOCAL_MODULE := hello-jni

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

:如果模块名称的开头已是 lib,则构建系统不会附加额外的前缀 lib;而是按原样采用模块名称,并添加 .so 扩展名。 因此,比如原来名为 libfoo.c 的源文件仍会生成名为 libfoo.so 的共享对象文件。 此行为是为了支持 Android 平台源文件从 Android.mk 文件生成的库;所有这些库的名称都以 lib 开头。

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

LOCAL_SRC_FILES := hello-jni.c

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

最后一行帮助系统将所有内容连接到一起:

include $(BUILD_SHARED_LIBRARY)

BUILD_SHARED_LIBRARY 变量指向 GNU Makefile 脚本,用于收集您自最近 include 后在 LOCAL_XXX 变量中定义的所有信息。 此脚本确定要构建的内容及其操作方法。

示例目录中有更复杂的示例,包括您可以查看的带注释的 Android.mk 文件。 此外,示例:native-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_SHARED_LIBRARY

此变量指向的脚本用于收集您在 LOCAL_XXX 变量中提供的模块所有相关信息,以及确定如何从列出的源文件构建目标共享库。 请注意,使用此脚本要求您至少已为 LOCAL_MODULE 和 LOCAL_SRC_FILES 赋值(如需了解有关这些变量的详细信息,请参阅模块描述变量)。

使用此变量的语法为:

include $(BUILD_SHARED_LIBRARY)

共享库变量导致构建系统生成具有 .so 扩展名的库文件。

BUILD_STATIC_LIBRARY

用于构建静态库的 BUILD_SHARED_LIBRARY 的变体。构建系统不会将静态库复制到您的项目/软件包,但可能使用它们构建共享库(请参阅下面的 LOCAL_STATIC_LIBRARIES 和 LOCAL_WHOLE_STATIC_LIBRARIES)。 使用此变量的语法为:

include $(BUILD_STATIC_LIBRARY)

静态库变量导致构建系统生成扩展名为 .a 的库。

PREBUILT_SHARED_LIBRARY

指向用于指定预建共享库的构建脚本。与 BUILD_SHARED_LIBRARY 和 BUILD_STATIC_LIBRARY 的情况不同,这里的 LOCAL_SRC_FILES 值不能是源文件, 而必须是指向预建共享库的单一路径,例如 foo/libfoo.so。 使用此变量的语法为:

include $(PREBUILT_SHARED_LIBRARY)

也可使用 LOCAL_PREBUILTS 变量引用另一个模块中的预建库。 如需了解有关使用预建库的详细信息,请参阅使用预建库。

PREBUILT_STATIC_LIBRARY

与 PREBUILT_SHARED_LIBRARY 相同,但用于预构建的静态库。如需了解有关使用预建库的详细信息,请参阅使用预建库。

TARGET_ARCH

Android 开放源代码项目所指定的目标 CPU 架构的名称。对于与 ARM 兼容的任何构建,请使用独立于 CPU 架构修订版或 ABI 的 arm(请参阅下面的 TARGET_ARCH_ABI)。

此变量的值取自您在 Android.mk 文件中定义的 APP_ABI 变量,系统将在解析 Android.mk 文件前读取其值。

TARGET_PLATFORM

作为构建系统目标的 Android API 级别号。例如,Android 5.1 系统映像对应于 Android API 级别 22:android-22。如需平台名称及相应 Android 系统映像的完整列表,请参阅 Android NDK 原生 API。以下示例显示了使用此变量的语法:

TARGET_PLATFORM := android-22

TARGET_ARCH_ABI

当构建系统解析此 Android.mk 文件时,此变量将 CPU 和架构的名称存储到目标。 您可以指定以下一个或多个值,使用空格作为多个目标之间的分隔符。 表 1 显示了要用于每个支持的 CPU 和架构的 ABI 设置。

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

CPU 和架构设置ARMv5TEarmeabiARMv7armeabi-v7aARMv8 AArch64arm64-v8ai686x86x86-64x86_64mips32 (r1)mipsmips64 (r6)mips64全部all

以下示例显示如何将 ARMv8 AArch64 设置为目标 CPU 与 ABI 的组合:

TARGET_ARCH_ABI := arm64-v8a

注:在 Android NDK 1.6_r1 和以前的版本中,此变量定义为 arm

如需了解架构 ABI 和相关兼容性问题的详细信息,请参阅 ABI 管理。

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

TARGET_ABI

目标 Android API 级别与 ABI 的联接,特别适用于要针对实际设备测试特定目标系统映像的情况。 例如,要指定在 Android API 级别 22 上运行的 64 位 ARM 设备:

TARGET_ABI := android-22-arm64-v8a

:在 Android NDK 1.6_r1 和以前的版本中,默认值为 android-3-arm

模块描述变量


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

    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.mk 和 Application.mk 文件中,请通过未修改的名称引用模块。 例如,以下行会导致生成名为 libfoo.so 的共享库模块:

LOCAL_MODULE := "foo"

如果希望生成的模块使用 lib 以外的名称和 LOCAL_MODULE 以外的值,可以使用 LOCAL_MODULE_FILENAME 变量为生成的模块指定自己选择的名称。

LOCAL_MODULE_FILENAME

此可选变量可让您覆盖构建系统默认用于其生成的文件的名称。 例如,如果 LOCAL_MODULE 的名称为 foo,您可以强制系统将它生成的文件命名为 libnewfoo。 以下示例显示如何完成此操作:

LOCAL_MODULE := fooLOCAL_MODULE_FILENAME := libnewfoo

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

:无法替换文件路径或文件扩展名。

LOCAL_SRC_FILES

此变量包含构建系统用于生成模块的源文件列表。 只列出构建系统实际传递到编译器的文件,因为构建系统会自动计算所有关联的依赖关系。

请注意,可以使用相对文件路径(指向 LOCAL_PATH)和绝对文件路径。

建议避免使用绝对文件路径;相对路径会使 Android.mk 文件移植性更强。

注:在构建文件中务必使用 Unix 样式的正斜杠 (/)。构建系统无法正确处理 Windows 样式的反斜杠 (\)。

LOCAL_CPP_EXTENSION

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

LOCAL_CPP_EXTENSION := .cxx

从 NDK r7 开始,您可以使用此变量指定多个扩展名。例如:

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)时添加到 include 搜索路径。 例如:

LOCAL_C_INCLUDES := sources/foo

甚至:

LOCAL_C_INCLUDES := $(LOCAL_PATH)//foo

在通过 LOCAL_CFLAGS 或 LOCAL_CPPFLAGS 设置任何对应的 include 标志之前定义此变量。

在使用 ndk-gdb 启动本地调试时,构建系统也会自动使用 LOCAL_C_INCLUDES 路径。

LOCAL_CFLAGS

此可选变量为构建系统设置在构建 C  C++ 源文件时要传递的编译器标志。 此功能对于指定额外的宏定义或编译选项可能很有用。

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

注:在 android-ndk-1.5_r1 中,相应的标志只适用于 C 源文件,而不适用于 C++ 源文件。 它们现在与整个 Android 构建系统的行为匹配。(您现在可以使用 LOCAL_CPPFLAGS 只为 C++ 源文件指定标志。)

可通过编写以下代码指定其他 include 路径:

LOCAL_CFLAGS += -I<path>,
但使用 LOCAL_C_INCLUDES 更好,因为这样也可以通过 ndk-gdb 使用可用于本地调试的路径。

LOCAL_CPPFLAGS

当构建 C++ 源文件时才会传递一组可选的编译器标志。 它们将出现在编译器命令行中的 LOCAL_CFLAGS 后面。

注:在 android-ndk-1.5_r1 中,相应的标志适用于 C 和 C++ 源文件。 这已经更正,可与整个 Android 构建系统的行为匹配。要为 C 和 C++ 源文件指定标志,请使用 LOCAL_CFLAGS

LOCAL_STATIC_LIBRARIES

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

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

如果当前模块是静态库,此变量只是指示,依赖当前模块的模块也会依赖列出的库。

LOCAL_SHARED_LIBRARIES

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

LOCAL_WHOLE_STATIC_LIBRARIES

此变量是 LOCAL_STATIC_LIBRARIES 的变体,表示链接器应将相关的库模块视为整个存档。 如需了解有关整个存档的详细信息,请参阅 GNU 链接器关于 --whole-archive 标志的文档。

当多个静态库之间具有循环相依关系时,此变量很有用。 使用此变量构建共享库时,将会强制构建系统将所有对象文件从静态库添加到最终二进制文件。 但在生成可执行文件时不会发生这样的情况。

LOCAL_LDLIBS

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

LOCAL_LDLIBS := -lz

如需了解此 NDK 版本中可以链接的已公开系统库列表,请参阅 Android NDK 原生 API。

注: 如果为静态库定义此变量,构建系统会忽略它,并且 ndk-build 会显示一则警告。

LOCAL_LDFLAGS

构建共享库或可执行文件时供构建系统使用的其他链接器标志列表。 例如,以下示例在 ARM/X86 GCC 4.6+ 上使用 ld.bfd 链接器,该系统上的默认链接器是 ld.gold

LOCAL_LDFLAGS += -fuse-ld=bfd

注:如果为静态库定义此变量,构建系统会忽略它,并且 ndk-build 会显示一则警告。

LOCAL_ALLOW_UNDEFINED_SYMBOLS

默认情况下,若构建系统在尝试构建共享库时遇到未定义的引用,将会引发“未定义的符号”错误。 此错误可帮助您捕获源代码中的缺陷。

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

注: 如果为静态库定义此变量,构建系统会忽略它,并且 ndk-build 会显示一则警告。

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

注:您也可以在 Application.mk 文件中将 APP_OPTIM 设置为 debug,强制构建系统生成 ARM 二进制文件。指定 debug 会强制构建 ARM,因为工具链调试程序无法正确处理 Thumb 代码。

LOCAL_ARM_NEON

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

请注意,并非所有基于 ARMv7 的 CPU 都支持 NEON 指令集扩展。因此,必须执行运行时检测以便在运行时安全地使用此代码。 如需了解详细信息,请参阅 NEON 支持和 cpufeatures 库。

或者,您也可以使用 .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_NO_EXECUTE

Android NDK r4 添加了对“NX 位”安全功能的支持。此支持默认启用,但您也可通过将此变量设置为 true 将其停用。 如果没有必要的原因,我们不建议停用。

此功能不会修改 ABI,并且仅在针对 ARMv6+ CPU 设备的内核上启用。 启用此功能的机器代码在运行较早 CPU 架构的设备上将不加修改而直接运行。

如需了解详细信息,请参阅 Wikipedia:NX 位和 GNU 栈快速入门。

LOCAL_DISABLE_RELRO

默认情况下,NDK 编译具有只读重定位和 GOT 保护的代码。 此变量指示运行时链接器在重定位后将某些内存区域标记为只读,增加了某些安全漏洞利用(例如 GOT 覆盖)的难度。 请注意,这些保护仅在 Android API 级别 16 和更高版本上有效。在较低的 API 级别上,该代码仍会运行,但没有内存保护。

此变量默认启用,但您也可通过将其值设置为 true 来停用它。 如果没有必要的原因,我们不建议停用。

如需了解详细信息,请参阅 RELRO:重定位只读和 RedHat Enterprise Linux 中的安全增强功能(第 6 节)。

LOCAL_DISABLE_FORMAT_STRING_CHECKS

默认情况下,构建系统编译具有格式字符串保护的代码。如果 printf 样式的函数中使用非常量的格式字符串,这样会强制编译器出错。

此保护默认启用,但您也可通过将此变量的值设置为 true 将其停用。 如果没有必要的原因,我们不建议停用。

LOCAL_EXPORT_CFLAGS

此变量用于记录一组 C/C++ 编译器标志,这将标志将添加到通过 LOCAL_STATIC_LIBRARIES 或 LOCAL_SHARED_LIBRARIES 变量使用它们的任何其他模块的 LOCAL_CFLAGS 定义。

例如,假设有以下模块对:foo 和 bar,分别依赖于 foo

include $(CLEAR_VARS)LOCAL_MODULE := fooLOCAL_SRC_FILES := foo/foo.cLOCAL_EXPORT_CFLAGS := -DFOO=1include $(BUILD_STATIC_LIBRARY)include $(CLEAR_VARS)LOCAL_MODULE := barLOCAL_SRC_FILES := bar.cLOCAL_CFLAGS := -DBAR=2LOCAL_STATIC_LIBRARIES := fooinclude $(BUILD_SHARED_LIBRARY)

在这里,构建系统在构建 bar.c 时会向编译器传递标志 -DFOO=1 和 -DBAR=2。 它还会在模块的 LOCAL_CFLAGS 前面加上导出的标志,以便您轻松替换它们。

此外,模块之间的关系也是可传递的:如果 zoo 依赖于 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 include 路径。例如,当 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 := fooLOCAL_SRC_FILES := foo/foo.cLOCAL_EXPORT_LDLIBS := -lloginclude $(BUILD_STATIC_LIBRARY)include $(CLEAR_VARS)LOCAL_MODULE := barLOCAL_SRC_FILES := bar.cLOCAL_STATIC_LIBRARIES := fooinclude $(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 或空白。可通过 APP_THIN_ARCHIVE 变量在 Application.mk 文件中设置默认值。

:对于非静态库模块或预构建的静态库模块会忽略此变量。

LOCAL_FILTER_ASM

将此变量定义为构建系统要用于过滤从您为 LOCAL_SRC_FILES 指定的文件提取或生成的汇编文件的 shell 命令。

定义此变量会导致发生以下情况:

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

例如:

LOCAL_SRC_FILES  := foo.c bar.SLOCAL_FILTER_ASM :=foo.c --1--> $OBJS_DIR/foo.S.original --2--> $OBJS_DIR/foo.S --3--> $OBJS_DIR/foo.obar.S                                 --2--> $OBJS_DIR/bar.S --3--> $OBJS_DIR/bar.o

“1”对应编译器,“2”对应过滤器,“3”对应汇编程序。过滤器必须是采用输入文件名称作为其第一个参数、输出文件名称作为第二个参数的独立 shell 命令。 例如:

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

NDK 提供的函数宏

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

my-dir

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

LOCAL_PATH := $(call my-dir)

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

例如,考虑以下示例:

LOCAL_PATH := $(call my-dir)# ... declare one moduleinclude $(LOCAL_PATH)/foo/`Android.mk`LOCAL_PATH := $(call my-dir)# ... declare another module

这里的问题在于,对 my-dir 的第二次调用将 LOCAL_PATH 定义为 $PATH/foo,而不是 $PATH,因为这是其最近 include 指向的位置。

在 Android.mk 文件中的任何其他内容后放置额外 include 可避免此问题。 例如:

LOCAL_PATH := $(call my-dir)# ... declare one moduleLOCAL_PATH := $(call my-dir)# ... declare another module# extra includes at the end of the Android.mk fileinclude $(LOCAL_PATH)/foo/Android.mk

如果以这种方式构建文件不可行,请将第一个 my-dir 调用的值保存到另一个变量中。 例如:

MY_LOCAL_PATH := $(call my-dir)LOCAL_PATH := $(MY_LOCAL_PATH)# ... declare one moduleinclude $(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 文件。


Application.mk

本页内容

  1. 概览
  2. 变量

本文档介绍 Application.mk 构建文件,此文件用于描述应用需要的原生模块。 模块可以是静态库、共享库或可执行文件。

建议在阅读本页之前先阅读概念和 Android.mk 页面。 这样有助于您最深入地了解本页的内容。

概览


Application.mk 文件实际上是定义要编译的多个变量的微小 GNU Makefile 片段。 它通常位于 $PROJECT/jni/ 下,其中 $PROJECT 指向应用的项目目录。 另一种方式是将其放在顶级 $NDK/apps/ 目录的子目录下。 例如:

$NDK/apps/<myapp>/Application.mk

这里的 <myapp> 是用于向 NDK 构建系统描述应用的短名称。它不会实际进入生成的共享库或最终软件包。

变量


APP_PROJECT_PATH

此变量用于存储应用项目根目录的绝对路径。构建系统使用此信息将生成的 JNI 共享库的简缩版放入 APK 生成工具已知的特定位置。

如果将 Application.mk 文件放在 $NDK/apps/<myapp>/ 下,则必须定义此变量。 如果将其放在 $PROJECT/jni/ 下,则此变量可选。

APP_OPTIM

将此可选变量定义为 release 或 debug。在构建应用的模块时可使用它来更改优化级别。

发行模式是默认模式,可生成高度优化的二进制文件。调试模式会生成未优化的二进制文件,更容易调试。

请注意,您可以调试发行或调试二进制文件。但发行二进制文件在调试时提供的信息较少。 例如,构建系统会选择某些合适的变量,您无需检查它们。 此外,代码重新排序可能增大单步调试代码的难度;堆叠追踪可能不可靠。

在应用清单的 <application> 标记中声明 android:debuggable 将导致此变量默认使用 debug而非 release。 将 APP_OPTIM 设置为 release 可替换此默认值。

APP_CFLAGS

此变量用于存储构建系统在为任何模块编译任何 C 或 C++ 源代码时传递到编译器的一组 C 编译器标志。 您可使用此变量根据需要它的应用更改指定模块的版本,而无需修改 Android.mk 文件本身。

这些标志中的所有路径应为顶级 NDK 目录的相对路径。例如,如果您有以下设置:

sources/foo/Android.mksources/bar/Android.mk

要在 foo/Android.mk 中指定您在编译时要添加指向 bar 源文件的路径,应使用:

APP_CFLAGS += -Isources/bar

或者:

APP_CFLAGS += -I$(LOCAL_PATH)/../bar

-I../bar 在其等于 -I$NDK_ROOT/../bar 后不会运行。

注:此变量仅适用于 android-ndk-1.5_r1 中的 C 源文件,而不适用于 C++ 源文件。 在该版本后的所有版本中,APP_CFLAGS 匹配整个 Android 构建系统。

APP_CPPFLAGS

此变量包含构建系统在仅构建 C++ 源文件时传递到编译器的一组 C++ 编译器标志。

注:在 android-ndk-1.5_r1 中,此变量适用于 C 和 C++ 源文件。 在 NDK 的所有后续版本中,APP_CPPFLAGS 现在匹配整个 Android 构建系统。 对于适用于 C 和 C++ 源文件的标志,请使用 APP_CFLAGS

APP_LDFLAGS

构建系统在链接应用时传递的一组链接器标志。此变量仅在构建系统构建共享库和可执行文件时才相关。 当构建系统构建静态库时,会忽略这些标志。

APP_BUILD_SCRIPT

默认情况下,NDK 构建系统在 jni/ 下查找名称为 Android.mk 的文件。

如果要改写此行为,可以定义 APP_BUILD_SCRIPT 指向替代构建脚本。 构建系统始终将非绝对路径解释为 NDK 顶级目录的相对路径。

APP_ABI

默认情况下,NDK 构建系统为 armeabi ABI 生成机器代码。 此机器代码对应于基于 ARMv5TE、采用软件浮点运算的 CPU。 您可以使用 APP_ABI 选择不同的 ABI。 表 1 所示为不同指令集的 APP_ABI 设置。

表 1. APP_ABI 不同指令集的设置。

指令集值基于 ARMv7 的设备上的硬件 FPU 指令APP_ABI := armeabi-v7aARMv8 AArch64APP_ABI := arm64-v8aIA-32APP_ABI := x86Intel64APP_ABI := x86_64MIPS32APP_ABI := mipsMIPS64 (r6)APP_ABI := mips64所有支持的指令集APP_ABI := all

注:all 从 NDKr7 开始可用。

您也可以指定多个值,将它们放在同一行上,中间用空格分隔。例如:

APP_ABI := armeabi armeabi-v7a x86 mips

如需了解所有支持的 ABI 列表及其用法和限制的详细信息,请参阅 ABI 管理。

APP_PLATFORM

此变量包含目标 Android 平台的名称。例如,android-3 指定 Android 1.5 系统映像。 如需平台名称和对应 Android 系统映像的完整列表,请参阅 Android NDK 原生 API。

APP_STL

默认情况下,NDK 构建系统为 Android 系统提供的最小 C++ 运行时库 (system/lib/libstdc++.so) 提供 C++ 标头。 此外,它随附您可以在自己的应用中使用或链接的替代 C++ 实现。请使用 APP_STL 选择其中一个。 如需了解有关支持的运行时及其功能的信息,请参阅 NDK 运行时和功能。

APP_SHORT_COMMANDS

相当于 Application.mk 中的 LOCAL_SHORT_COMMANDS,适用于整个项目。如需了解详细信息,请参阅 Android.mk 上此变量的相关文档。

NDK_TOOLCHAIN_VERSION

将此变量定义为 4.9 或 4.8 以选择 GCC 编译器的版本。 64 位 ABI 默认使用版本 4.9 ,32 位 ABI 默认使用版本 4.8。要选择 Clang 的版本,请将此变量定义为 clang3.4clang3.5 或 clang。 指定 clang 会选择 Clang 的最新版本。

APP_PIE

从 Android 4.1(API 级别 16)开始,Android 的动态链接器支持位置独立的可执行文件 (PIE)。 从 Android 5.0(API 级别 21)开始,可执行文件需要 PIE。要使用 PIE 构建可执行文件,请设置 -fPIE 标志。 此标志增大了通过随机化代码位置来利用内存损坏缺陷的难度。 默认情况下,如果项目针对 android-16 或更高版本,ndk-build 会自动将此值设置为 true。您可以手动将其设置为 true 或 false

此标志仅适用于可执行文件。它在构建共享或静态库时没有影响。

注:PIE 可执行文件无法在 4.1 版之前的 Android 上运行。

此限制仅适用于可执行文件。它在构建共享或静态库时没有影响。

APP_THIN_ARCHIVE

在 Android.mk 文件中为此项目中的所有静态库模块设置 LOCAL_THIN_ARCHIVE 的默认值。 如需了解详细信息,请参阅 Android.mk 文档中的 LOCAL_THIN_ARCHIVE


ndk-build

本页内容

  1. 内部构建
  2. 从命令行调用
  3. 64 位和 32 位工具链
  4. 要求

ndk-build 文件是 Android NDK r4 中引入的一个 shell 脚本。其用途是调用正确的 NDK 构建脚本。

内部构建


运行 ndk-build 脚本相当于运行以下命令:

$GNUMAKE -f <ndk>/build/core/build-local.mk<parameters>

$GNUMAKE 指向 GNU Make 3.81 或更新版本,<ndk> 指向 NDK 安装目录。 您可以使用此信息从其他 shell 脚本甚至您自己的 Make 文件调用 ndk-build。

从命令行调用


ndk-build 文件位于 NDK 安装目录的顶层。若要从命令行运行该文件,请在应用项目目录中或其子目录中调用它。例如:

cd <project>$ <ndk>/ndk-build

在此示例中,<project> 指向项目的根目录,<ndk> 是您安装 NDK 的目录。

选项

ndk-build 的所有参数将直接传递到运行 NDK 构建脚本的底层 GNU make。 将 ndk-build 和表单 ndk-build <option> 中的选项结合使用。 例如:

$ ndk-build clean

提供的选项如下:

clean
移除以前生成的任意二进制文件。
V=1
启动构建,并显示构建命令。
-B
强制执行完全的重新构建。
-B V=1
强制执行完全的重新构建,并显示构建命令。
NDK_LOG=1
显示内部 NDK 日志消息(用于调试 NDK 本身)。
NDK_DEBUG=1
强制执行可调试版构建(请参阅表 1)。
NDK_DEBUG=0
强制执行发布版构建(请参阅表 1)。
NDK_HOST_32BIT=1
始终使用 32 位模式下的工具链(请参阅 64 位和 32 位工具链)。
NDK_APPLICATION_MK=<file>
使用 NDK_APPLICATION_MK 变量指向的特定 Application.mk 文件构建。
-C <project>
构建位于 <project> 的项目路径的原生代码。如果您不想在终端通过 cd 切换到该路径,则此选项非常有用。

可调试版与发布版构建

使用 NDK_DEBUG 选项,在特定情况下,通过 AndroidManifest.xml 指定调试版或发布版构建、与优化相关的行为以及是否包含符号。 表 1 显示每个可能的设置组合的结果。

表 1. NDK_DEBUG(命令行)的结果和 android:debuggable(清单)组合。

 NDK_DEBUG=0NDK_DEBUG=1未指定 NDK_DEBUGandroid:debuggble="true"调试;符号;已优化*1调试;符号;未优化*2(与 NDK_DEBUG=1 相同)android:debuggable="false"版本;符号;已优化版本;符号;未优化版本;无符号;已优化*3*1:用于分析
*2:用于运行 ndk-gdb 的默认值。
*3:默认模式。

注: NDK_DEBUG=0 等同于 APP_OPTIM=release,并符合 GCC -O2 选项。NDK_DEBUG=1 等同于 Application.mk 中的 APP_OPTIM=debug,并符合 GCC -O0 选项。 如需了解有关 APP_OPTIM 的详细信息,请参阅 Application.mk。

例如,命令行上的语法为:

$ ndk-build NDK_DEBUG=1

如果您使用 SDK r8 以前版本的构建工具,您还必须修改您的 AndroidManifest.xml 文件以指定调试模式。 执行此操作的语法类似于如下:

<application android:label="@string/app_name"android:debuggable="true">
从 SDK r8 开始,您不需要使用 AndroidManifest.xml。构建调试软件包(例如,使用 ant 调试或对应的 ADT 插件选项)可使工具自动选取通过 NDK_DEBUG=1 生成的原生调试文件。

64 位和 32 位工具链


某些工具链附带 64 位和 32 位版本。例如,目录 <ndk>/toolchain/<name>/prebuilt/ 和 <ndk>/prebuilt/ 可能同时包含分别用于 32 位和 64 位模式中的 Linux 工具的 linux-x86 和 linux-x86_64 文件夹。 ndk-build 脚本自动选择工具链的 64 位版本(如果主机操作系统支持)。 您可以通过在您的环境中或 ndk-build 命令行中使用 NDK_HOST_32BIT=1 来强制使用 32 位工具链。

请注意,64 位工具可以更好地利用主机资源(例如,它们速度更快,并且可处理更大的程序),同时它们仍可以为 Android 生成 32 位二进制文件。

要求


一般情况下,您需要安装 GNU Make 3.81 或更新版本才能使用 ndk-build 或 NDK。构建脚本将检测不兼容的 Make 工具,并生成错误消息。

如果您已安装 GNU Make 3.81,但默认 make 命令不能启动它,则在您的环境中定义 GNUMAKE 以便在启动 ndk-build 之前指向它。 例如:

$ export GNUMAKE=/usr/local/bin/gmake$ ndk-build

您可以在 $NDK/prebuilt/<OS>/bin/ 中将其他主机预构建工具替换为下列环境变量:

$ export NDK_HOST_AWK=<path-to-awk>$ export NDK_HOST_ECHO=<path-to-echo>$ export NDK_HOST_CMP=<path-to-cmp>

CMake

On this page

  1. Using CMake variables in Gradle
  2. Understanding the CMake build command
  3. YASM support in CMake
  4. Reporting problems

Using Android Studio 2.2 and higher, you can use the NDK and CMake to compile C and C++ code into a native library. Android Studio then packages your library into your APK using Gradle, the IDE's integrated build system.

If you are new to using CMake with Android Studio, go to Add C and C++ Code to Your Project to learn the basics of adding native sources to your project, creating a CMake build script, and adding your CMake project as a Gradle dependency. This page provides some additional information you can use to customize your CMake build.

Using CMake variables in Gradle


Once you link Gradle to your CMake project, you can configure certain NDK-specific variables that change the way CMake builds your native libraries. To pass an argument to CMake from your module-level build.gradle file, use the following DSL:

android {  ...  defaultConfig {    ...    // This block is different from the one you use to link Gradle    // to your CMake build script.    externalNativeBuild {      cmake {        ...        // Use the following syntax when passing arguments to variables:        // arguments "-DVAR_NAME=ARGUMENT".        arguments "-DANDROID_ARM_NEON=TRUE",        // If you're passing multiple arguments to a variable, pass them together:        // arguments "-DVAR_NAME=ARG_1 ARG_2"        // The following line passes 'rtti' and 'exceptions' to 'ANDROID_CPP_FEATURES'.                  "-DANDROID_CPP_FEATURES=rtti exceptions"      }    }  }  buildTypes {...}  // Use this block to link Gradle to your CMake build script.  externalNativeBuild {    cmake {...}  }}

The following table describes some of the variables you can configure when using CMake with the NDK.

Variable nameArgumentsDescriptionANDROID_TOOLCHAIN
  • clang (default)
  • gcc (deprecated)

Specifies the compiler toolchain CMake should use.

ANDROID_PLATFORM

For a complete list of platform names and corresponding Android system images, see Android NDK Native APIs.

Specifies the name of the target Android platform. For example,android-18 specifies Android 4.3 (API level 18).

Instead of changing this flag directly, you should set theminSdkVersion property in the defaultConfig or productFlavorsblocks of your module-level build.gradle file. This makes sure your library is used only by apps installed on devices running an adequate version of Android. The CMake toolchain then chooses the best platform version for the ABI you're building using the following logic:

  1. If there exists a platform version for the ABI equal tominSdkVersion, CMake uses that version.
  2. Otherwise, if there exists platform versions lower thanminSdkVersion for the ABI, CMake uses the highest of those platform versions. This is a reasonable choice because a missing platform version typically means that there were no changes to the native platform APIs since the previous available version.
  3. Otherwise, CMake uses the next available platform version higher than minSdkVersion.
ANDROID_STL

For a complete list of options, see Helper Runtimes

By default, CMake uses gnustl_static.

Specifies the STL CMake should use.

ANDROID_PIE
  • ON (default when ANDROID_PLATFORM = android-16 and higher)
  • OFF (default when ANDROID_PLATFORM = android-15 and lower)

Specifies whether to use position-independent executables (PIE). Android's dynamic linker supports PIE on Android 4.1 (API level 16) and higher.

ANDROID_CPP_FEATURES

This variable is empty by default. However, the following are a few examples of arguments you can pass:

  • rtti (indicates that your code uses RTTI)
  • exceptions (indicates that your code uses C++ exceptions)

Specifies certain C++ features CMake needs to use when compiling your native library, such as RTTI (RunTime Type Information) and C++ exceptions.

ANDROID_ALLOW_UNDEFINED_SYMBOLS
  • TRUE
  • FALSE (default)

Specifies whether to throw an undefined symbol error if CMake encounters an undefined reference while building your native library. To disable these types of errors, set this variable to TRUE.

ANDROID_ARM_MODE
  • arm
  • thumb (default)

Specifies whether to generate ARM target binaries in arm or thumbmode. In thumb mode, each instruction is 16 bits wide and linked with the STL libraries in the thumb/ directory. Passing arm tells CMake to generate your library's object files in 32-bit arm mode.

ANDROID_ARM_NEON
  • TRUE
  • FALSE (default)

Specifies whether CMake should build your native library with NEON support.

ANDROID_DISABLE_NO_EXECUTE
  • TRUE
  • FALSE (default)

Specifies whether to enable NX bit, or No eXecute, security feature. To disable this feature, pass TRUE.

ANDROID_DISABLE_RELRO
  • TRUE
  • FALSE (default)

Specifies whether to enable read-only relocations.

ANDROID_DISABLE_FORMAT_STRING_CHECKS
  • TRUE
  • FALSE (default)

Specifies whether to compile your source code with format string protection. When enabled, the compiler throws an error if a non-constant format string is used in a printf-style function.

Understanding the CMake build command


When debugging CMake build issues, it's helpful to know the specific build arguments that Android Studio uses when cross-compiling for Android.

Android Studio saves the build arguments it uses for executing a CMake build, in a cmake_build_command.txt file. For each Application Binary Interface (ABI) that your app targets, and each build type for those ABIs (namely, release or debug), Android Studio generates a copy of the cmake_build_command.txt file for that specific configuration. Android Studio then places the files it generates in the following directories:

<project-root>/<module-root>/.externalNativeBuild/cmake/<build-type>/<ABI>/

Tip: In Android Studio, you can quickly view these files by using the search keyboard shortcut (shift+shift) and entering cmake_build_command.txtin the input field.

The following snippet shows an example of the CMake arguments to build a debuggable release of the hello-jni sample targeting the armeabi-v7aarchitecture.

Executable : /usr/local/google/home/{$USER}/Android/Sdk/cmake/3.6.3155560/bin/cmakearguments :-H/usr/local/google/home/{$USER}/Dev/github-projects/googlesamples/android-ndk/hello-jni/app/src/main/cpp-B/usr/local/google/home/{$USER}/Dev/github-projects/googlesamples/android-ndk/hello-jni/app/.externalNativeBuild/cmake/arm7Debug/armeabi-v7a-GAndroid Gradle - Ninja-DANDROID_ABI=armeabi-v7a-DANDROID_NDK=/usr/local/google/home/{$USER}/Android/Sdk/ndk-bundle-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=/usr/local/google/home/{$USER}/Dev/github-projects/googlesamples/android-ndk/hello-jni/app/build/intermediates/cmake/arm7/debug/obj/armeabi-v7a-DCMAKE_BUILD_TYPE=Debug-DCMAKE_MAKE_PROGRAM=/usr/local/google/home/{$USER}/Android/Sdk/cmake/3.6.3155560/bin/ninja-DCMAKE_TOOLCHAIN_FILE=/usr/local/google/home/{$USER}/Android/Sdk/ndk-bundle/build/cmake/android.toolchain.cmake-DANDROID_NATIVE_API_LEVEL=23-DANDROID_TOOLCHAIN=clangjvmArgs : 

Build arguments

The following table highlights the key CMake build arguments for Android. These build arguments are not meant to be set by developers. Instead, theAndroid Plugin for Gradle sets these arguments based on the build.gradle configuration in your project.

Build ArgumentsDescription-G <build-system>

Type of build files that CMake generates.

For projects in Android Studio with native code, the <build-system> is set to Android Gradle - Ninja. This setting indicates that CMake uses the ninja build system to compile and link the C/C++ sources for your app. CMake also generates a android_gradle_build.json file which contains metadata for the Gradle plugin about the CMake build such as compiler flags and names of targets.

This setting indicates that CMake uses Gradle together with the ninja build system to compile and link the C/C++ sources for your app. The ninja build system is the only generator that Studio supports.

-DANDROID_ABI <abi>

The target ABI.

The NDK supports a set of ABIs, as described in ABI Management. This option is similar to theAPP_ABI variable that the ndk-build tool uses.

By default, Gradle builds your native library into separate .so files for the ABIs that NDK supports, and then packages them all into your APK. If you want Gradle to build only for certain ABI configurations, follow the instructions in Add C and C++ Code to Your Project.

If the target ABI is not specified, CMake defaults to using armeabi-v7a.

Valid target names are:

  • armeabi: ARMv5TE based CPU with software floating point operations.
  • armeabi-v7a: ARMv7 based devices with hardware FPU instructions (VFPv3_D16).
  • armeabi-v7a with NEON: Same as armeabi-v7a, but enables NEON floating point instructions. This is equivalent to setting -DANDROID_ABI=armeabi-v7a and -DANDROID_ARM_NEON=ON.
  • arm64-v8a: ARMv8 AArch64 instruction set.
  • mips: MIPS32 instruction set (r1).
  • mips64 - MIPS64 instruction set (r6).
  • x86: IA-32 instruction set.
  • x86_64 - Instruction set for the x86-64 architecture.
-DANDROID_NDK <path>Absolute path to the root directory of the NDK installation on your host.-DCMAKE_LIBRARY_OUTPUT_DIRECTORY <path>Location on your host where CMake puts the LIBRARY target files when built.-DCMAKE_BUILD_TYPE <type>Similar to the build types for the ndk-build tool. The valid values are Release and Debug. To simplify debugging, CMake does not strip the release or debug version as part of the build. However, Gradle strips binaries when it packages them in the APK.-DCMAKE_MAKE_PROGRAM <program-name>Tool to launch the native build system. The Gradle plugin sets this value to the CMake ninjagenerator bundled with the Android SDK.-DCMAKE_TOOLCHAIN_FILE <path>Path to the android.toolchain.cmake file that CMake uses for cross-compiling for Android. Typically, this file is located in the $NDK/build/cmake/ directory, where $NDK is the NDK installation directory on your host. For more information about the toolchain file, see Cross Compiling for Android.-DANDROID_NATIVE_API_LEVEL <level>Android API level that CMake compiles for.-DANDROID_TOOLCHAIN <type>The compiler toolchain that CMake uses. Defaults to clang

YASM support in CMake


NDK r15 and higher provides CMake support for building assembly code written in YASM to run on x86 and x86-64 architectures. YASM is an open-source assembler for x86 and x86-64 architectures, based on the NASM assembler.

You may find it useful to link assembly language programs or routines with C code in order to access C libraries or functions from your assembly code. You can also include short assembly routines in your compiled C code to take advantage of the better machine performance that assembly code affords.

To build assembly code with CMake, make the following changes in your project's CMakeLists.txt:

  1. Call enable_language with the value set to ASM_NASM.
  2. Depending on whether you are building a shared library or an executable binary, call add_library or add_executable. In the arguments, pass in a list of source files consisting of the .asm files for the assembly program in YASM and and the .c files for the associated C libraries or functions.

The following snippet shows how you might configure your CMakeLists.txt to build a YASM program as a shared library.

cmake_minimum_required(VERSION 3.6.0)enable_language(ASM_NASM)add_library(test-yasm SHARED jni/test-yasm.c jni/print_hello.asm)

For an example of how to build a YASM program as an executable, see the test-yasm code in the NDK git repository.

Reporting problems


If you run into any issues that aren't due to the open source version of CMake, report them via the android-ndk/ndk issue tracker on GitHub.


独立工具链

本页内容

  1. 选择您的工具链
  2. 选择您的 Sysroot
  3. 调用编译器
  4. 使用 Clang
  5. ABI 兼容性
  6. 警告和限制

您可以独立使用 Android NDK 附带的工具链,或将其作为插件与现有 IDE 结合使用。 如果您已有自己的构建系统,且仅需要调用交叉编译器功能以将对构建系统的支持添加到 Android,则这种灵活性非常有用。

一个典型用例是在 CC 环境变量中调用一个需要交叉编译器的开源库的 configure 脚本。

:本页假设您非常了解编译、链接和低级架构。 此外,对于大多数用例来说本页介绍的技术并不是必需的。 在大多数情况下,我们建议您放弃使用独立工具链,而是坚持使用 NDK 构建系统。

选择您的工具链


首先,您需要决定您的独立工具链将以哪个处理架构为目标。 每个架构均对应不同的工具链名称,如表 1 所示。

表 1. APP_ABI 不同指令集的设置。

架构工具链名称基于 ARMarm-linux-androideabi-<gcc-version>基于 x86x86-<gcc-version>基于 MIPSmipsel-linux-android-<gcc-version>基于 ARM64aarch64-linux-android-<gcc-version>基于 X86-64x86_64-<gcc-version>基于 MIPS64mips64el-linux-android--<gcc-version>

选择您的 Sysroot


接下来您需要做的是定义您的 sysroot(sysroot 是一个包含针对您的目标的系统标头和库的目录)。 如需定义 sysroot,您必须知道原生支持的目标 Android API 级别;可用的原生 API 因 Android API 级别而异。

针对相应 Android API 级别的原生 API 位于 $NDK/platforms/ 下;每个 API 级别目录又包含针对各种 CPU 和架构的子目录。 以下示例显示如何针对 ARM 架构为以 Android 5.0(API 级别 21)为目标的构建定义 sysroot

SYSROOT=$NDK/platforms/android-21/arch-arm
如需了解有关 Android API 级别及其支持的相应原生 API 的详细信息,请参阅 Android NDK 原生 API。

调用编译器


调用编译器的方式有两种。其中一个方法很简单,大部分事务都由构建系统完成。 另一种方法则较为复杂,但提供更多灵活性。

简单方法

最简单的构建方式是直接从命令行调用相应的编译器,使用 --sysroot 选项指明您的目标平台的系统文件位置。 例如:

export CC="$NDK/toolchains/arm-linux-androideabi-4.8/prebuilt/ \linux-x86/bin/arm-linux-androideabi-gcc-4.8 --sysroot=$SYSROOT"$CC -o foo.o -c foo.c

尽管此方法很简单,但它缺少灵活性:它不允许您使用任何 C++ STL(STLport、libc++ 或 GNU libstdc++)。 它也不支持例外或 RTTI。

对于 Clang,您需要执行两个额外的步骤:

    1. 为目标架构添加适合的 -target,如表 2 所示。

      表 2. 架构和对应的 -target 的值。

      架构值armeabi-target armv5te-none-linux-androideabiarmeabi-v7a-target armv7-none-linux-androideabiarm64-v8a-target aarch64-none-linux-androidx86-target i686-none-linux-androidx86_64-target x86_64-none-linux-androidmips-target mipsel-none-linux-android
    2. 通过添加 -gcc-toolchain 选项添加汇编程序和链接器支持,如以下示例所示:
      -gcc-toolchain $NDK/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64
    最终,一个使用 Clang 进行编译的命令可能如下所示:
    export CC="$NDK/toolchains/arm-linux-androideabi-4.8/prebuilt/ \linux-x86/bin/arm-linux-androideabi-gcc-4.8 --sysroot=$SYSROOT" -target \armv7-none-linux-androideabi \-gcc-toolchain $NDK/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64"$CC -o foo.o -c foo.c

高级方法

NDK 提供 make-standalone-toolchain.sh shell 脚本以允许您从命令行执行定制的工具链安装。 与简单方法中所述的程序相比,此方法为您提供更多灵活性。

脚本位于 $NDK/build/tools/ 目录中,其中 $NDK 是 NDK 的安装根目录。 下面展示了使用此脚本的示例:

$NDK/build/tools/make-standalone-toolchain.sh \--arch=arm --platform=android-21 --install-dir=/tmp/my-android-toolchain

此命令创建一个名为 /tmp/my-android-toolchain/ 的目录,包含一个 android-21/arch-arm sysroot 的副本,以及适用于 32 位 ARM 架构的工具链二进制文件的副本。

请注意,工具链二进制文件不依赖或包含主机特有的路径,换句话说,您可以将它们安装在任意位置中,甚至移动它们(如果需要)。

默认情况下,构建系统使用 32 位、基于 ARM 的 GCC 4.8 工具链。不过,您可以通过将 --arch=<toolchain> 指定为选项来指定一个不同的值。表 3 显示将用于其他工具链的值:

表 3. 工具链和对应的值,使用 --arch

工具链值mips64 编译器--arch=mips64mips GCC 4.8 编译器--arch=mipsx86 GCC 4.8 编译器--arch=x86x86_64 GCC 4.8 编译器--arch=x86_64mips GCC 4.8 编译器--arch=mips

或者,您可以使用 --toolchain=<toolchain> 选项。表 4 显示您可以为 <toolchain> 指定的值:

表 4. 工具链和对应的值,使用 --toolchain.

工具链值arm
  • --toolchain=arm-linux-androideabi-4.8
  • --toolchain=arm-linux-androideabi-4.9
  • --toolchain=arm-linux-android-clang3.5
  • --toolchain=arm-linux-android-clang3.6
  • x86
  • --toolchain=x86-linux-android-4.8
  • --toolchain=x86-linux-android-4.9
  • --toolchain=x86-linux-android-clang3.5
  • --toolchain=x86-linux-android-clang3.6
  • mips
  • --toolchain=mips-linux-android-4.8
  • --toolchain=mips-linux-android-4.9
  • --toolchain=mips-linux-android-clang3.5
  • --toolchain=mips-linux-android-clang3.6
  • arm64
  • --toolchain=aarch64-linux-android-4.9
  • --toolchain=aarch64-linux-android-clang3.5
  • --toolchain=aarch64-linux-android-clang3.6
  • x86_64
  • --toolchain=x86_64-linux-android-4.9
  • --toolchain=x86_64-linux-android-clang3.5
  • --toolchain=x86_64-linux-android-clang3.6
  • mips64
  • --toolchain=mips64el-linux-android-4.9
  • --toolchain=mips64el-linux-android-clang3.5
  • --toolchain=mips64el-linux-android-clang3.6
  • 注:表 4 并不是一个详尽的列表。其他组合可能也有效,但未经验证。

    您也可以使用以下两种方法之一复制 Clang/LLVM 3.6:您可以将 -clang3.6 附加到 --toolchain 选项,以便 --toolchain 选项看上去如以下示例所示:

    --toolchain=arm-linux-androideabi-clang3.6

    您也可以在命令行上添加 -llvm-version=3.6 作为单独的选项。

    注:无需指定特定版本,您也可以使用 <version>,其默认使用可用的 Clang 最高版本。

    默认情况下,构建系统针对 32 位主机工具链进行构建。您可以指定一个 64 位主机链代替它。 表 5 显示针对不同平台将与 -system 一起使用的值。

    表 5. 主机工具链和对应的值,使用 -system

    主机工具链值64 位 Linux-system=linux-x86_6464 位 MacOSX-system=darwin-x86_6464 位 Windows-system=windows-x86_64如需了解有关指定 64 或 32 位指令主机工具链的详细信息,请参阅 64 位和 32 位工具链。

    您可以指定 --stl=stlport 以复制 libstlport,而不是使用默认的 libgnustl。 如果您执行此操作并想链接共享库,则必须以显式方式使用 -lstlport_shared。 此要求与必须为 GNU libstdc++ 使用 -lgnustl_shared 相似。

    同样,您可以指定 --stl=libc++ 复制 LLVM libc++ 标头和库。如需链接共享库,您必须以显式方式使用 -lc++_shared。

    您可以直接进行这些设置,如以下示例所示:

    export PATH=/tmp/my-android-toolchain/bin:$PATHexport CC=arm-linux-androideabi-gcc   # or export CC=clangexport CXX=arm-linux-androideabi-g++  # or export CXX=clang++

    请注意,如果您忽略 -install-dir 选项,则 make-standalone-toolchain.sh shell 脚本在 tmp/ndk/<toolchain-name>.tar.bz2 中创建一个 tarball。 此 tarball 让您可以轻松存档和重新分发二进制文件。

    此独立工具链还提供了一个额外优势,即:它包含一个 C++ STL 库的工作中副本以及工作中例外和 RTTI 支持。

    如需了解更多选项和详细信息,请使用 --help

    使用 Clang


    您可以使用 --llvm-version=<version> 选项在独立安装中安装 Clang 二进制文件。<version> 是 LLVM/Clang 版本号,如 3.5 或 3.6。 例如:

    build/tools/make-standalone-toolchain.sh \--install-dir=/tmp/mydir \--toolchain=arm-linux-androideabi-4.8 \--llvm-version=3.6

    请注意,Clang 二进制文件与 GCC 二进制文件一起复制,因为它们依赖于相同的汇编程序、链接器、标头、库以及 C++ STL 实现。

    此操作也将在 <install-dir>/bin/@ 下安装两个名为 clang 和 clang++ 的脚本。 这些脚本使用默认目标架构标志调用真实的 clang 二进制文件。 换句话说,它们无需任何修改就能运行,并且您只需设置指向它们的 CC CXX 环境变量就可以在您自己的构建中使用它们。

    调用 Clang

    在一个使用 llvm-version=3.6 构建的 ARM 独立安装中,在 Unix 系统上调用 Clang 采用单行形式。 例如:

    `dirname $0`/clang36 -target armv5te-none-linux-androideabi "$@"

    clang++ 以相同方式调用 clang++31

    Clang 以 ARM 为目标

    针对 ARM 进行构建时,Clang 基于是否存在 -march=armv7-a 和/或 -mthumb 选项更改目标:

    表 5. 可指定的 -march 值及其生成的目标。

    -march 值生成的目标-march=armv7-aarmv7-none-linux-androideabi-mthumbthumb-none-linux-androideabi-march=armv7-a 和 -mthumbthumbv7-none-linux-androideabi

    如果您希望,您也可以替换为您自己的 -target

    -gcc-toolchain 选项不是必需的,因为在独立软件包中,Clang 在预定义的相对位置中查找 as 和 ld

    clang 和 clang++ 应能够轻松替换 makefile 中的 gcc 和 g++。 如有疑问,添加下列选项以验证他们是否正确运行。

    • -v,用于转储与编译器驱动程序问题有关的命令
    • -###,用于转储命令行选项,包括以隐式方式预定义的选项。
    • -x c < /dev/null -dM -E,用于转储预定义的预处理器定义
    • -save-temps,用于比较 *.i 或 *.ii 预处理文件。

    如需了解有关 Clang 的详细信息,请参阅 http://clang.llvm.org/,尤其是 GCC 兼容性部分。

    ABI 兼容性


    默认情况下,ARM 工具链生成的机器代码应与官方 Android armeabi ABI 兼容。

    我们建议使用 -mthumb 编译器标志以强制生成 16 位 Thumb-1 指令(默认成为 32 位 ARM 指令)。

    如果您要以 armeabi-v7a ABI 为目标,则必须设置下列标志:

    CFLAGS= -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16

    第一个标志启用 Thumb-2 指令。第二个标志启用硬件 FPU 指令,同时确保系统在核心寄存器中传递浮点参数,这对于 ABI 兼容性至关重要。

    注:在 r9b 以前的 NDK 版本中,请勿单独使用这些标志。 您必须同时设置所有标志或一个都不设置。否则,可能导致无法预测的行为和崩溃。

    如需使用 NEON 指令,您必须更改 -mfpu 编译器标志:

    CFLAGS= -march=armv7-a -mfloat-abi=softfp -mfpu=neon

    请注意,按照 ARM 规范,此设置强制使用 VFPv3-D32

    另外,确保向链接器提供以下两个标志:

    LDFLAGS= -march=armv7-a -Wl,--fix-cortex-a8

    第一个标志指示链接器选取为 armv7-a 定制的 libgcc.alibgcov.a 和 crt*.o。 在某些 Cortex-A8 实现中,需要第二个标志作为 CPU 错误的解决方法。

    自 NDK 版本 r9b 开始,获取或返回双精度值或浮点值的所有 Android 原生 API 都具有用于 ARM 的 attribute((pcs("aapcs")))。 这让您可以在 -mhard-float(其表示 -mfloat-abi=hard)中编译用户代码,并仍与符合 softfp ABI 的 Android 原生 API 关联。 如需了解有关此操作的详细信息,请参阅 $NDK/tests/device/hard-float/jni/Android.mk 中的注释。

    如果您要在 x86 上使用 NEON intrinsics,构建系统可以使用与标准 ARM NEON 内联函数标头具有相同名称 arm_neon.h 的特殊 C/C++ 语言标头将它们转换为原生 x86 SSE 内联函数。

    默认情况下,x86 ABI 最大支持 SIMD 的 SSSE3,且标头涵盖 NEON 函数的 93% 左右(1869 个(总数为 2009 个))。

    如果以 MIPS ABI 为目标,您不必使用任何特定的编译器标志。

    如需有关 ABI 支持的详细信息,请参阅 x86 支持。

    警告和限制


    Windows 支持

    Windows 二进制文件不依赖于 Cygwin。这种独立性让它们的运行速度更快。不过,代价是它们不理解 Cygwin 路径规范,如 cygdrive/c/foo/bar,但可以理解 C:/foo/bar

    NDK 构建系统确保所有从 Cygwin 传递到编译器的路径可自动转换,同时管理其他复杂性。 如果您有自定义构建系统,您可能需要自己解决这些复杂性。

    如需有关为 Cygwin/MSys 贡献支持的信息,请访问 android-ndk 论坛。

    wchar_t 支持

    Android 平台在 Android 2.3(API 级别 9)之前并没有真正地支持 wchar_t。这种情况产生多个结果:

    • 如果您的目标平台为 Android 2.3 或更高版本,则 wchar_t 的大小为 4 字节,且大多数 wide-char 函数可在 C 库中获取(多字节编码/解码函数和 wsprintf/wsscanf 除外)。
    • 如果您以任意较低的 API 级别为目标,则 wchar_t 的大小为 1 字节,且任何 wide-char 函数均无法运行。

    我们建议您不要依赖 wchar_t 类型,并改用更好的表示形式。 Android 中提供的此支持目的只是为了帮助您迁移现有代码。

    例外、RTTI 和 STL

    默认情况下,工具链二进制文件支持 C++ 例外和 RTTI。在构建源时,如需停用 C++ 例外和 RTTI(例如,为了生成更轻量的机器代码),则使用 -fno-exceptions 和 -fno-rtti

    如需将这些功能与 GNU libstdc++ 结合使用,您必须以显式方式与 libsupc++ 进行关联。为此,链接二进制文件时请使用 -lsupc++。 例如:

    arm-linux-androideabi-g++ .... -lsupc++

    如果使用 STLport 或 libc++ 库,那么您不需要执行此操作。

    C++ STL 支持

    独立工具链包含一个 C++ 标准模板库实现的副本。此实现适用于 GNU libstdc++、STLport 或 libc++,具体取决于您为前面所述的 --stl=<name> 选项所指定的内容。 如需使用这个 STL 实现,您需要将您的项目与正确的库进行关联:

    • 使用 -lstdc++ 以链接任意实现的静态库版本。这样做可确保将所有必需的 C++ STL 代码添加到您最终的二进制文件。 如果您仅生成一个共享库或可执行文件,则此方法为理想之选。

      这是我们建议的方法。

    • 替代方法是使用 -lgnustl_shared 链接 GNU libstdc++ 的共享库版本。 如果您使用此选项,您还必须确保将 libgnustl_shared.so 复制到您的设备以正确加载您的代码。 表 6 显示对于每个工具链类型此文件的位置。

      注:GNU libstdc++ 依据 GPLv3 许可证授权,具有一个链接例外。 如果您不能符合其要求,则无法在您的项目中重新分发共享库。

    • 使用 -lstlport_shared 链接 STLport 的共享库版本。如果您这样做,您需要确保您也将 libstlport_shared.so 复制到您的设备以正确加载您的代码。 表 6 显示对于每个工具链此文件的位置:

      Table 6. 可指定的 -march 值及其生成的目标。

      工具链位置arm$TOOLCHAIN/arm-linux-androideabi/lib/arm64$TOOLCHAIN/aarch64-linux-android/lib/x86$TOOLCHAIN/i686-linux-android/lib/x86_64$TOOLCHAIN/x86_64-linux-android/lib/mips$TOOLCHAIN/mipsel-linux-android/lib/mips64$TOOLCHAIN/mips64el-linux-android/lib/

      注:如果您的项目包含多个共享库或可执行文件,那么,您必须链接一个共享库 STL 实现。 否则,此构建系统不会定义特定的全局唯一性,从而导致不可预测的运行时行为。此行为可能包括崩溃和未能正确捕捉异常。

      这些库不只是称为 libstdc++.so 的原因是此名称在运行时与系统自身的最小 C++ 运行时冲突。 为此,构建系统强制为 GNU ELF 库指定一个新名称。 静态库没有这个问题。