[Kotlin/Native] 創(chuàng)建全平臺動態(tài)庫

本來是想寫一下用 Kotlin/Native 玩 JNI 的,同時手里有一些 Android JNI 項目試圖做一個移植,研究了一下之后發(fā)現(xiàn),Kotlin/Native 的跨平臺庫實在是太強大了,除了喊 666 也沒別的話好說,于是干脆搞個大的,把全平臺的庫全部盤一遍。

首先要說一下,Kotlin/Native 體系下有一個很牛逼的命令叫做 konan,社區(qū)里也有人稱它為柯南,這個全平臺具體能全到什么程度,還要看柯南的。

$ konanc -list-targets
macos_x64:                    (default) macbook, macos, imac
ios_arm32:                    iphone32
ios_arm64:                    iphone, ipad, ios
ios_x64:                      iphone_sim
linux_x64:                    linux
linux_arm32_hfp:              raspberrypi
android_arm32:                          
android_arm64:                          
wasm32:      

除此之外,Kotlin/Native 原生支持 JSJVM 的編譯,不被列在這個表內(nèi)。另外,這個列表并非全部平臺,有一些編譯目標如 mingwX64 只能在 Windows 下進行,因此在 Mac 上的 konan 無法列出這些目標。

知道這些后,我們就可以按自己的需要來添加編譯平臺,這里需要注意的是,每個平臺支持的編譯方式都是有差異的,不能一概而論,下面我列了個表,來幫助大家寫編譯腳本:

平臺 target 名稱 編譯目標 特殊選項
js js moduleKind [可選 amd, commonjs, umd]
sourceMap [可選 true, false]
jvm jvm jvmTarget
iOS iosArm64 framework embedBitcode [可選 bitcode]
staticLib
iosArm32 framework embedBitcode [可選 bitcode]
staticLib
iosX64 framework embedBitcode [可選 bitcode]
staticLib
Android androidNativeArm64 executable entryPoint
sharedLib
staticLib
androidNativeArm32 executable entryPoint
sharedLib
staticLib
Mac macosX64 executable entryPoint
sharedLib
staticLib
framework embedBitcode [可選 bitcode]
Linux linuxX64 executable entryPoint
sharedLib
staticLib
linuxMipsel32 executable entryPoint
sharedLib
staticLib
linuxMips32 executable entryPoint
sharedLib
staticLib
Windows mingwX64 executable entryPoint
sharedLib
staticLib
WebAssembly wasm32 executable entryPoint
Raspberry Pi linuxArm32Hfp executable entryPoint
sharedLib
staticLib

這個表怎么用呢?比如說要針對 iOS Arm64 編譯一個 bitcode 的 framework,參考上表可以這樣寫腳本:

kotlin {
    iosArm64("ios64") {
        binaries {
            framework {
                embedBitcode "bitcode"
            }
        }
    }
}

同樣的,如果要針對 Android Arm64 編譯 JNI 庫和對應的靜態(tài)庫,只需要這樣寫:

kotlin {
    androidNativeArm64("android64") {
        binaries {
            sharedLib { }
            staticLib { }
        }
    }
}

下面來說一下使用動態(tài)庫的問題,對于通常的 C/C++ 庫來說,Kotlin 都可以簡單的通過 cinterop 來引入,官方也早就相關(guān)的文檔來說明(點擊查閱),同樣的,也可以在 C/C++ 里使用 Kotlin 的庫,官方文檔也說明了這一點(點擊查閱)。

在這里有一個問題,如官方文檔所述,在實際應用中為了一個函數(shù)去寫一大堆代碼顯然是不合適的,這里貼來官方的例子比較一下:

#include "libnative_api.h"
#include "stdio.h"

int main(int argc, char** argv) {
  //obtain reference for calling Kotlin/Native functions
  libnative_ExportedSymbols* lib = libnative_symbols();
... ...
  //use C and Kotlin/Native strings
  const char* str = "Hello from Native!";
  const char* response = lib->kotlin.root.example.strings(str);
  printf("in: %s\nout:%s\n", str, response);
  lib->DisposeString(response);
... ...
  return 0;
}

如果我想直接使用里面的 strings() 方法要怎么辦呢?其實是可以使用命名注解的:

package example
... ...
@CName("strings")
fun strings(str: String) : String? {
  return "That is '$str' from C"
}
... ...

注意此處的 @CName() 對應的名稱,就是最終導出的名稱,所以我們就可以用簡單的辦法來訪問了:

#include "libnative_api.h"
#include "stdio.h"

int main(int argc, char** argv) {
  //obtain reference for calling Kotlin/Native functions
  // libnative_ExportedSymbols* lib = libnative_symbols();
... ...
  //use C and Kotlin/Native strings
  const char* str = "Hello from Native!";
  // const char* response = lib->kotlin.root.example.strings(str);
  const char* response = strings(str);
  printf("in: %s\nout:%s\n", str, response);
  // lib->DisposeString(response);
... ...
  return 0;
}

通過同樣的方法,我們可以聲明 JNI 的導出函數(shù):

@CName("Java_com_rarnu_sample_NativeAPI_sayHello")
fun sayHello(env: CPointer<JNIEnvVar>, thiz: jobject) { ... ... }

另外,全網(wǎng)搜索 Kotlin 調(diào)用自己的庫未果,而且經(jīng)過一系列常規(guī)的嘗試后發(fā)現(xiàn)兩個大家都遇到了的問題(第一個,第二個),顯然不可能往這些方向繼續(xù)進行。

其實 Kotlin 要使用自己的庫并沒有那么麻煩,只不過設計思路有些不同,因為有一個很神奇的中間層叫 klib,通過引用 klib 就可以

$ konanc sample.kt -p library -o sample

編譯庫文件源碼,可以得到一個 sample.klib 把它放到項目里,然后直接引用文件即可:

sourceSets {
    ... ...
    macosMain {
        dependencies {
            implementation files('sample.klib')
        }
    }
}

這樣一來,這個 klib 就可以正確的代碼中引用到了。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容