Slide 1

Slide 1 text

2017/08/24 どこでもKotlin #m3kt Starting Kotlin/Native おなじところ、ちがうところ 2017/08/24 どこでもKotlin #1 @Crowd Works エムスリー株式会社 星川貴樹 (@oboenikui)

Slide 2

Slide 2 text

2017/08/24 どこでもKotlin #m3kt 目次 1. Kotlin/Nativeとは? a. LLVMとは? b. できること・できないこと 2. Kotlin/Nativeを使い始める 3. おなじところ、ちがうところ 4. 使ってみた

Slide 3

Slide 3 text

2017/08/24 どこでもKotlin #m3kt 自己紹介 ● 星川 貴樹 (@oboenikui) ● 17卒の入社5ヶ月目 ● 現在の仕事は主にAndroidアプリ ● 野球(見る方)、CTFが趣味

Slide 4

Slide 4 text

2017/08/24 どこでもKotlin #m3kt Kotlin/Nativeとは? ● KotlinコードをLLVM経由で各ターゲット向けネイティ ブバイナリにコンパイルするコンパイラ ● 今年4月公開,現在v0.3 (まだ実用レベルにない) ● 現在サポートが確認されているターゲット ○ x86-64系 Linux, macOS, Windows ○ ARM系 iOS, Android, Raspberry Pi ○ その他 (WebAssembly)

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

2017/08/24 どこでもKotlin #m3kt できること・できないこと ● ˉできるˉ ○ kotlin.*パッケージに含まれるクラス・メソッドを使う ○ Cのヘッダーファイルが使えるライブラリを使う ○ デバッグ ● ˈできないˈ ○ Fileクラスのようにkotlin.*パッケージに含まれないJavaの クラスを使う ○ Javaのライブラリを使う ○ Cのヘッダーファイルを含まないライブラリを使う※

Slide 8

Slide 8 text

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/

Slide 9

Slide 9 text

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:+" } }

Slide 10

Slide 10 text

2017/08/24 どこでもKotlin #m3kt Kotlin/Nativeのコンパイルフロー .def 使用するヘッダー ファイルを記述 .c .h Source cinterop konanc .bc .bc .kexe Shared Library LLVM bitcode

Slide 11

Slide 11 text

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; }

Slide 12

Slide 12 text

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の外部ライブラリ呼び出しの記法と同じ

Slide 13

Slide 13 text

2017/08/24 どこでもKotlin #m3kt C++のライブラリは使えない? ● 現状ヘッダファイルからKotlinコードを生成できないた め、人の手で実装する必要あり ● ニーズもあると思うのでそのうち実装されてほしい

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

2017/08/24 どこでもKotlin #m3kt Kotlin/JVMと基本的に同じところ ● kotlin.*パッケージのクラスは使用可能 (最終的には全て実装されるはず) ● ほとんどの文法 ➔ 完全にKotlinの世界に収まっているライブラリは 理論上JVMでもNativeでも利用可能に!

Slide 17

Slide 17 text

2017/08/24 どこでもKotlin #m3kt Kotlin/JVMとの大きな違い ● 使えるライブラリの違い ● Cのための相互運用型・メソッド ● メモリ管理 ● プラットフォーム型がない ● 安全性

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

2017/08/24 どこでもKotlin #m3kt メモリ管理 Kotlinのクラス ● 現在の構想では、ターゲットによって最適なメモリ管理 方法を選択できるようにする予定 ● 例えば、GC、手動管理、ARC(iOS)、といった選択が可 能に

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

2017/08/24 どこでもKotlin #m3kt プラットフォーム型がない ● Javaが介さないためプラットフォーム型は存在しない!! ● Cでポインタを返すメソッドはKotlinでは全て CPointer?を返す!! ➔ その結果サンプルコードは!!演算子だらけになってし まっている!!

Slide 29

Slide 29 text

2017/08/24 どこでもKotlin #m3kt

Slide 30

Slide 30 text

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]) }

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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 こっちの方 がまずい

Slide 33

Slide 33 text

2017/08/24 どこでもKotlin #m3kt 実際に動かしてみる OpenCVで顔抽出をやってみる https://github.com/oboenikui/kotlin-native-sample

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

2017/08/24 どこでもKotlin #m3kt ● ゲーム系? → Unityなどのサポート次第 ● 組み込み系? → なさそう(ランタイムのサイズがネックに?) ● WebAssembly? → まだ入り込む余地がありそう ● iOS Application? → 素直にSwift学ぼう Kotlin/Nativeが活躍できる未来は来るか?

Slide 36

Slide 36 text

2017/08/24 どこでもKotlin #m3kt まとめ ● Kotlin/Nativeの基本的な機能は整った ● 正直今のままではキツい部分が多い ○ C相互運用部分とKotlin標準部分が混ざると読みにくい ○ GCCなどのセキュリティチェック機能が削がれてしまっているの で危険なコードに気づきにくい ● 各ライブラリのKotlin/Native向けラッパーが出てきた ら辛さは変わるかも (でもそれJVMでよくね?) ● WebAssembly対応が発表されたらもう少し注目される?