Android NDK总结

一. introduction

android NDK的介绍及应用对象
android NDK全称为Native Development Kit, 主要为了方便android开发程序员编写高速高性能的native 程序,也为处理一些底层的库和接口(如,调用OpenGL, OpenCL等等)

二. ndk-build 基础

我们在android中编写ndk程序的常用结构是这样的
+– project_root
| +– jni
| +– Android.mk
| +– Application.mk
| +– main.c
| +– obj
| +– libs


其中所有的源文件(即.cpp文件)和编译文件.mk文件都放在jni目录下
而obj文件夹和lib文件夹使我们ndk-build后编译生成的中间文件,以及我们C++code产生的.so文件。

Android.mk 与Application.mk 是Android NDK项目中最重要的makefile文件
Android.mk 中负责定义以下内容:
1. .cpp/c 等源文件的名字
2. 需要包含的头文件
3. 需要依赖附加的库
4. 要生成的so名字
5. build的类型
典型的Android.mk写法如下

LOCAL_PATH := $(call my-dir) # 获取Android.mk的文件路径
include $(CLEAR_VARS)  # 清除全部带有"LOCAL_"前缀的变量
OPENCV_LIB_TYPE :=STATIC
LOCAL_C_INCLUDES+= \
        $(LOCAL_PATH)/include   #定义工程需要包含的头文件所在目录
LOCAL_MODULE    := <module_name>  # name your module here.
LOCAL_SRC_FILES := \
src/opencvmain.cpp    \
src/ImageIO.cpp         \
src/CommonOperate_JNI.cpp  (这里多个文件编译用这个隔开)
include $(BUILD_SHARED_LIBRARY)

我的文件结构对应为
这里写图片描述
Application.mk定义了android应用的相关属性,比如
1. android SDK的版本
2. debug or release 模式
3. 目标平台ABI (architecture binary interface)
4. standard C/C++ library

典型的Application.mk如下

APP_OPTIM := debug    # Build the target in debug mode. 
APP_STL := gnustl_static   #(标准STL静态库)
APP_CPPFLAGS := -frtti -fexceptions # This is the place you enable exception.
APP_ABI := armeabi armeabi-v7a   #Define the target architecture to be ARM.
APP_PLATFORM := android-19    # Define the target Android version of the native application.

以上设置结束之后,我们在project_root下运行ndk-build,NDK building会自动查询到对应的jni文件夹下的native代码,之后会build生成lib<module_name>.so ,这个文件在libs/<abi>文件夹下,这里写图片描述

有了这个文件,就代表你的native代码已经集成在这个.so文件中了,那么后续的编译其实是不需要jni目录下的cpp文件的,之后我们就可以在java层中调用这个库,进而调用native代码接口。调用方式如下:

首先在一个java文件中作为与native的接口

public class ImageIO {
    static {
        System.loadLibrary("OpenCV");//这里是我们在Android.mk中定义的LOCAL_MODULE的名字
    }

    public static native boolean readimageDir(String ImgDir);
    public static native double readimage(String ImgPath);
}

之后在主程序中就可以使用
ImageIO .readimageDir("/testdata")


Android.mk中命令的几点解析
1. 关于build的类型
include $(BUILD_SHARED_LIBRARY) 将native代码编译为共享库文件
2. LOCAL_C_INCLUDES 用于指定工程所在头文件的位置, 我们建一个include文件夹,里边放我们的所有头文件,比如一个 test.h. 之后我们在工程中的所有src文件夹下都可以直接不加任何路径的做#include"test.h"

include $(BUILD_EXECUTABLE) 将native代码编译为可执行二进制文件
2. 关于stl库的类型
ndk中包含了stl对应的库,在$(NKD_HOME)/sources/cxx-stl/stlport/stlport
APP_STL 可以设置的参数如下:

  • system –> 系统默认的最小支持的C++运行时库 (这样生成的应用体积小,内存占用小,但部分功能将无法支持)
  • stlport_static –> 以静态链接的方式使用stlport版本的STL (不支持RTTI和异常)
  • stlport_shared –> 以动态链接的方式使用stlport版本的STL(不建议)
  • gnustl_static –> 以静态链接的方式使用gnu版本的STL (生成的文件体积会偏大,运行效率会低一些,支持C++异常处理,,需要在APP_CPPFLAGS 添加-fexceptions和-frtti这两个编译选项)

三. 一些有用的tips

1. 如何编译不在jni目录下的源文件?

1.1 使用相对路径

文件结构如下
这里写图片描述
这个时候,我们在Android.mk中可以说明src文件的路径,Android.mk如下

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES:= ../src/hello.cpp
LOCAL_MODULE:= hello
include $(BUILD_EXECUTABLE)

LOCAL_PATH:= $(call my-dir) 返回Android.mk所在的文件路径,之后Android.mk文件下的所有变量都可以得到一个基于Android.mk路径的绝对路径。例如,LOCAL_SRC_FILES:= ../src/hello.cpp中的相对路径是相对Android.mk所在的位置为基准的,这样就可以跳出jni目录了。
include $(CLEAR_VARS) 代表 清除全部带有”LOCAL_”前缀的变量, 但是不会清除LOCAL_PATH, 会清除掉以下变量,例如LOCAL_SRC_FILES, LOCAL_C_INCLUDES, LOCAL_CFLAGS, LOCAL_LDFLAGS, LOCAL_LDLIBS。因此,这一句话最好放在开头,在设置这些变量之前。

关于ndk脚本的一些说明:默认情况下Application.mk和Android.mk名字定了的,ndk-build直接去工程文件夹下去找jni,然后找到这个目录下的这两个.mk文件。在使用命令行的时候,利用ndk-build可以手动指定Application.mk的位置,比如我们把Application.mk放在工程根目录下,

export NDK_PROJECT_PATH=.
$ ndk-build NDK_APPLICATION_MK=./Application.mk

第一句指定.为工程根目录,然后第二句设定Application.mk的位置。而Android.mk的位置是在Application.mk中指定的

APP_BUILD_SCRIPT := Android.mk  

我们在Application.mk中的最后一句添加以上代码,APP_BUILD_SCRIPT 代表整个application的主要makefile。

总结一下:: ndk-build 命令通过以项目根目录为基准加上NDK_APPLICATION_MK 设定Application.mk的位置,在Application.mk设定主编译makefile为Android.mk,Android.mk以其文件所在位置为相对路径设定native源文件的位置。


注意:本文翻译自

http://web.guohuiwang.com/technical-notes/androidndk1
再次感谢作者

发布了46 篇原创文章 · 获赞 10 · 访问量 11万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章