首页 > Coding > 多语言编程之 C and Java: Android NDK

多语言编程之 C and Java: Android NDK

2016年7月11日 发表评论 阅读评论

NDK(Native Debelopment Kit) 是 Android 提供的一个工具集,它允许在 Android app 使用 native 代码(C/CPP). 它集成了交叉编译器, 使用 mk 文件对平台、CPU 等进行隔离。在不同的平台下,只需要配置相应的 mk 文件即可以编译相就的模块。

1 NDK project 基本结构

ndkprojectFoloer

 

 

 

 

 

2 Android.mk

Android.mk 文件存在于工程路径中的 jni/ 路径下。它可以看作是 GNUMakefile 的一部分,用来向编译器描述如何从 native 源码构建共享库(动态库)。
Android.mk 可以将源码分成不同的模块。这些 模块 可以是静态库、共享库(甚至是可执行文件)。静态库用来生成共享库,共享库则会和 app 打包。

2.1 基础

  • LOCAL_PATH Android.mk 文件必须以此变量开始:

LOCAL_PATH := $(call my-dir)

该变量表明源文件的位置。此处的 my-dir 由编译器提供,返回当前路径(Android.mk所在的路径)

  • CLEAR_VARS 该变量一般在第二行声明。此变量仍由编译器提供

include $(CLEAR_VARS)

该变量指向一个特殊的 GNUMakefile ,用来清理除了 LOCAL_PATH 以外的 LOCAL_xxx 变量,如 LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES 等。

  • LOCAL_MODULE 变量:

LOCAL_MODULE := <module-name>

该变量用于定义将要编译的模块名称。该名称必须是唯一的。编译器会以此命名最终生成的模块文件,如:该变量为 gdal, 则生成的共享库名为 libgdal.so 。值得注意的是,不需要为模块名添加 lib 前缀,编译器会自动添加 lib 前缀和 so 后缀。编译器会自动检测模块名是否已经添加了前缀,如果已添加,则编译器在生成模块文件时不会再次添加。

  • LOCAL_SRC_FILE 变量用于指定要编译的源文件。多个文件间用空格区分

LOCAL_SRC_FILE := sourcefile.c sfile.cpp

另外也可以使用 LOCAL_CPP_EXTENSION 来定义不同的 c++ 扩展名,其值以点符号开始,如 .hpp 。

  • BUILD_SHARED_LIBRARYBUILD_STATIC_LIBRARY

include $(BUILD_SHARED_LIBRARY)

该变量指向一个 GNUmakefile ,负责收集在 Android.mk 中从 'include $(CLEAR_VARS)' 到该变量之间所有的 LOCAL_XXX 的变量值。它将最终确定生成模块是什么,并确定如何生成它。

2.2 宏与变量

编译器为 Android.mk 提供了很多变量,大部分变量都已经有预分配的值,当然你也可以重新指定值 。
你也可以定义自己的变量。当你使用自定义变量名时,需要注意, NDK 编译器保留了如下变量名:

  • 以 LOCAL_ 开头的变量名。如 LOCAL_MODULE
  • 以 PROVATE_, NDK_ 或 APP 开头的变量名。编译器内部会有使用
  • 小写的变量名。如 my_dir.依旧会在编译器内部使用

2.3 NDK 定义的变量

  • CLEAR_VARS 见前文
  • BUILD_SHARED_LIBRARY / BUILD_STATIC_LIBRARY 见前文
  • PREBUILT_SHARED_LIBRARY / PREBUILT_STATIC_LIBRARY 指向一个预编译库的编译脚本。其 LOCAL_SRC_FILE 的值必须指向一个动态库或静态库
  • TARGET_ARCH Android 指定的目标 CPU 架构的名称。如果是 ARM 兼容 CPU, 则名称为 arm .其它平台参见 TARGET_ARCH_ABI
  • TARGET_PLATFORM 指定的 Android API 版本。例如, Android 5.1 系统镜像对应的 API 版本为 22

TARGET_PLATFORM := android-22

  • TARGET_ARCH_ABI 目标 CPU + ABI 的名称。可以有一个或多个值。

TARGET_ARCH_ABI := arm64-v8a

参见下表:

Table 1: CPU 架构变量值
CPU 平台和架构 变量值
ARMv5TE armeabi
ARMv7 armeabi-v7a
ARMv8 AArch64 arm64-v8a
i686 x89
x86-64 x86-64
mips32 mips
mips64 mips64
All all
  • TARGET_ABI Android API 版本与 ABI 联合的名称。如

TARGET_ABI := android-22-ar,64-v8a

2.4 DNK 定义的方法宏

  • my-dir 见前文
  • all-subdir-makefiles 返回 my-dir 下所有包含 Android.mk 的子目录
  • this-makefile 返回当前 makefile 所在的目录
  • parent-makefile 返回上一层 makefile 所在目录
  • grand-parent-makefile 返回上两层 makefile 所在的目录
  • import-module 通过模块名找到另一个模块的 Android.mk 文件所在的目录.一个典型的用例如下:

$(call import-modules,<name>)

  • 这将在环境参数NDK_MODULE_PATH所定义的目录下通过模块名<name>寻找Android.mk所在的目录

2.5 模块描述变量

  • LCOAL_PATH 见前文
  • LOCAL_MODULE 见前文
  • LOCAL_MODULE_FILENAME 可以重新定义生成文件的文件名。默认情况下会生成 lib<LOCAL_MODULE>.so ,但可以通过此变量自定义文件名.(不需要定义扩展名)
  • LOCAL_SRC_FILES 见前文
  • LOCAL_CPP_EXTENSION 见前文
  • LOCAL_CPP_FEATURES 可选变量,指定 C++ 代码所依赖指定的 C++ 特性。例如:

