Starting Kotlin/Native おなじところ、ちがうところ #m3kt

Starting Kotlin/Native おなじところ、ちがうところ #m3kt

2017/08/24 どこでもKotlin #1 @Cloud Works
エムスリー株式会社 星川貴樹 (@oboenikui)

A87027204ff57be1dadbf36a78a73c1b?s=128

Takaki Hoshikawa

August 24, 2017
Tweet

Transcript

  1. 2017/08/24 どこでもKotlin #m3kt Starting Kotlin/Native おなじところ、ちがうところ 2017/08/24 どこでもKotlin #1 @Crowd

    Works エムスリー株式会社 星川貴樹 (@oboenikui)
  2. 2017/08/24 どこでもKotlin #m3kt 目次 1. Kotlin/Nativeとは? a. LLVMとは? b. できること・できないこと

    2. Kotlin/Nativeを使い始める 3. おなじところ、ちがうところ 4. 使ってみた
  3. 2017/08/24 どこでもKotlin #m3kt 自己紹介 • 星川 貴樹 (@oboenikui) • 17卒の入社5ヶ月目

    • 現在の仕事は主にAndroidアプリ • 野球(見る方)、CTFが趣味
  4. 2017/08/24 どこでもKotlin #m3kt Kotlin/Nativeとは? • KotlinコードをLLVM経由で各ターゲット向けネイティ ブバイナリにコンパイルするコンパイラ • 今年4月公開,現在v0.3 (まだ実用レベルにない)

    • 現在サポートが確認されているターゲット ◦ x86-64系 Linux, macOS, Windows ◦ ARM系 iOS, Android, Raspberry Pi ◦ その他 (WebAssembly)
  5. 2017/08/24 どこでもKotlin #m3kt LLVMとは? 中間言語を介して様々なターゲット向けのバイナリにコンパイルする LLVM bitcode

  6. 2017/08/24 どこでもKotlin #m3kt LLVMとは? 中間言語を介して様々なターゲット向けのバイナリにコンパイルする LLVM bitcode

  7. 2017/08/24 どこでもKotlin #m3kt できること・できないこと • ˉできるˉ ◦ kotlin.*パッケージに含まれるクラス・メソッドを使う ◦ Cのヘッダーファイルが使えるライブラリを使う

    ◦ デバッグ • ˈできないˈ ◦ Fileクラスのようにkotlin.*パッケージに含まれないJavaの クラスを使う ◦ Javaのライブラリを使う ◦ Cのヘッダーファイルを含まないライブラリを使う※
  8. 2017/08/24 どこでもKotlin #m3kt Kotlin/Nativeを使い始める 1. GitHubからクローン $ git clone https://github.com/jetbrains/kotlin-native

    2. JetBrainsのサイトからダウンロード (サンプルを試す場合はこれがおすすめ) Download from https://blog.jetbrains.com/kotlin/2017/06/kotlinnative-v0-3-is-out/
  9. 2017/08/24 どこでもKotlin #m3kt Kotlin/Nativeを使い始める 3. Gradleで導入 (IDEAでも一応コーディング可) apply plugin: 'konan'

    buildscript { repositories { mavenCentral() maven { url "https://dl.bintray.com/jetbrains/kotlin-native-dependencies" } } dependencies { classpath "org.jetbrains.kotlin:kotlin-native-gradle-plugin:+" } }
  10. 2017/08/24 どこでもKotlin #m3kt Kotlin/Nativeのコンパイルフロー .def 使用するヘッダー ファイルを記述 .c .h Source

    cinterop konanc .bc .bc .kexe Shared Library LLVM bitcode
  11. 2017/08/24 どこでもKotlin #m3kt Cのメソッドの呼び出され方 • CのヘッダーファイルからKotlinとCのコードを生成 • // stdio.kt fun

    printf(arg0: String?, vararg args: Any?): Int = memScoped { // kni_printfの返り値(関数ポインタ)の実行処理 ... } @SymbolName("stdio_kni_printf") private external fun kni_printf(): NativePtr // stdiostubs.c void* stdio_kni_printf() { return printf; }
  12. 2017/08/24 どこでもKotlin #m3kt Cのメソッドの呼び出され方 • CのヘッダーファイルからKotlinとCのコードを生成 • // stdio.kt fun

    printf(arg0: String?, vararg args: Any?): Int = memScoped { // kni_printfの返り値(関数ポインタ)の実行処理 ... } @SymbolName("stdio_kni_printf") private external fun kni_printf(): NativePtr // stdiostubs.c void* stdio_kni_printf() { return printf; } Kotlin/JSの外部ライブラリ呼び出しの記法と同じ
  13. 2017/08/24 どこでもKotlin #m3kt C++のライブラリは使えない? • 現状ヘッダファイルからKotlinコードを生成できないた め、人の手で実装する必要あり • ニーズもあると思うのでそのうち実装されてほしい

  14. 2017/08/24 どこでもKotlin #m3kt おなじところ、ちがうところ

  15. 2017/08/24 どこでもKotlin #m3kt Kotlin/JVMと基本的に同じところ • kotlin.*パッケージのクラスは使用可能 (最終的には全て実装されるはず) • ほとんどの文法

  16. 2017/08/24 どこでもKotlin #m3kt Kotlin/JVMと基本的に同じところ • kotlin.*パッケージのクラスは使用可能 (最終的には全て実装されるはず) • ほとんどの文法 ➔

    完全にKotlinの世界に収まっているライブラリは 理論上JVMでもNativeでも利用可能に!
  17. 2017/08/24 どこでもKotlin #m3kt Kotlin/JVMとの大きな違い • 使えるライブラリの違い • Cのための相互運用型・メソッド • メモリ管理

    • プラットフォーム型がない • 安全性
  18. 2017/08/24 どこでもKotlin #m3kt Cのための相互運用型・メソッド • signed, unsignedな整数・浮動小数点型の数値は、同じ幅の数値型に マップ (32bit幅の整数の場合unsignedでもInt) •

    ポインタ・配列はCPointer<T>?にマップ • enumはenumか整数値にマップ • 構造体はCStructVarを継承したクラスにマップ • typedefはtypealiasにマップ • C相互運用のための拡張関数が定義されている など (例) char *getenv(const char *) Kotlin fun getenv(arg0: String?): CPointer<ByteVar>? Kotlin C
  19. 2017/08/24 どこでもKotlin #m3kt Cのための相互運用型・メソッド • signed, unsignedな整数・浮動小数点型の数値は、同じ幅の数値型に マップ (32bit幅の整数の場合unsignedでもInt) •

    ポインタ・配列はCPointer<T>?にマップ • enumはenumか整数値にマップ • 構造体はCStructVarを継承したクラスにマップ • typedefはtypealiasにマップ • C相互運用のための拡張関数が定義されている など (例) // kotlinx.cinterop.Utils fun CPointer<ByteVar>.toKString(): String fun getenv(arg0: String?): CPointer<ByteVar>? Kotlin
  20. 2017/08/24 どこでもKotlin #m3kt Cのための相互運用型・メソッド • signed, unsignedな整数・浮動小数点型の数値は、同じ幅の数値型に マップ (32bit幅の整数の場合unsignedでもInt) •

    ポインタ・配列はCPointer<T>?にマップ • enumはenumか整数値にマップ • 構造体はCStructVarを継承したクラスにマップ • typedefはtypealiasにマップ • C相互運用のための拡張関数が定義されている など (例) val path = getenv("PATH")?.toKString() ?: ""
  21. 2017/08/24 どこでもKotlin #m3kt メモリ管理 Kotlinのクラス • 現在の構想では、ターゲットによって最適なメモリ管理 方法を選択できるようにする予定 • 例えば、GC、手動管理、ARC(iOS)、といった選択が可

    能に
  22. 2017/08/24 どこでもKotlin #m3kt メモリ管理 Cとの相互運用部分 val buffer = nativeHeap.allocArray<ByteVar>(64 *

    1024) fgets(buffer, bufferLength, file)?.toKString() ?: "" ... nativeHeap.free(buffer)
  23. 2017/08/24 どこでもKotlin #m3kt メモリ管理 Cとの相互運用部分 memScoped { val bufferLength =

    64 * 1024 val buffer = allocArray<ByteVar>(bufferLength) for (i in 1..count) { val nextLine = fgets(buffer, bufferLength, file)? .toKString() ... } }
  24. 2017/08/24 どこでもKotlin #m3kt メモリ管理 Cとの相互運用部分 memScoped { val bufferLength =

    64 * 1024 val buffer = allocArray<ByteVar>(bufferLength) for (i in 1..count) { val nextLine = fgets(buffer, bufferLength, file)? .toKString() ... } } 動的確保した部分はmemScopedを抜 けると自動的にfreeされる
  25. 2017/08/24 どこでもKotlin #m3kt メモリ管理 Cとの相互運用部分 val head = memScoped {

    val bufferLength = 64 * 1024 val buffer = allocArray<ByteVar>(bufferLength) fgets(buffer, bufferLength, file)? .toKString() ?: "" }
  26. 2017/08/24 どこでもKotlin #m3kt メモリ管理 Cとの相互運用部分 val head = memScoped {

    val bufferLength = 64 * 1024 val buffer = allocArray<ByteVar>(bufferLength) fgets(buffer, bufferLength, file)? .toKString() ?: "" }
  27. 2017/08/24 どこでもKotlin #m3kt プラットフォーム型がない • Javaが介さないためプラットフォーム型は存在しない!! • Cでポインタを返すメソッドはKotlinでは全て CPointer<T>?を返す!!

  28. 2017/08/24 どこでもKotlin #m3kt プラットフォーム型がない • Javaが介さないためプラットフォーム型は存在しない!! • Cでポインタを返すメソッドはKotlinでは全て CPointer<T>?を返す!! ➔

    その結果サンプルコードは!!演算子だらけになってし まっている!!
  29. 2017/08/24 どこでもKotlin #m3kt

  30. 2017/08/24 どこでもKotlin #m3kt 安全性 • Kotlin部分は領域外アクセスなどに対し比較的安全だが、C相 互運用部分は注意が必要 val arr =

    arrayOf(1, 2, 3) for(i in 0..3) println(arr[i]) memScoped { val arr = intArrayOf(1, 2, 3) .toCValues() .getPointer(this) for (i in 0..3) println(arr[i]) }
  31. 2017/08/24 どこでもKotlin #m3kt 安全性 • Kotlin部分は領域外アクセスなどに対し比較的安全だが、C相 互運用部分は注意が必要 val arr =

    arrayOf(1, 2, 3) for(i in 0..3) println(arr[i]) memScoped { val arr = intArrayOf(1, 2, 3) .toCValues() .getPointer(this) for (i in 0..3) println(arr[i]) } 1 2 3 268435456 kotlin.ArrayIndexOutOfBoundsException
  32. 2017/08/24 どこでもKotlin #m3kt 安全性 • Kotlin部分は領域外アクセスなどに対し比較的安全だが、C相 互運用部分は注意が必要 val arr =

    arrayOf(1, 2, 3) for(i in 0..3) println(arr[i]) kotlin.ArrayIndexOutOfBoundsException memScoped { val arr = intArrayOf(1, 2, 3) .toCValues() .getPointer(this) for (i in 0..3) println(arr[i]) } 1 2 3 268435456 こっちの方 がまずい
  33. 2017/08/24 どこでもKotlin #m3kt 実際に動かしてみる OpenCVで顔抽出をやってみる https://github.com/oboenikui/kotlin-native-sample

  34. 2017/08/24 どこでもKotlin #m3kt 実際に動かしてみる OpenCVで顔抽出をやってみる • CのレガシーAPIしか使えなくてつらい • Cよりもコード量多くなりそうでつらい https://github.com/oboenikui/kotlin-native-sample

  35. 2017/08/24 どこでもKotlin #m3kt • ゲーム系? → Unityなどのサポート次第 • 組み込み系? →

    なさそう(ランタイムのサイズがネックに?) • WebAssembly? → まだ入り込む余地がありそう • iOS Application? → 素直にSwift学ぼう Kotlin/Nativeが活躍できる未来は来るか?
  36. 2017/08/24 どこでもKotlin #m3kt まとめ • Kotlin/Nativeの基本的な機能は整った • 正直今のままではキツい部分が多い ◦ C相互運用部分とKotlin標準部分が混ざると読みにくい

    ◦ GCCなどのセキュリティチェック機能が削がれてしまっているの で危険なコードに気づきにくい • 各ライブラリのKotlin/Native向けラッパーが出てきた ら辛さは変わるかも (でもそれJVMでよくね?) • WebAssembly対応が発表されたらもう少し注目される?