Android JNI之執杖生涯 .a -> .so(mk方式)(android studio)

緣由

曾夢想仗劍走天涯,看一看世界的繁華。豈料一入 JNI 深似海,從此女神是路人。生成so文件,是每個 JNI 人的終極夢想。前段日子,公司人少,扔過來的是cpp實現文件,呵呵,以為要往c渣渣方向發展,嚇得我趕緊拿起那本紅皮書,c++從入門到放棄。幾個月過去,書還沒人捧熱,cpp不見了,取而代之是.a文件,什么玩意兒?掏出度娘,怒刷binggo。一手Shadowsocks,谷狗汪汪汪。靜態庫,簡單來說,編譯器認識,而linux不認識。故事,從這里開始。

.a 怎么用

想用就用,用得響亮。我就靜靜的,靜靜的看著。一巴掌一個腳印,啪啪啪,痛嗎?不痛,輕輕松松三步走。

啪. 定位

下藥要對口,位置不能隨心。來來來,jni (JNI Floder)目錄下。又回到最初的起點,記憶中你cpp文件的位置(打個廣告,參考我前邊寫的關于JNI文章)。對,沒錯,又是jni目錄。進階的.a,還是老地方,熟悉的味道,不一樣的配方。然,no pic no bb。吶~*@……#!#!神圣召喚術 --- 圖圖圖。


JNI目錄圖

上邊的sources目錄是瞎寫的,歸個類。這里有東西解釋下,比如說 arm64-v8a之類的, 這個是指cpu類型。目前而言,armeabi 這個是基類,所有手機都支持的類型。蕓蕓眾手機,天涯cpu類型what?no,no,nobody I want nobody nobody But You,一個字:懶。so armeabi,你值得擁有。x86/x86-64這個一般是電腦cpu類型,模擬器用得上。如果能夠每個類型都build出來,自然是好的,畢竟每個類型cpu都有各自的優化。

啪啪. 鏈接

重點來了。使用.a的過程,就是鏈接。當然不僅僅是,整個打包成so過程,都是鏈接過程,這里主講如何鏈接.a。
mk,從 jni 誕生那一刻起,隨之誕生。這里暫且先講mk方式實現鏈接,其它暫且不提。悠久的歷史,腳本性質的配置,承載著老一輩人的遠方與詩。左手,右手,一個慢動作。一步兩步三四步,帶你走個過場。記住了,固然可喜,若是沒有,就再看一遍吧。


mk版結構圖
# Android.mk文件,稍作修改,即可食用
LOCAL_PATH := $(call my-dir)

//鏈接.a塊
include $(CLEAR_VARS)
LOCAL_MODULE := libHello
LOCAL_C_INCLUDES := $(LOCAL_PATH)/sources
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/sources
LOCAL_SRC_FILES := sources/$(TARGET_ARCH_ABI)/libHello.a
include $(PREBUILT_STATIC_LIBRARY)

include $(CLEAR_VARS)
LOCAL_CPPFLAGS  := -std=c++14
LDFLAGS := -shared
LOCAL_LDFLAGS += -fuse-ld=bfd
LOCAL_MODULE           := JniDemo
LOCAL_SRC_FILES        :=   jni_dynamic.cpp
LOCAL_STATIC_LIBRARIES := libHello
include $(BUILD_SHARED_LIBRARY)
# Application.mk 這個基本不需要改
APP_STL := gnustl_static//使用 STL 靜態庫
NDK_TOOLCHAIN_VERSION := 4.9//鏈接器tool版本
/**
 *fexceptions 允許異常功能
 *frtti 運行時類型識別
 *fpermissive 此項有效時表示寬松的編譯形式,比如沒有用到的代碼中有錯誤也可以通過
 * std=c++14 允許使用c++14的函數等功能
 */
APP_CPPFLAGS := -fexceptions -frtti -fpermissive -std=c++14
APP_ABI := armeabi armeabi-v7a arm64-v8a mips mips64
APP_PLATFORM := android-14
APP_OPTIM := debug

這2個固定搭配,沒什么需要特別解釋的地方,照搬磚頭即可。如果你砸到了自己的腳,火速120,你來找我也沒用。mk文件已經就位,當然還需要build.gradle的支持。

android{
    ....
    task ndkBuild(type: Exec, description: 'Compile JNI source via NDK') {
        commandLine "E:/adt-bundle-windows-x86_64-20140321/android-ndk-r10/ndk-build.cmd",//ndk.build位置
                'NDK_PROJECT_PATH=build/intermediates/ndk',//ndk位置
                'NDK_LIBS_OUT=src/main/jniLibs',//輸出目錄
                'APP_BUILD_SCRIPT=src/main/jni/Android.mk',
                'NDK_APPLICATION_MK=src/main/jni/Application.mk'
    }
    tasks.withType(JavaCompile) {
        compileTask -> compileTask.dependsOn ndkBuild
    }
}

這段,不解釋呢,說不過去。解釋呢,一句話,自定義ndkbuild命令(生成so的利器)。到這里本想著已經告一段路了,是時候見證奇跡的時刻了。然而還不料,一個error讓我沉醉,毫無保留,沒有余力悲傷:

D:\Study_Code\JniDemo\app\src\main\jni\sources\hello.h
Error:(1, 18) string: No such file or directory
Error:Execution failed for task ':app:compileDebugNdk'.
> com.android.ide.common.process.ProcessException: Error while executing 'E:\adt-bundle-windows-x86_64-20140321\android-ndk-r10\ndk-build.cmd' with arguments {NDK_PROJECT_PATH=null APP_BUILD_SCRIPT=D:\Study_Code\JniDemo\app\build\intermediates\ndk\debug\Android.mk APP_PLATFORM=android-25 NDK_OUT=D:\Study_Code\JniDemo\app\build\intermediates\ndk\debug\obj NDK_LIBS_OUT=D:\Study_Code\JniDemo\app\build\intermediates\ndk\debug\lib APP_ABI=all}

顯然,c++中string找不到。喲喲喲,切克鬧。bug,bug,bug,驚起一灘苦水。既然開啟了自定義,那么就需要做點限制,比如說禁用自動執行ndk-build。如果自動執行ndk-build的話,那么我的Application.mk配置將失效,默認是c環境,緣來如此。

android{
    ...
    sourceSets {
        main {
            jni.srcDirs = []//禁用自動執行ndk-build 
        }
    }
}

.mk 這艘小船,到這兒,已經上岸了。

啪啪啪.見證奇跡的時刻

上邊的已然做到,那么這一刻,屬于你的奇跡終究還是到來了。biu,biu,build。接下來,或許更精彩。
附送一張機票,帶你領略世界的浩瀚

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容