前回はaarでネイティブライブラリを公開する話でした。
今回はそのaar内に含まれるネイティブライブラリへリンクした別のネイティブライブラリを作ってみた話です。
Android developersによると、prefab機能でaar内に含まれたネイティブライブラリを使ってビルドするには、つぎの2つが必要です。
- AGPのprefab機能を有効にする
- CMakeLists.txtでaar内のネイティブライブラリをfind_packageで参照する
AGPのprefab機能を有効にするにはbuild.gradleへ次のように追加します。
1 2 3 |
buildFeatures { prefab true } |
CMakeLists.txtの方はこんな感じでfind_packageでライブラリを参照します。
1 2 3 4 5 6 7 |
# appターゲットに対してapp.cppファイルを追加して共有ライブラリとしてビルドする add_library(app SHARED app.cpp) # prefab機能でaar内に含まれるlibcurl.soを探す find_package(curl REQUIRED CONFIG) # 見つかったlibcurl.soをappターゲットへリンクする target_link_libraries(app curl::curl) |
前回の記事のスクショの通り、今回使おうとしているaarにはaandusb, jpeg-turbo2x, media-backport, common, media-utilsの5つのネイティブライブラリがprefabとして含まれています(prefabとして公開していない他のライブラリも含んでますが)。
そのうちのcommon(libcommon.so)へリンクするために、Android developersの例と同じようにfind_packageにcommonを指定してみました。
1 2 3 |
... find_package(common REQUIRED CONFIG) ... |
でも実際に試すとこんなエラーがでてaar内のネイティブライブラリを見つけることができませんでした。ナンデヤネンナ
1 2 3 |
CMake Error at CMakeLists.txt:17 (find_package): Could not find a package configuration file provided by "common" with any of the following names: |
aarをモジュールとしてインポートしたり、libs下に入れてみたり、ローカルファイルとして参照してみたり色々してみましたがだめでした(´・ω・`)ちくせう
なんでやようわからんということで、buildFeatures.prefabなどというあやしげな動かねぇ機能は無かったことにして、一番実績のある方法に切り替えることにしました。
ズバリっ✨
aarは単なるzipファイルに過ぎないのでbuild.gradle内でコピータスクを作ればzipTreeでアクセスして展開・コピーできるのです✌️
まずはbuild.gradleへコピータスクを追加します。
1 2 3 4 5 6 7 8 9 10 11 12 |
tasks.withType(JavaCompile) { compileTask -> compileTask.mustRunAfter ndkA } // aandusbのaar内のprefabフォルダ内から共有ライブラリとヘッダーファイルをソースディレクトリへコピーするタスク task ndkA(type: Copy) { FileTree natives = zipTree(new File(project(':aandusb-release').projectDir, "aandusb-${aandUsbVersion}.aar")) from natives into 'src/main/cpp/' include ('prefab/**/**.so', 'prefab/**/**.h') includeEmptyDirs = false } |
これでaarのprefabフォルダ内の共有ライブラリ(*.so)・ヘッダーファイル(*.h)が丸っと指定場所にコピーされます。やったね😉
(コピーしたprefabディレクトリ以下を.gitignoreでgitの除外設定してあげてね)
次いで、相対ファイルパス指定でプレビルドライブラリとしてCMakeLists.txtへ追加すればOK。find_packageではないのでインクルードパスも自前で指定しておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
... # プレビルドライブラリの設定(common/libcommon.so) add_library(common SHARED IMPORTED) set_property(TARGET common PROPERTY IMPORTED_LOCATION ${lib_src_DIR}/prefab/modules/common/libs/android.${ANDROID_ABI}/libcommon.so) set(INC_COMMON ${lib_src_DIR}/prefab/modules/common/include/ ) ... # ヘッダーファイルを指定 target_include_directories(${target} PRIVATE ${INC_COMMON} ... ) # リンクするライブラリを指定 target_link_libraries(${target} PRIVATE common ... ) ... |
これで自前のソースファイルからaar内のヘッダーファイルを使い、共有ライブラリへリンクできるようになりましたチャンチャン…と言いたいところなのですが、実はこれだけだとビルドが通りません。
なにがだめかというか、aar内に元々jni下にも共有ライブラリが存在しており、prefab内からコピーしたものと合わせて同じ共有ライブラリが2つ存在することになってしまうのです。
なので重複してしまう共有ライブラリは除外設定が必要です。
共有ライブラリを除外するには例えば次のようにbuild.gradleへ書き加えます。
1 2 3 4 5 |
packagingOptions { exclude("**/libcommon.so") exclude("**/libc++_shared.so") ... } |
この除外設定が必要ですので、aar内のネイティブライブラリにリンクして新しいネイティブライブラリを作る場合には、ライブラリモジュールとして分離した方が良いです。そして、そのモジュール内で新しく作ったネイティブライブラリ以外は全て除外設定するようにすればOKです(prefabの場合も同じです)。
ということで、prefab機能を作ってaar内に含めたネイティブライブラリへリンクして新しいネイティブライブラリをビルドしてみたでした。
次回はその新しくビルドしたネイティブライブラリ、UVC機器からの映像へOpenCVを使った手ぶれ補正をした話です(^.^)/~~~