1. 程式人生 > >Android NDK生成共享庫和靜態庫

Android NDK生成共享庫和靜態庫

在Android平臺上,通過NDK可以編譯NativeC程式,生成原生的NativeCode。從生成的程式碼的使用方式來看,主要有三種形式:Native Executable BinaryShared Dynamic Library, 以及Static Link Library。接下來將分別介紹這三種類型的二進位制檔案的用途和生成時的MakeFile的設定。

1. Static Link Library

1.1 用途

顧名思義,就是靜態連結庫的意思。靜態庫編譯生成後是以*.a的檔案形式存在;主要用於生成其他連結庫或可執行程式;在生成時靜態連結庫的程式碼會被連結到目標程式中去,因此,目標程式在使用工程中無需在使用靜態連結庫。同時由於靜態連結庫的部分或全部程式碼被連線到目標程式中,從而使得目標程式體積變大;使用了同一靜態連結庫的不同程式均已經連線了各自所需的目的碼,程式間不會共享程式碼。

在使用時,會用到聲明瞭靜態連結庫中函式的標頭檔案。

1.2 生成方式

使用NDK再帶的ndk-build生成時,要求程式碼需放在./jni/目錄下;同時在jni下建立Android.mk檔案;根據需要建立Application.mk

一個典型的用於生成靜態連結庫的Android.mk內容如下:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE    := mystaticLibrary
LOCAL_SRC_FILES := mystaticLibrary.cpp
LOCAL_INCLUDES  := $(LOCAL_PATH)/jni

include $(BUILD_STATIC_LIBRARY)

由於生產的是靜態庫,所以還需要一個Application.mk的檔案:

APP_MODULES     := mystaticLibrary
#APP_PLATFORM   := android-8

其中宣告應用平臺的這一行是可選項。

之後在當前目錄使用$(NDK_PATH)/ndk-build命令,正常情況即可生成相應的模組,一般位於./libs/armeabi/目錄下.

2. Shared Dynamic Library

2.1 用途

動態連結庫,通常不會在編譯時將庫中程式碼直接連線到目標程式中。在目標程式載入記憶體或使用dlopen動態載入時才會對映到程序記憶體;由於檔案是單獨存在的,故需要隨其它程式或模組一起分發;當然,檔案獨立存在性,也使得其具備不同模組或目標程式可以共享一個共同的庫檔案,就是有了共享庫的含義。

如前所說,存在兩種使用方式:

  • 編譯目標程式時聲明瞭所使用的動態連結庫,那麼在目標程式啟動時,動態連結庫將會被載入記憶體;
  • 目標程式在使用時通過dlopen主動裝載連結庫,那麼這種情況,連結庫的裝載時機取決於開發者。

下面簡單介紹第2種情況的使用流程:

typedef bool (void * _MY_FUNC)(int)
...
//*使用`dlopen`*將庫載入記憶體,獲得控制代碼
void * libHandle = dlopen("mySharedLibrary.so",RTLD_LAZY);
...
//獲取匯出函式
_MY_FUNC myFunc = (_MY_FUNC)dlsym(libHandle, "MyTestFunc");
...
//呼叫匯出函式
bool bRet = myFunc(2);
...
//關閉連結庫
dlclose(libHandle);

2.2 生成動態連結共享庫

2.2.1 通常情況的so生成

與生成靜態連結庫的要求一樣,需要將原始碼和庫放在當前目錄下的jni目錄下,並在jni目錄建立Android.mk檔案。一般情況其內容如下:

include $(CLEAR_VARS)

LOCAL_MODULE        :=  myLibrary
LOCAL_C_INCLUDES    :=  $(LOCAL_PATH)/jni
LOCAL_SRC_FILES := myLibrary.cpp

include $(BUILD_SHARED_LIBRARY)

之後ndk-build即可。

2.2.2 適用於jni介面的so的生成

生成適用於jni呼叫的so,則需要用先用javah生成包含函式宣告的標頭檔案:javah <包名>.<類名>。例如:

javah com.my.package.myActivity

2.2.3 生成過程中靜態連線其他靜態庫

生成so時,可能會需要連結其他一些靜態庫,這是Android.mk如下所示:

LOCAL_PATH := $(call my-dir)
###include myStaticLibrary lib as a prebuilt lib###
include $(CLEAR_VARS)

LOCAL_MODULE            := mystaticLibrary
LOCAL_SRC_FILES         := ./../../mystaticLibrary/obj/local/armeabi/libmystaticLibrary.a
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/../mystaticLibrary/jni
include $(PREBUILT_STATIC_LIBRARY)

### build ndk lib###
include $(CLEAR_VARS)

LOCAL_MODULE        :=  myLib
LOCAL_C_INCLUDES    :=  $(LOCAL_PATH)/jni \
                                $(LOCAL_PATH)/../../mystaticLibrary/jni
LOCAL_SRC_FILES := myLib.cpp

LOCAL_LDLIBS := -llog
LOCAL_STATIC_LIBRARIES := mystaticLibrary

include $(BUILD_SHARED_LIBRARY)

其中LOCAL_SRC_FILES指定的靜態庫需要提前已經編譯好。這裡也需要Application.mk

3. Native Executable Binary

這裡說的就是原生的可執行檔案。Android平臺本身就有不少原生的可執行程式,如ps、cd等命令對應的bin。

其生產方法和so生成類似,連結靜態庫也類似。

### compile NDK Executable ###
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE    :=   native_run
LOCAL_SRC_FILES :=  native_run.cpp
LOCAL_INCLUDE   := $(LOCAL_PATH)/jni    
include $(BUILD_EXECUTABLE)

參考