NDK构建

ndk-build

ndk-build是NDK基于Make构建系统的构建命令

这个脚本通过Android.mkApplication.mk来配置

ndk-build等同于以下命令

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

GNUMAKE指的是GNU Make 3.81或之后的版本,<ndk>指的是NDK构建目录

命令选项

1
$ ndk-build clean

移除之前构建的二进制

1
V=1

启动构建,并显示构建命令。

1
-B

强制完成重建。

1
-B V=1

强制完成重建,并显示构建命令。

1
NDK_LOG=1

显示内部NDK日志消息(用于调试NDK本身)。

1
NDK_DEBUG=1

强制debug构建(参见表1)。

1
NDK_DEBUG=0

强制release构建(参见表1)。

1
NDK_HOST_32BIT=1

始终在32位模式下使用工具链(请参阅64位和32位工具链)。

1
NDK_APPLICATION_MK=<file>

使用NDK_APPLICATION_MK变量指向的特定Application.mk文件

1
-C <project>

的项目路径构建本机代码.

在使用该NDK_DEBUG选项的情况下, AndroidManifest.xml可以指定调试或发布版本,与优化相关的行为以及符号的包含

Manifest 设置 NDK_DEBUG=0 NDK_DEBUG=1 NDK_DEBUG 未指定
android:debuggable=”true” Debug; Symbols; Optimized*1 Debug; Symbols; Not optimized*2 (same as NDK_DEBUG=1)
android:debuggable=”false” Release; Symbols; Optimized Release; Symbols; Not optimized Release; No symbols; Optimized*3

AndroidManifest.xml中:

  • NDK_DEBUG=0 等同于 APP_OPTIM=release

  • NDK_DEBUG=1 等同于APP_OPTIM=debug

64-Bit和32-Bit工具链的配置

大部分工具链都有32和64位的版本,

<ndk>/toolchain/<name>/prebuilt/<ndk>/prebuilt/可能都包含linux-x86linux-x86_64两个文件大

如果操作系统支持64位的话,那么会默认选择64位,你可以在ndk-build或者是配置中强制选择32位工具链

1
NDK_HOST_32BIT=1

Android.mk

Android.mkjni/目录下,标识了构建系统的资源和库

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

1
LOCAL_PATH := $(call my-dir)

这个属性表示在开发目录中的资源文件,通过构建系统,返回当前目录的路径

然后是声明CLEAR_VARS,由构建系统提供的值

1
include $(CLEAR_VARS)

LOCAL_MODULE

1
LOCAL_MODULE := hello-jni

这个是model的名称,构建系统会为其自动添加前缀和后缀比如这个就会变为libhello-jni.so

LOCAL_SRC_FILES

1
LOCAL_SRC_FILES := hello-jni.c

枚举源文件,其中空格分隔多个文件:

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

BUILD_SHARED_LIBRARY

1
include $(BUILD_SHARED_LIBRARY)

