一般的な問題と解決策

このドキュメントでは、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 を使用するよう指示されます。mmap64android-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 の不一致と同様に、細心の注意を払えばこの問題を回避できますが、問題を直接回避するのが好適です。こうした問題を回避する最善の方法として、アプリに複数の共有ライブラリを含めないことをおすすめします。