このドキュメントでは、NDK の使用中に発生する可能性のある、バグ以外の一般的な問題とその解決策(解決策がある場合)をいくつか説明します。
古い API レベルで _FILE_OFFSET_BITS=64
を使用する
統合ヘッダーの導入以前は、NDK は _FILE_OFFSET_BITS=64
をサポートしていませんでした。アプリの作成時にこのオプションを定義すると、通知を伴わずに無視されます。_FILE_OFFSET_BITS=64
オプションは統合ヘッダーをサポートするようになりましたが、旧バージョンの Android では、off64_t
バリアントとして使用できる off_t
API はほとんどありませんでした。したがって、この機能を古い API レベルで使用すると、利用できる関数の数が少なくなります。
この問題について詳しくは、r16 のブログ投稿と bionic のドキュメントで説明されています。
問題: ご利用のビルドには、minSdkVersion
に存在しない API が必要です。
解決策: _FILE_OFFSET_BITS=64
を無効にするか、minSdkVersion
の値を引き上げてください。
未宣言のまたは暗黙的な mmap
の定義
C++ で次のエラーが表示されることがあります。
エラー: 宣言されていない識別子「mmap」が使用されています。
または C で次のエラーが表示されます。
警告: 関数「mmap」の暗黙的な宣言は C99 では無効です
_FILE_OFFSET_BITS=64
を使用すると、C ライブラリは mmap
ではなく mmap64
を使用するよう指示されます。mmap64
は android-21
になるまでは使用できませんでした。minSdkVersion
値が 21 未満の場合、この関数は使用できません。C ライブラリに _FILE_OFFSET_BITS=64
と互換性のある mmap
が含まれていないためです。
minSdkVersion
がデバイスの API レベルよりも高く設定されている
NDK を使用してビルドする API レベルは、Java の場合の compileSdkVersion
とは大きく異なります。NDK API レベルは、アプリでサポートされている最小 API レベルです。これは、ndk-build では APP_PLATFORM
の設定に対応します。CMake では -DANDROID_PLATFORM
の設定に対応します。
関数への参照は、通常、ライブラリが最初に呼び出されたときではなく、ライブラリが読み込まれるときに解決されます。したがって、常に存在するとは限らない API を参照したり、API レベルのチェックでこうした API の使用を保護したりすることはできません。API をすべて参照する場合は、API がすべて存在している必要があります。
問題: NDK API レベルが、お使いのデバイスでサポートされている API のレベルを上回っています。
解決策: NDK API レベル(APP_PLATFORM
)を、アプリでサポートされている Android の最小バージョンに設定します。
ビルドシステム | 設定 |
---|---|
ndk-build | APP_PLATFORM |
CMake | ANDROID_PLATFORM |
externalNativeBuild | android.minSdkVersion |
他のビルドシステムの場合は、他のビルドシステムで NDK を使用するをご覧ください。
__aeabi
のシンボルが見つかりません
次のメッセージが返されます。
unsatisfiedLinkError: dlopen が失敗しました: シンボル「
__aeabi_memcpy
」が見つかりません
これは、発生する可能性のある ランタイム エラーの 1 つです。ネイティブ ライブラリを読み込もうとすると、これらのエラーがログに表示されます。このシンボルは __aeabi_*
のいずれかです。__aeabi_memcpy
と __aeabi_memclr
が最も一般的とされています。
この問題は、問題 126 に記載されています。
シンボル rand
が見つかりません
次のエラー ログメッセージの場合:
unsatisfiedLinkError: dlopen が失敗しました: シンボル「
rand
」が見つかりません
詳しくは、Stack Overflow の回答をご覧ください。
未定義の __atomic_*
への参照
問題: 一部の ABI は、アトミック操作を実装するために libatomic
を必要とします。
解決策: リンク時に -latomic
を追加します。
次のエラー メッセージの場合:
エラー: 未定義の「
__atomic_exchange_4
」への参照
ここでの実際のシンボルは、接頭辞 __atomic_
の付いた任意のシンボルにできます。
RTTI / 例外がライブラリ境界を越えて正しく機能しない
問題: 共有ライブラリ間でスローされた例外が検出されないか、dynamic_cast
が失敗した。
解決策: 型に鍵関数を 1 つ追加します。鍵関数は、型の最初の非純粋仮想関数です。具体例については、不具合 533 に関する説明をご覧ください。
C++ ABI では、2 つのオブジェクトの type_info
ポインタが同じである場合に限り、これらのオブジェクトは同じ型であると規定しています。catch の type_info
がスローされた例外と一致する場合に限り、例外が検出されます。dynamic_cast
にも同じルールが適用されます。
型に鍵関数が含まれていない場合、その typeinfo
は弱いシンボルとして出力され、ライブラリが読み込まれると、一致する型情報が統合されます。実行可能ファイルが読み込まれた後(つまり dlopen
または System.loadLibrary
を通じて読み込まれた後)にライブラリが動的に読み込まれると、ローダは読み込まれたライブラリの型情報を統合できない場合があります。この場合、この 2 つの型は等しいとみなされません。
一致しないビルド済みライブラリを使用する
アプリでビルド済みライブラリ(通常はサードパーティのライブラリ)を使用する場合は細心の注意が必要です。一般に、次のルールに注意してください。
作成されるアプリの最小 API レベルは、すべてのアプリ ライブラリの
minSdkVersion
の最大値です。minSdkVersion
が 16 でありながら、21 に対してビルドされたビルド済みライブラリを使用している場合、作成されるアプリの最小 API レベルは 21 になります。ビルド済みのライブラリが静的である場合、このルール違反はビルド時に表示されますが、ビルド済みの共有ライブラリの実行前には表示されない場合があります。すべてのライブラリは同じ NDK バージョンで生成される必要があります。
中断が最小限であるため、このルールは他の多くのルールよりもわずかに互換性がありますが、NDK の異なるメジャー バージョンでビルドされたライブラリ間の互換性は保証されていません。C++ ABI は安定したものではなく、過去に変更されたことがあります。
アプリに複数の共有ライブラリが含まれている場合は、共有 STL を使用する必要があります。
STL の不一致と同様に、細心の注意を払えばこの問題を回避できますが、問題を直接回避するのが好適です。こうした問題を回避する最善の方法として、アプリに複数の共有ライブラリを含めないことをおすすめします。