AndroidStudio 1.5 でNDKを認識させるメモ
仕事でndk使うことになって、そういえば
ndk plugin 0.4.X系も出てたよな・・・ と思いつつ調べてみた
>結論から言うと
android.useDeprecatedNdk=trueとかndk pluginとか結局まともに動かなくて、従来通りこの方法が現状最善 / “タイトルとか決めてないけどこのままでもいいかもしんな…” https://t.co/PTM4jzEgoH #andoid #gradle
— close_yutori (@kimukou2628) 2015年11月10日
でしかビルドが出来なかった・・。
>原因としては
方式1)gradle gradle plugin NDKレガシー対応ベース*4
- gradle.properties
android.useDeprecatedNdk=true //◎
1.3以降で無効にされているandroid gradle pluginの
ndkの機能を有効化する
>jni.srcDirs = ['jni']を有効にした時点で
◎を指定しないとチェックタスクでエラーになるんだよな。。
- build.gradle
android { sourceSets { main { jni.srcDirs = ['jni'] //☆ jniLibs.srcDirs = ['libs'] } } buildTypes { debug { debuggable true } jniDebug { initWith(buildTypes.debug) jniDebuggable true } } }
と記述する方法だが、内部的にはndk-buildを呼んではいるのですが
- 中途はんぱにDSLを適応しようとしていて
みたいな謎な現象になっていたりしてたり。。(苦笑
何で素直に
- ndk-buildを実行+実行済タイムスタンプ記録
するだけにしてくれなかったのか...
と前からツッコミ入れたいと思ってましたね。。
解決した方法:方式2)
上記のURL記事と方式1)をあわせる技
因みに
にも書いてあるけど
- local.properties に下記のように書くと
sdk.dir=XXX ndk.dir=XXX
android.sdkDirectory android.ndkDirectory
で参照可能になるので、パスの決め打ち自体はじつはいらない。
- build.gradle
apply from:'build_ndk_ext.gradle' android { sourceSets { main { //ADTで解釈できるプロジェクト形式 manifest.srcFile 'AndroidManifest.xml' java.srcDirs = ['src'] resources.srcDirs = ['src'] aidl.srcDirs = ['src'] renderscript.srcDirs = ['src'] res.srcDirs = ['res'] assets.srcDirs = ['assets'] jni.srcDirs = ['jni'] //☆ //jni.srcDirs = [''] //== 普通改変推奨される箇所== jniLibs.srcDirs = ['libs'] //☆☆ } } }
現状だと
ndk buildだけ通す観点からだと
- 独自ndk-buildタスクを書く
- jni.srcDirs = [''] にしろと要求される
- //== 普通改変推奨される箇所== の箇所
となるわけですが、これだと
したがって
jniフォルダを有効にしつつ、本来のndkレガシータスクを無効化する形に修正する
- build_ndk_ext.gradle
//ndk レガシータスクを無効にする tasks.whenTaskAdded { task -> //組み込まれているNdkタスクを無効にする if (task.name.indexOf("Ndk")!=-1) { task.enabled = false } //assembleXXX ビルドをコマンドラインで指定しているときはデフォルトのテスト実行を無効にする(ビルドの高速化) def cmd_task = project.gradle.startParameter.taskNames[0] if (cmd_task !=null && cmd_task.indexOf("assemble")!=-1) { if (task.name.indexOf("test")!=-1) { task.enabled = false } } //assemble x ProductFlavor が非表示になっているので表示させる // see http://mrhaki.blogspot.jp/2012/06/gradle-goodness-adding-tasks-to.html if (task.name.indexOf("assemble")!=-1) { task.group = 'build' } } ext { ndkHome = android.ndkDirectory ==null ? "":android.ndkDirectory.getAbsolutePath() cpuNum = Runtime.getRuntime().availableProcessors() } //debugの時のみNDK_DEBUG=1をつける tasks.withType(JavaCompile) {task-> if(!new File('jni').exists())return; if(task.name.indexOf("Debug")!=-1){ task.dependsOn ndkBuildDebug } else{ task.dependsOn ndkBuildRelease } } if(new File('jni').exists()){ clean.dependsOn 'ndkClean' } import org.apache.tools.ant.taskdefs.condition.Os task ndkBuildDebug(type: Exec) { println "=== exec ndk-build ===" //soファイルが1個でも見つかったらndk-buildをUptodate扱いにしてSkipする if (Os.isFamily(Os.FAMILY_WINDOWS)) { commandLine "${ndkHome}/ndk-build.cmd","NDK_DEBUG=1","-j${cpuNum}" }else{ commandLine "${ndkHome}/ndk-build","NDK_DEBUG=1","-j${cpuNum}" } } task ndkBuildRelease(type: Exec) { println "=== exec ndk-build release===" if (Os.isFamily(Os.FAMILY_WINDOWS)) { commandLine "${ndkHome}/ndk-build.cmd","-j${cpuNum}" }else{ commandLine "${ndkHome}/ndk-build","-j${cpuNum}" } } task ndkClean(type: Exec) { println "=== exec ndk-build clean ===" if (Os.isFamily(Os.FAMILY_WINDOWS)) { commandLine "${ndkHome}/ndk-build.cmd", 'clean' }else{ commandLine "${ndkHome}/ndk-build", 'clean' } }
これでADTと同じような感じになるわけですが、
毎回ndk-build走るのはADTが遅い言われる原因の一つなので
ちょっと微妙な気がするわけでは有りますね。。
公式pluginを使うメリットって
- 実行済みタスクを.gradle/XXXX.bin としてタイムスタンプ記憶してSkipしてくれる
- 毎回ビルドが発生しないので時間短縮
なところがあるわけで、これを自前でやろうとすると実は大変(苦笑
でもup to-date を出す仕組み自体は興味があるから
後々再度調べてみたいと思う *5
12/24記)
- UP-TODATEは下記のように書けば良いとのこと。
- build_ndk_ext.gradle
//gradleで関数を使うには //def XXX => ext.XXX に変更しないと使えない // see http://stackoverflow.com/questions/27777591/how-to-define-and-call-custom-methods-in-build-gradle // ext.findFirstFile = {rootDir,filter -> println "rootDir=$rootDir" println "filter=$filter" if(rootDir==null || !rootDir.exists()){ return null } File result rootDir.traverse( type : groovy.io.FileType.FILES, nameFilter : filter ) { it -> //println it result = it groovy.io.FileVisitResult.TERMINATE } result } task ndkBuildDebug(type: Exec) { println "=== exec ndk-build debug ===" //TODO: onlyIf + println('UP-TO-DATE') outputs.upToDateWhen { //new File('libs/armeabi-v7a').exists() findFirstFile(new File(projectDir,'libs'), ~/.*\.so/)!=null } if (Os.isFamily(Os.FAMILY_WINDOWS)) { commandLine "${ndkHome}/ndk-build.cmd",'NDK_DEBUG=1',"-j${cpuNum}" } else{ commandLine "${ndkHome}/ndk-build",'NDK_DEBUG=1',"-j${cpuNum}" } }
これは
との合わせ技ですね。
- outputs.upToDateWhenの箇所は doLast{ }と組み合わせているサンプル多
- 条件を満たさない時に「空タスクはNGだよ」とエラーでてはまってた。><
現在最新の方法:方式3)
の記載のものですが、
AS最新版のviewを見てると、右下にAndroid Modelというタブが追加されていて
現在のandroid gradle plugin をこの新しいNDK対応版に作りなおして置き換えようとする意図が見えます。
ただこの android gradle-experimental plugin のアホっぽい糞面倒な所は
- 実行gradlewバージョンを限定して、バージョンが違うとエラーにするcheck taskを必須で組んでる
- しかも0.1バージョン変更するごとに必要gradleが違うので試すのすら億劫
- sourceSetの所がまだ作りこまれていないので、ADTタイプのプロジェクトだとまずビルドが出来ない
- 0.4だと0.3とかでよくサンプルで記載されているapiFilter辺りがreadOnlyだといわれてエラーになる
- DSLのページ公開して欲しいなーと切に思う。
- 本流のandroid gradle pluginの状況を取り込めていないので 通常のjavaレイヤー *6 でエラーでよく引っかかったりする
なスライドも一応公開されているらしい
正直最初は別gradle運用でいんじゃね? とか思ってたのにな・・。
変にandroid pluginと同じようなチェック処理が入っててビルド2回走らせるんかい!
みたいな感覚になる
- 1個前(現在版?) :収拾がつかなくて放り投げた
- 最新版:最初から考えなおして作りなおしてみる
みたいな感じですので、これも行き詰まったら
多分bazel にgoogle様も移行するんだろうな・・とか思ってたりする。
だってGAEだって今はjavaじゃなくてGo開発が主流らしいですからね。。
メーリングリスト見てると Gaelyk はまだ使ってるみたいなのは流れてきたりはしてるのですが。。。