Android JNI编程学习笔记(二)——深入了解NDK

来源:互联网 发布:lamb动作数据百度云 编辑:程序博客网 时间:2024/06/05 03:21

    在上一章我们主要讲解了Android NDK开发环境及相关工具的配置,大家都知道Android NDK是一套原生代码开发的工具集,帮助开发人员能够使用原生编程语言(如C/C++/汇编)实现一些对代码性能要求比较高的模块,并将其嵌入到Android应用程序中。

    本章的内容主要深入探讨Android NDK的组成,及一些Android Makefile文件的编写知识。(本章的内容主要参考:《Android C++ 高级编程-使用NDK》 和Android NDK官网主页


Android NDK是一套综合工具集,包含API、交叉编译器、链接程序、调试器、构建工具、文档和示例应用。主要包含以下组件:

ARM 、X86 和 MIPS的交叉编译器

构建系统 (GUN Make)

Java原生接口头文件

C库

Math库

POSIX线程

最小的C++库

ZLib压缩库

动态链接库

Android日志库 

Android像素缓冲区库( Android 2.2及以上版本)

Android原生应用APIs

OpenGL ES 3D图像库

OpenSL ES原生音频库

OpenMAX AL最小支持


Android NDK目录下一些重要的文件以及子目录:

ndk-build: 改shell脚本是Android NDK构建系统的起始点。ndk开发用的最多的脚本,每一次的构建都会用到它。

ndk-gdb: 改shell脚本允许用GNU调试器调试原生组件。 调试章节中会着重介绍。

ndk-stack:改shell脚本可以帮助分析原生组件崩溃时的堆栈追踪。 非常有用的脚本,在后续的调试章节中会着重介绍。

build:该目录包含了Android NDK构建系统的所有模块。

platforms: 该目录包含了支持不同Android 目标版本的头文件和库文件。

samples:该目录包含了一些示例应用程序,这些程序帮助你了解NDK开发,体验NDK的强大。

sources:该目录包含了可供开发人员导入到现有的Android NDK项目的一些共享模块。

toolchains:该目录包含目前Android NDK支持的不同目标机体系结构的交叉编译器。 目前支持:ARM X86 MIPS体系结构。

docs:该目录主要包含了一些介绍文档 以及参考资料。


Android NDK构建系统:

Android NDK的构建系统基于多种GUN Make片段构成。其主要目的使开发人员能够用很短的构建文档来描述原生的Android 应用程序;包括替开发人员制定的工具链,平台,CPU和ABI等很多细节。

组成NDK构建系统的片段可以在build/core子目录找到,知道它们的位置为以后构建系统的相关故障解决很有帮助。




Android.mk

Android.mk 隶属于GUN Makefile.向NDK编译器描述Android JNI项目的源码结构.是每一个NDK项目的必备组件.其位于jni子目录中.

经典的hello-jni项目下的Android.mk文件内容:

<pre name="code" class="html"># Copyright (C) 2009 The Android Open Source Project## Licensed under the Apache License, Version 2.0 (the "License");# you may not use this file except in compliance with the License.# You may obtain a copy of the License at##      http://www.apache.org/licenses/LICENSE-2.0## Unless required by applicable law or agreed to in writing, software# distributed under the License is distributed on an "AS IS" BASIS,# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.# See the License for the specific language governing permissions and# limitations under the License.#LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE    := hello-jniLOCAL_SRC_FILES := hello-jni.cinclude $(BUILD_SHARED_LIBRARY)

这是一个GUN Makefile片段,和其它Makefile基本是一样的. 以"#"开头的是注释行,GUN Make工具并不会处理.根据命名规范,变量名要大写.

LOCAL_PATH := $(call my-dir) 定义LOCAL_PATH变量.Android.mk文档必须以LOCAL_PATH变量的定义开头.

Android编译系统利用LOCAL_PATH定位源文件位置.Android提供了一个名为my-dir的宏功能.通过my-dir获取当前目录位置.

include $(CLEAR_VARS) 用于清除除了LOCAL_PATH以外的LOCAL_<name>变量,例如LOCAL_MODULE, LOCAL_SRC_FILES等等.

这样做主要是因为Android编译时 在单次执行中解析多个makefile文件 和 模块定义,而LOCAL_<name>是全局变量.清除它们可以避免冲突.

LOCAL_MODULE := hello-jni 利用LOCAL_MODULE给模块设定唯一的名称 hello-jni.本例中生成的是一个共享库,Android会为生成的文件添加适当的前缀 和 后缀.hello-jni模块最后会生成一个名为libhello-jni.so的文件.

LOCAL_SRC_FILES := hello-jni.c  指定了生成此模块所需要的源文件.

include $(BUILD_SHARED_LIBRARY) 指出模块最后生成的文件类型为动态库. Android NDK会将BUILD_SHARED_LIBRARY变量设置成build-shared-library.mk文件的存放位置.该makefile文件将源代码编译 和 组装成共享库的必要过程.

include $(BUILD_STATIC_LIBRARY) 最后生成静态库.Android应用程序并不直接使用静态库且应用程序包中也不包含静态库. 静态库主要用于提供功能,最后编译到其它动态库中.

include $(BUILD_EXCEUTABLE) 生成可执行文件,虽然会拷贝到libs目录下,但是并不会打包到apk文件中.可拷贝到android设备作为常规的linux应用程序执行.

Prebuilt库作用:

想在不发布源码情况下将模块发布给其他人使用.

提前编译好一些共享库,方便加速之后编译.

使用Prebuilt库:

虽然已经使用好,但是仍然需要提供一个Android.mk文件.

例如:

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := aLOCAL_SRC_FILES := liba.soinclude $(PREBUILT_SHARED_LIBRARY)
此时并未做任何编译操作,只是把Prebuilt库复制到ndk 项目的libs目录下.ndk就可以像普通共享库一样使用Prebuilt库了.

LOCAL_SHARED_LIBRARIES := a


Application.mk

Application.mk是ndk中一个可选的文件. 和 Android.mk文件一样,也存放在jni目录下.Application.mk的目的是描述应用程序需要哪些模块;定义所有模块的通用变量等.

以下是Application.mk文件支持的变量:

APP_ABI:默认情况下,编译生成armeabi ABI的二进制文件,使用此变量可以为其它ABI生成二进制文件.  例如APP_ABI := x86  为x86设备生成二进制文件.

APP_MODULES:默认情况下,Android NDK编译Android.mk文件声明的所有模块. 该变量覆盖Android.mk的声明模块并提供一个用空格分开的,需要编译的模块列表.

APP_OPTIM:该变量可以设置为release 或 debug 以改变生成二进制文件的优化级别.默认是release模式,生成的二进制文件被高度优化. 此变量被设置为debug时生成更容易调试的未优化二进制文件.

APP_CPPFLAGS:此变量列出了一些编译器标志,在编译任何模块的C++源文件时标志会传给编译器.

APP_BUILD_SCRIPT:默认情况下,Android NDK会在项目的jni目录下查找Android.mk 然后编译. 可以使用改变量改变上述行为,并使用不同的生成文件.

APP_STL:默认情况下,Android NDK使用最小的STL运行库. 可以使用该变量选择不同的STL.

APP_GNUSTL_FORCE_CPP_FEATURES:声明所有模块都依赖于具体的C++特性,如RTTI, exceptions等.

APP_SHORT_COMMANDS:在大量的源文件情况下,使编译系统使用更短的命令.


使用NDK-BUILD脚本命令

执行ndk-build脚本启动编译Android jni项目. 该命令提供了一组参数方便维护 和 控制编译过程.

-C:默认情况下,nkd-build应该在主项目目录下执行.-C可以指定命令行中NDK项目的位置.使ndk-build命令可以在任何位置开始. ndk-build -C /path/to/the/project

-B:如果源码未修改,Android NDK就不会重编项目.可以用-B强制重新编译所有源码. ndk-build -B

clean: 清理生成的二进制文件和目标文件. ndk-build clean

-j n : 使在编译时并行编译. n代表了并行编译的命令总数 ndk-build -j 4


NDK_LOG=1 :启用内部状态日志功能.在编译时产生大量的日志,日志信息前缀是:Android NDK. 用于排除编译错误.

V=1 : 实际执行的构建命令.

NDK_DEBUG=1 : 生成可调试的本地代码.

0 0