Android NDK生成共享庫和靜態庫
在Android平臺上,通過NDK可以編譯NativeC程式,生成原生的NativeCode。從生成的程式碼的使用方式來看,主要有三種形式:Native Executable Binary
, Shared
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)