複数ターゲット(例えばARM用とx86用)のプレビルド共有ライブラリをリンクするときのAndroid.mkの書き方です。
たまにしか書かなくて忘れがちなため自分用のメモ。
プレビルドの共有ライブラリをリンクする場合のAndroid.mkの書き方を、グルグル先生に聞くと、
- 一つの共有ライブラリを、複数のアプリで使用する方法-のねの日記
- [ Android ] 自分でコンパイルした既存のビルド済みの複数の共有ライブラリ(lib***.so)を使う方法。 Android.mk の設定が必要
とかが出てきます。本家本元はAndroid Developersや{$NDK}/docsにあります。
ちなみに、自分の以前の記事RenderScriptをNDKから使ってみたも検索にかかったりします\(^o^)/
でも、複数ターゲット(例えばARM用とx86用)のプレビルドの共有ライブラリをリンクするための設定について書かれた日本語のサイトは残念ながら見当たりませんでした。
{$NDK}/docs内に幾つか情報があるので紹介します。
複数ターゲットの共有ライブラリのビルド
まず最初に、単に複数ターゲットの共有ライブラリをビルドするだけであれば、今のNDKなら簡単ですね、定番はApplication.mkでAPP_ABIを設定します。
1 2 3 4 5 6 7 8 |
# armeabiとx86向けにビルドする時 APP_ABI := armeabi x86 # armeabi armeabi-v7a向けにビルドする時 APP_ABI := armeabi armeabi-v7a # 全部のターゲットをビルドする時 APP_ABI := armeabi armeabi-v7a x86 mips # NDKr7以降であれば上の行はこれと等価です。全部のターゲットをビルドする時 APP_ABI := all |
ちなみにApplication.mkにAPP_ABIを設定しなければ、armeabiだけになるようです。
今の端末のほとんどはarmeabi-v7aで、こっちの方が性能がいいので、旧端末を気にしないのであればarmeabi-v7aだけで、旧端末でも動かしたいのであれば、armeabi単体または、armeabi armeabi-v7aと指定します。
x86/mipsはプログラム側の対応もしないといけない可能性が有るので設定する場合には要注意ですね。
シングルターゲットのプレビルドの共有ライブラリのリンク
一方、プレビルドの共有ライブラリは、手動で{プロジェクトホーム}/libs/ターゲット/内にコピーしても自動で削除されてしまいます。そこで、ビルド時に自動でコピーしないといけないのですが、最初に載せたリンクに記載の内容では、
- {プロジェクトホーム}/jni/external/libのフォルダを作って、そこに共有ライブラリlib**.soを置く
- Android.mk に、そのライブラリーをコピーする記述を、ライブラリーの数だけ追加
Android.mkは、次のように記述。
1234 include $(CLEAR_VARS)LOCAL_MODULE := JohnnyLOCAL_SRC_FILES := external/lib/libJohnny.soinclude $(PREBUILT_SHARED_LIBRARY)
とみたいな感じで書いてありました。これはターゲットが1つだけであればOKなんですが、複数ターゲットの場合には、全然いけてません。
複数ターゲットのプレビルドの共有ライブラリをリンク
いよいよ、本命です。
自分の以前の記事RenderScriptをNDKから使ってみたのAndroid.mkでは、複数ターゲットでのビルドが出来ますが、Render Scriptのライブラリ限定での記述方法で汎用的ではありません。
じゃあどうすんねんと言うと、
- {プロジェクトホーム}/jni/external配下にターゲット別のフォルダを作ってそこにそれぞれのプレビルドの共有ライブラリを入れる。
ターゲット毎のフォルダ名はNDKのデフォルトに合わせて、armeabiやarmeabi-v7a等にしてください。複数のライブラリがある場合は、ターゲット毎のフォルダに直にまとめて入れても、ターゲット毎のフォルダ内に更に個別のサブフォルダを作って入れててもどちらでもOK。 - Android.mk に、そのライブラリーをコピーする記述を、ライブラリーの数だけ追加。
例えば、
{プロジェクトホーム}/jni/external/armeabi/libfoo.so
{プロジェクトホーム}/jni/external/armeabi-v7a/libfoo.so
{プロジェクトホーム}/jni/external/x86/libfoo.so
{プロジェクトホーム}/jni/external/mips/libfoo.so
の様に予めプレビルドの共有ライブラリをコピーしておきます。
上のlibfoo.soと言う名前の共有ライブラリを同じ名前のままでコピーする場合には、Android.mkに、次の様に記述します。
1 2 3 4 |
include $(CLEAR_VARS) LOCAL_MODULE := libfoo <=ここを修正しました LOCAL_SRC_FILES := external/$(TARGET_ARCH_ABI)/$(LOCAL_MODULE)$(TARGET_SONAME_EXTENSION) include $(PREBUILT_SHARED_LIBRARY) |
共有ライブラリ名の先頭の”lib”は自動で付加されるので書かなくてもOK。書いてもOK(仮にlibfooとしていてもliblibfooにはなりません)。いきなりの修正ですm(_ _)m。上のような書き方をする場合には、libを付けておいて下さい。LOCAL_SRC_FILESで$(LOCAL_MODULE)を参照せずに直接記入する場合にはLOCAL_MODULEで指定するライブラリ名にlibを付ける必要はありません。
ここで、キーとなるのは、$(TARGET_ARCH_ABI)と言うマクロです。
$(TARGET_ARCH_ABI)の部分はビルド中のターゲット名(armeabiとかx86とか)に置換されます。
$(TARGET_SONAME_EXTENSION)には共有ライブラリの拡張子が入ります。こっちは基本的に”.so”のはずなので直打ちしてもいいですけど。
ちなみに、この例ではjni/externalと言うフォルダをプロジェクト内に作ってますが、パスが通っていればどこに有っても構いません。もしかしたらdropboxとかのオンラインストレージに有っても大丈夫かも(試してないけど)。
他のライブラリへ依存している場合
他のライブラリへ依存している場合には、通常の共有ライブラリをビルドする時と同様に、LOCAL_SHARED_LIBRARIESまたはLOCAL_STATIC_LIBRARIESを定義する必要があります。
例えば、上のlibfoo.soがlibbar.soにリンクしている場合だと、
1 |
LOCAL_SHARED_LIBRARIES := bar |
と追加します。
スタティックリンクするのであれば、代わりにLOCAL_STATIC_LIBRARIESを設定します。
ヘッダーファイル
ところで、通常共有ライブラリを使うにはヘッダーファイルが必要です。
手動でコピーしてもいいですが、自動で参照するようにしたいもんですよね?
その場合には、上のAndroid.mkの例に
1 |
LOCAL_EXPORT_C_INCLUDES :={ヘッダーファイルへのパス} |
を追加して下さい。流石にこっちはターゲット毎に異なるってことは無いはずなので、直打ちでOKですが、例えば{プロジェクトホーム}/jni/external/includeみたいなフォルダを作って予めコピーしてそこを参照するようにしてもOKです。この方が相対パスになって移動や配布が楽なのと、プレビルドの共有ライブラリのバージョンがアプリ毎に異なる場合とかでも対応しやすいのでbetterかもですね。
おまけその1:ライブラリ名は変えてもOK
先ほどの、複数ターゲットのプリビルドの共有ライブラリ用のAndroid.mkでは、プレビルドの名前とアプリに組み込むときの共有ライブラリ名が同じでした。でも、実は変更することもできます。
例えば、libfoo.soをlibhoge.soとしてコピー&リンクしたいのであれば、次のようにします。
1 2 3 4 |
include $(CLEAR_VARS) LOCAL_MODULE := hoge LOCAL_SRC_FILES := external/$(TARGET_ARCH_ABI)/libfoo$(TARGET_SONAME_EXTENSION) include $(PREBUILT_SHARED_LIBRARY) |
おまけその2:元がスタティックライブラリでもOK
libbar.aと言うスタティックライブラリをコピー&リンクしてlibfoo.soにします。
1 2 3 4 |
include $(CLEAR_VARS) LOCAL_MODULE := foo LOCAL_WHOLE_STATIC_LIBRARIES = external/$(TARGET_ARCH_ABI)/libbar.a include $(BUILD_SHARED_LIBRARY) |
スタティックライブラリのままでコピーするなら最後のinclude $(BUILD_SHARED_LIBRARY)をinclude $(BUILD_STATIC_LIBRARY)に変えるだけです。
だんだんタイトルと内容がかけ離れていってしまうのでこれでおしまいです。
Android.mkではまだまだ、色んな設定が出来るので、興味有る方は{$NDK}/docs/ANDROID-MK.htmlやAPPLICATION-MK.html、PREBUILTS.html等を見て下さい。
お疲れ様でした。