BUILD_SHARED_LIBRARY变量指向GNU Makefile脚本,该脚本收集您在LOCAL_XXX最近的变量中定义的所有include`信息

变量和宏

构建系统提供了许多可能在Android.mk文件中使用的变量。也可以自己定义,但是注意不要使用以下这些

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

建议使用MY_去定义这些

NDK定义的包含变量

这个意思是构建系统在解析咱们的Android.mk变量之前定义的GNU Make定义的变量

NDK可能多次解析咱们的Android.mk变量,每次都使用不同的定义.

CLEAR_VARS

此变量指向一个构建脚本,改脚本取消"Developer-defined variables"之下所有类似于LOCAL_XXX的变量

1
include $(CLEAR_VARS)

BUILD_SHARED_LIBRARY

此变量指向构建脚本,该脚本收集有关您在LOCAL_XXX变量中提供的模块的所有信息,并确定如何从列出的资源构建目标共享库

1
include $(BUILD_SHARED_LIBRARY)

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

其变体BUILD_SHARED_LIBRARY用于构建静态库。

1
include $(BUILD_STATIC_LIBRARY)

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

PREBUILT_SHARED_LIBRARY

指向用于指定预构建共享库的构建脚本,与BUILD_SHARED_LIBRARYBUILD_STATIC_LIBRARY的情况不同,LOCAL_SRC_FILES不能是资源文件,它必须是预先构建的共享库的单一路径,例如foo/libfoo.so

1
include $(PREBUILT_SHARED_LIBRARY)

PREBUILT_STATIC_LIBRARY

PREBUILT_SHARED_LIBRARY一样,但是是预构建静态共享库

目标信息变量

构建系统Android.mk根据APP_ABI 变量指定的ABI 解析一次,如果APP_ABIall,则构建系统Android.mk按NDK支持的每个ABI 解析一次。

TARGET_ARCH

构建系统在解析此Android.mk 文件时所针对的CPU系列。值是armarm64x86,或x86_64

TARGET_PLATFORM

建系统在解析此Android.mk文件时所针对的Android API级别编号

使用方法:

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

TARGET_ARCH_ABI

构建系统在解析此Android.mk文件时所针对的ABI

CPU and architecture Setting
ARMv7 armeabi-v7a
ARMv8 AArch64 arm64-v8a
i686 x86
x86-64 x86_64

使用方法:

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

TARGET_ABI

目标Android API级别和ABI的串联。

使用方法:

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

模块描述变量

Module-Description Variables

  1. CLEAR_VARS变量初始化变量相信
  2. 将值分配给用于描述模块的变量。
  3. 使用BUILD_XXX变量将NDK构建系统设置为使用模块的相应构建脚本。

LOCAL_PATH

此变量用于提供当前文件的路径。

1
LOCAL_PATH := $(call my-dir)

CLEAR_VARS的脚本不会清除此变量。因此只需要定义一次

LOCAL_MODULE

此变量存储模块的名称。

  • 它在所有模块名称中必须是唯一的,并且不得包含任何空格。

  • 必须在包含任何脚本之前定义它

1
LOCAL_MODULE := "foo"

LOCAL_MODULE_FILENAME

此可选变量允许您覆盖构建系统默认为其生成的文件使用的名称。

例如,如果您的名称 LOCAL_MODULEfoo,则可以强制系统调用它生成的文件 libnewfoo:

1
2
LOCAL_MODULE := foo
LOCAL_MODULE_FILENAME := libnewfoo

LOCAL_SRC_FILES

此变量包含构建系统用于生成模块的源文件列表。

可以使用LOCAL_PATH来改变绝对路径,使其更具移植性

LOCAL_CPP_EXTENSION

您可以使用此可选变量来指示除.cppC ++源文件之外的文件扩展名 。

例如,以下行将扩展名更改为.cxx

1
LOCAL_CPP_EXTENSION := .cxx

也可以指定多个扩展名

1
LOCAL_CPP_EXTENSION := .cxx .cpp .cc

LOCAL_CPP_FEATURES

您可以使用此可选变量来指示您的代码依赖于特定的C ++功能。

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

1
LOCAL_CPP_FEATURES := rtti

要表明您的代码使用C ++异常:

1
LOCAL_CPP_FEATURES := exceptions

多个同时使用:

1
LOCAL_CPP_FEATURES := rtti features

LOCAL_C_INCLUDES

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

1
LOCAL_C_INCLUDES := sources/foo

或者

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

LOCAL_CFLAGS

此可选变量在构建C C ++源文件时为构建系统设置编译器标志。

1
LOCAL_CFLAGS += -I<path>,

LOCAL_CPPFLAGS

一组可选的编译器标志,在构建C ++源文件时传递。在LOCAL_CFLAGS之后定义

LOCAL_STATIC_LIBRARIES

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

LOCAL_SHARED_LIBRARIES

此变量是此模块在运行时所依赖的共享库模块的列表。

LOCAL_WHOLE_STATIC_LIBRARIES

此变量是LOCAL_STATIC_LIBRARIES的变量,并表示链接器应将关联的库模块视为整个文档。

LOCAL_LDLIBS

变量包含用于构建共享库或可执行文件的其他链接器标志的列表。

可以使用-l前缀来传递特定系统库的名称。

如告诉链接器链接到/system/lib/libz.so

1
LOCAL_LDLIBS := -lz

LOCAL_LDFLAGS

构建系统在构建共享库或可执行文件时使用的其他链接器标志的列表

1
LOCAL_LDFLAGS += -fuse-ld=bfd

LOCAL_ARM_MODE

默认情况下,构建系统以thumb模式生成ARM目标二进制文件,其中每条指令都是16位宽,并与thumb/目录中的STL库链接 ,定义此变量会arm强制构建系统以32位arm模式生成模块的目标文件。

1
LOCAL_ARM_MODE := arm

也可以指定文件

1
LOCAL_SRC_FILES := foo.c bar.c.arm

LOCAL_ARM_NEON

此变量仅在您定位armeabi-v7aABI 时才有意义。它允许在C和C ++源代码中使用ARM Advanced SIMD(NEON)编译器内在函数,以及在汇编文件中使用NEON指令。

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

LOCAL_EXPORT_CFLAGS

此变量记录一组C / C ++编译器标志,

LOCAL_EXPORT_CPPFLAGS

NDK提供的函数宏

my-dir

该宏返回最后包含的makefile的路径,该文件通常是当前Android.mk的目录。

例如:

1
LOCAL_PATH := $(call my-dir)

all-subdir-makefiles

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

this-makefile

返回当前makefile的路径

parent-makefile

返回包含树中的父makefile的路径

grand-parent-makefile

返回包含树中祖父项makefile的路径

import-module

一种功能,允许您通过模块Android.mk名称查找和包含模块的文件。如:

1
$(call import-module,<name>)

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

Application.mk

Application.mk文件在$PROJECT/jni/定义了几个在GNU Makefile 中用于编译的变量

另一种方法是将它放在顶级$NDK/apps/ 目录的子目录下。例如:

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

<myapp>是一个简短的名称,用于描述NDK构建系统的应用程序。它实际上并不会生成您生成的共享库或最终包。

APP_PROJECT_PATH

此变量存储应用程序项目根目录的绝对路径。

如果放置Application.mk文件$NDK/apps/<myapp>/,则必须定义此变量。如果放置它$PROJECT/jni/,它是可选的。

APP_MODULES

如果定义了这个变量,它会告诉ndk-build你只构建相应的模块和它们所依赖的模块。和出现在Android.mk文件中的LOCAL_MODULE 一样它必须是以空格分隔的模块名列表。

如果变量未定义,则ndk-build查找所有可安装顶级模块的列表,即Android.mk文件列出的模块及其直接包含的任何文件。

如果变量未定义,并且项目中没有可安装的顶级模块,则ndk-build构建所有顶级静态库及其依赖项

这些库放在obj/obj-debug/下面。

可安装模块是共享库或可执行文件,将会在libs/$ABI/中生成一个文件

APP_OPTIM

这个变量有两个选项debug或者release

release是默认选项,生成优化的二进制文件,debug模式生成未优化的二进制文件,更利于调试

android:debuggable在应用程序清单<application> 标记中声明将导致此变量默认为debug而不是release

APP_CFLAGS

此变量存储一组C编译器标志,可以使用此变量根据需要的应用程序更改给定模块的构建,而不必修改Android.mk文件本身。使用APP_CPPFLAGS只可以指定C ++的标志。

这些标志中的所有路径都应该相对于顶级NDK目录,如你有以下设置:

1
2
sources/foo/Android.mk
sources/bar/Android.mk

那么在编译期间要指定bar的路径到foo/Android.mk需要添加:

1
APP_CFLAGS += -Isources/bar

或者是:

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

-I../bar不会起作用它相当于-I$NDK_ROOT/../bar

APP_CPPFLAGS

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

APP_LDFLAGS

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

APP_BUILD_SCRIPT

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

如果要覆盖此行为,可以定义APP_BUILD_SCRIPT为指向备用生成脚本。

APP_ABI

默认情况下,NDK构建系统为所有未弃用的ABI生成机器代码。您可以使用该APP_ABI设置为特定ABI生成机器代码。

指令系统
基于ARMv7的设备上的硬件FPU指令 APP_ABI := armeabi-v7a
ARMv8 AArch64 APP_ABI := arm64-v8a
IA-32 APP_ABI := x86
Intel64 APP_ABI:= x86_64
所有支持的指令集 APP_ABI := all

也可以指定多个

1
APP_ABI := armeabi-v7a arm64-v8a x86

如果在gradle中配置了那么这个就不生效了

APP_PLATFORM

支持的最低android版本如android-15

如果在gradle中配置了最小版本,则取两个之中最大的来用

APP_SHORT_COMMANDS

为此项目中所有的Android.mk设置LOCAL_SHORT_COMMANDS

APP_THIN_ARCHIVE

为此项目中的所有静态库模块设置Android.mk中的LOCAL_THIN_ARCHIVE

ABI

不同的Android手机使用不同的CPU,这反过来支持不同的指令集。CPU和指令集的每个组合都有自己的应用程序二进制接口ABI,在NDK开发中必须为希望应用程序使用的每个CPU体系结构指定ABI。

通常ABI包括以下信息:

  • 机器代码应使用的CPU指令集。
  • 内存的字节顺序在运行时存储和加载。
  • 可执行二进制文件的格式,例如程序和共享库,以及它们支持的内容类型。
  • 在代码和系统之间传递数据的各种约定。这些约定包括对齐约束,以及系统在调用函数时如何使用堆栈和寄存器。
  • 机器代码在运行时可用的功能符号列表,通常来自非常特定的库集。

支持的ABI

ABI Supported Instruction Set(s) Notes
armeabi ARMV5TE and later
Thumb-1
在r16中弃用。在r17删除
armeabi-v7a armeabi
Thumb-2
VFPv3-D16
Other, optional
与ARMv5,v6设备不兼容。
arm64-v8a AArch64
x86 x86 (IA-32)
MMX
SSE/2/3
SSSE3
不支持MOVBE或SSE4。
x86_64 x86-64
MMX
SSE/2/3
SSSE3
SSE4.1, 4.2
POPCNT

参考

jni例子

官方文档

谢谢您的鼓励~