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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章