LOCAL_CPP_FEATURES := rtti exceptions

  • LOCAL_C_INCLUDES 可选变量,指定头文件所有路径
  • LOCAL_CFLAGS
  • LOCAL_CPPFLAGS
  • LOCAL_STATIC_LIBRARIES 编译所依赖的共享库
  • LOCAL_SHARED_LIBRARIES 编译所依赖的静态库
  • LOCAL_WHOLE_STATIC_LIBRARIES
  • LOCAL_LDLIBS 用于额外的链接选项。
  • LOCAL_LDFLAGS
  • LOCAL_ALLOW_UNDEFINED_SYMBOLS 允许使用未定义的变量
  • LOCAL_ARM_MODE 默认情况下,ARM目标二进制文件将会以 thumb 模式生成(16位指令),你可以将此变量设置为 arm,生成目标文件时将以 arm 模式生成(32位指令)。
  • LOCAL_ARM_NEON 此变量设置为"true"的话,将允许你在C/C++中使用ARM 高级 SIMD (a.k.a. NEON) GCC intrinsics,就像汇编文件中的NEON指令.只有在使用'armeabi-v7a' ABI时使用此变量,注意不是所有的 基于armv7的CPU支持NEON指令集
  • LOCAL_DISABLE_NO_EXECUTE Android NDK r4添加了支持"NX bit"的安全特性。在默认情况下此特性被激活,如果你不需要它,那么将此变量设置为"true"即可.
  • LOCAL_DISABLE_RELRO
  • LOCAL_DISABLE_FORMAT_STRING_CHECKS
  • LOCAL_EXPORT_CFLAGS C/C++编译选项
  • LOCAL_EXPORT_CPPFLAGS C++ 编译选项
  • LOCAL_EXPORT_C_INCLUDES 与LOCAL_EXPORT_CFLAGS相同,只不过用于C的包含路径.
  • LOCAL_EXPORT_LDFLAGS
  • LOCAL_EXPORT_LDLIBS 与LOCAL_EXPORT_CFLAGS相同,只不过用于链接选项.注:被导入的链接选项将会加入在变量LOCAL_LDLIBS定义的选项之前.

3 Applocation.mk

3.1 概述

Application.mk 用于描述 native 模块(共享库、静态库或可执行文件)。它作为 GNUMakefile 的一部分,通常放在工程路径下的 jni 文件夹中。

3.2 变量

  • APP_PROJECT_PATH 存储工程的绝对路径。当 Application.mk 文件在 jni 目录下时,此变量是可选的。
  • APP_OPTIM 此变量指定编译优化方式 ,值可以是 release 或 debug.缺省值为 release.
  • APP_CFLAGS 该变量用于存储 C 编译器的选项。它用在此处可以替换在 Android.mk 中定义的选项。如果为添加选项,则可以使用 += 添加来添加定义。
  • APP_CPPFLAGS 同上。用于 C++
  • APP_LDFLAGS 同上。
  • APP_BUILD_SCRIPT 缺省值指向 jni 目录下的 Android.mk 文件
  • APP_ABI 参见 TARGET_ARCH_ABI
  • APP_PLATFORM 参见 TARGET_PLATFORM
  • APP_STL 默认发问下,NDK 编译器提供了最小化的 C++ runtime library(system/lib/libstdc++.so),包括头文件。使用此变量可以指定其他 runtime:
    Name Explanation Features
    libstdc++ (default) The default minimal system C++ runtime library. N/A
    gabi++_static The GAbi++ runtime (static). C++ Exceptions and RTTI
    gabi++_shared The GAbi++ runtime (shared). C++ Exceptions and RTTI
    stlport_static The STLport runtime (static). C++ Exceptions and RTTI; Standard Library
    stlport_shared The STLport runtime (shared). C++ Exceptions and RTTI; Standard Library
    gnustl_static The GNU STL (static). C++ Exceptions and RTTI; Standard Library
    gnustl_shared The GNU STL (shared). C++ Exceptions and RTTI; Standard Library
    c++_static The LLVM libc++ runtime (static). C++ Exceptions and RTTI; Standard Library
    c++_shared The LLVM libc++ runtime (shared). C++ Exceptions and RTTI; Standard Library
  • APP_SHORT_COMMANDS
  • NDK_TOOLCHAIN_VERSION 指定 GCC 编译器的版本.
  • APP_PIE 使用 PIE 来编译可执行文件(-fPIE).值可以为 true 或 false.

4 ndk-build

ndk-build 是 Android NDK 提供的一个脚本文件,它简化了调用 GNU makefile 的方法。我们在编译模块的时候,只需要调用 ndk-build就可以了:

cd <project>

$<ndk>/ndk-build

4.1 编译选项:

  • clean 清理已经生成的编译文件
  • V=1 打印编译命令
  • -B 强制重新编译
  • NDK_DEBUG NDK_DEBUG=0 编译为 release 版本; NDK_DEBUG=1 编译为 debug 版本
  • NDK_HOST_32BIT =1 总是使用 32 位模式编译
  • NDK_APPLICATION_MK=<file> 指定 Applocation.mk
  • C <project> 指定工程路径。当命令行在工程路径下时,无需此选项。

5 附录

 

 

  1. 本文目前尚无任何评论.
  1. 本文目前尚无任何 trackbacks 和 pingbacks.