2017/08/24 どこでもKotlin #1 @Cloud Works エムスリー株式会社 星川貴樹 (@oboenikui)
2017/08/24 どこでもKotlin #m3ktStarting Kotlin/Nativeおなじところ、ちがうところ2017/08/24 どこでもKotlin #1 @Crowd Worksエムスリー株式会社星川貴樹 (@oboenikui)
View Slide
2017/08/24 どこでもKotlin #m3kt目次1. Kotlin/Nativeとは?a. LLVMとは?b. できること・できないこと2. Kotlin/Nativeを使い始める3. おなじところ、ちがうところ4. 使ってみた
2017/08/24 どこでもKotlin #m3kt自己紹介● 星川 貴樹 (@oboenikui)● 17卒の入社5ヶ月目● 現在の仕事は主にAndroidアプリ● 野球(見る方)、CTFが趣味
2017/08/24 どこでもKotlin #m3ktKotlin/Nativeとは?● KotlinコードをLLVM経由で各ターゲット向けネイティブバイナリにコンパイルするコンパイラ● 今年4月公開,現在v0.3 (まだ実用レベルにない)● 現在サポートが確認されているターゲット○ x86-64系Linux, macOS, Windows○ ARM系iOS, Android, Raspberry Pi○ その他(WebAssembly)
2017/08/24 どこでもKotlin #m3ktLLVMとは?中間言語を介して様々なターゲット向けのバイナリにコンパイルするLLVMbitcode
2017/08/24 どこでもKotlin #m3ktできること・できないこと● ˉできるˉ○ kotlin.*パッケージに含まれるクラス・メソッドを使う○ Cのヘッダーファイルが使えるライブラリを使う○ デバッグ● ˈできないˈ○ Fileクラスのようにkotlin.*パッケージに含まれないJavaのクラスを使う○ Javaのライブラリを使う○ Cのヘッダーファイルを含まないライブラリを使う※
2017/08/24 どこでもKotlin #m3ktKotlin/Nativeを使い始める1. GitHubからクローン$ git clone https://github.com/jetbrains/kotlin-native2. JetBrainsのサイトからダウンロード(サンプルを試す場合はこれがおすすめ)Download fromhttps://blog.jetbrains.com/kotlin/2017/06/kotlinnative-v0-3-is-out/
2017/08/24 どこでもKotlin #m3ktKotlin/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:+"}}
2017/08/24 どこでもKotlin #m3ktKotlin/Nativeのコンパイルフロー.def使用するヘッダーファイルを記述.c.hSourcecinteropkonanc.bc.bc.kexeSharedLibraryLLVM bitcode
2017/08/24 どこでもKotlin #m3ktCのメソッドの呼び出され方● CのヘッダーファイルからKotlinとCのコードを生成●// stdio.ktfun printf(arg0: String?, vararg args: Any?): Int =memScoped {// kni_printfの返り値(関数ポインタ)の実行処理...}@SymbolName("stdio_kni_printf")private external fun kni_printf(): NativePtr// stdiostubs.cvoid* stdio_kni_printf() { return printf; }
2017/08/24 どこでもKotlin #m3ktCのメソッドの呼び出され方● CのヘッダーファイルからKotlinとCのコードを生成●// stdio.ktfun printf(arg0: String?, vararg args: Any?): Int =memScoped {// kni_printfの返り値(関数ポインタ)の実行処理...}@SymbolName("stdio_kni_printf")private external fun kni_printf(): NativePtr// stdiostubs.cvoid* stdio_kni_printf() { return printf; }Kotlin/JSの外部ライブラリ呼び出しの記法と同じ
2017/08/24 どこでもKotlin #m3ktC++のライブラリは使えない?● 現状ヘッダファイルからKotlinコードを生成できないため、人の手で実装する必要あり● ニーズもあると思うのでそのうち実装されてほしい
2017/08/24 どこでもKotlin #m3ktおなじところ、ちがうところ
2017/08/24 どこでもKotlin #m3ktKotlin/JVMと基本的に同じところ● kotlin.*パッケージのクラスは使用可能(最終的には全て実装されるはず)● ほとんどの文法
2017/08/24 どこでもKotlin #m3ktKotlin/JVMと基本的に同じところ● kotlin.*パッケージのクラスは使用可能(最終的には全て実装されるはず)● ほとんどの文法➔ 完全にKotlinの世界に収まっているライブラリは理論上JVMでもNativeでも利用可能に!
2017/08/24 どこでもKotlin #m3ktKotlin/JVMとの大きな違い● 使えるライブラリの違い● Cのための相互運用型・メソッド● メモリ管理● プラットフォーム型がない● 安全性
2017/08/24 どこでもKotlin #m3ktCのための相互運用型・メソッド● signed, unsignedな整数・浮動小数点型の数値は、同じ幅の数値型にマップ (32bit幅の整数の場合unsignedでもInt)● ポインタ・配列はCPointer?にマップ● enumはenumか整数値にマップ● 構造体はCStructVarを継承したクラスにマップ● typedefはtypealiasにマップ● C相互運用のための拡張関数が定義されている など(例)char *getenv(const char *)Kotlinfun getenv(arg0: String?): CPointer?KotlinC
2017/08/24 どこでもKotlin #m3ktCのための相互運用型・メソッド● signed, unsignedな整数・浮動小数点型の数値は、同じ幅の数値型にマップ (32bit幅の整数の場合unsignedでもInt)● ポインタ・配列はCPointer?にマップ● enumはenumか整数値にマップ● 構造体はCStructVarを継承したクラスにマップ● typedefはtypealiasにマップ● C相互運用のための拡張関数が定義されている など(例)// kotlinx.cinterop.Utilsfun CPointer.toKString(): Stringfun getenv(arg0: String?): CPointer?Kotlin
2017/08/24 どこでもKotlin #m3ktCのための相互運用型・メソッド● signed, unsignedな整数・浮動小数点型の数値は、同じ幅の数値型にマップ (32bit幅の整数の場合unsignedでもInt)● ポインタ・配列はCPointer?にマップ● enumはenumか整数値にマップ● 構造体はCStructVarを継承したクラスにマップ● typedefはtypealiasにマップ● C相互運用のための拡張関数が定義されている など(例)val path = getenv("PATH")?.toKString() ?: ""
2017/08/24 どこでもKotlin #m3ktメモリ管理Kotlinのクラス● 現在の構想では、ターゲットによって最適なメモリ管理方法を選択できるようにする予定● 例えば、GC、手動管理、ARC(iOS)、といった選択が可能に
2017/08/24 どこでもKotlin #m3ktメモリ管理Cとの相互運用部分val buffer = nativeHeap.allocArray(64 * 1024)fgets(buffer, bufferLength, file)?.toKString() ?: ""...nativeHeap.free(buffer)
2017/08/24 どこでもKotlin #m3ktメモリ管理Cとの相互運用部分memScoped {val bufferLength = 64 * 1024val buffer = allocArray(bufferLength)for (i in 1..count) {val nextLine = fgets(buffer, bufferLength, file)?.toKString()...}}
2017/08/24 どこでもKotlin #m3ktメモリ管理Cとの相互運用部分memScoped {val bufferLength = 64 * 1024val buffer = allocArray(bufferLength)for (i in 1..count) {val nextLine = fgets(buffer, bufferLength, file)?.toKString()...}}動的確保した部分はmemScopedを抜けると自動的にfreeされる
2017/08/24 どこでもKotlin #m3ktメモリ管理Cとの相互運用部分val head = memScoped {val bufferLength = 64 * 1024val buffer = allocArray(bufferLength)fgets(buffer, bufferLength, file)?.toKString() ?: ""}
2017/08/24 どこでもKotlin #m3ktプラットフォーム型がない● Javaが介さないためプラットフォーム型は存在しない!!● Cでポインタを返すメソッドはKotlinでは全てCPointer?を返す!!
2017/08/24 どこでもKotlin #m3ktプラットフォーム型がない● Javaが介さないためプラットフォーム型は存在しない!!● Cでポインタを返すメソッドはKotlinでは全てCPointer?を返す!!➔ その結果サンプルコードは!!演算子だらけになってしまっている!!
2017/08/24 どこでもKotlin #m3kt
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])}
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])}123268435456kotlin.ArrayIndexOutOfBoundsException
2017/08/24 どこでもKotlin #m3kt安全性● Kotlin部分は領域外アクセスなどに対し比較的安全だが、C相互運用部分は注意が必要val arr = arrayOf(1, 2, 3)for(i in 0..3)println(arr[i])kotlin.ArrayIndexOutOfBoundsExceptionmemScoped {val arr = intArrayOf(1, 2, 3).toCValues().getPointer(this)for (i in 0..3)println(arr[i])}123268435456こっちの方がまずい
2017/08/24 どこでもKotlin #m3kt実際に動かしてみるOpenCVで顔抽出をやってみるhttps://github.com/oboenikui/kotlin-native-sample
2017/08/24 どこでもKotlin #m3kt実際に動かしてみるOpenCVで顔抽出をやってみる● CのレガシーAPIしか使えなくてつらい● Cよりもコード量多くなりそうでつらいhttps://github.com/oboenikui/kotlin-native-sample
2017/08/24 どこでもKotlin #m3kt● ゲーム系?→ Unityなどのサポート次第● 組み込み系?→ なさそう(ランタイムのサイズがネックに?)● WebAssembly?→ まだ入り込む余地がありそう● iOS Application?→ 素直にSwift学ぼうKotlin/Nativeが活躍できる未来は来るか?
2017/08/24 どこでもKotlin #m3ktまとめ● Kotlin/Nativeの基本的な機能は整った● 正直今のままではキツい部分が多い○ C相互運用部分とKotlin標準部分が混ざると読みにくい○ GCCなどのセキュリティチェック機能が削がれてしまっているので危険なコードに気づきにくい● 各ライブラリのKotlin/Native向けラッパーが出てきたら辛さは変わるかも(でもそれJVMでよくね?)● WebAssembly対応が発表されたらもう少し注目される?