常見問題及解決方案

本文件針對您在使用 NDK 時可能會遇到的常見非錯誤性問題,列出部分情形並提供適用的解決方法 (如有)。

_FILE_OFFSET_BITS=64 與舊版 API 級別搭配使用

統一標頭之前,NDK 並不支援 _FILE_OFFSET_BITS=64。如果您在建構應用程式時已自行定義,系統會直接忽略這個選項。_FILE_OFFSET_BITS=64 選項現在支援統一標頭,但在舊版 Android 中,只有少數 off_t API 可做為 off64_t 變數使用。因此,如果將這項功能與舊版 API 級別搭配使用,會導致可用的函式減少。

如需瞭解這個問題,r16 網誌文章bionic 說明文件中有提供詳細說明。

問題:您的建構要求 minSdkVersion 中沒有的 API。

解決方法:停用 _FILE_OFFSET_BITS=64 或提高 minSdkVersion

未宣告或隱含的 mmap 定義

您可能會在 C++ 中看到下列錯誤:

錯誤:使用未宣告的 ID「mmap」

或者,在 C 中看到以下錯誤:

警告:函式「mmap」的隱含宣告在 C99 中無效

使用 _FILE_OFFSET_BITS=64 會指示 C 程式庫使用 mmap64,而非 mmapmmap64 不適用於 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 被參照,則這個 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」符號

是執行階段中可能出現的其中一種錯誤。當您嘗試載入原生資料庫時,記錄中會顯示這些錯誤。符號可以是 __aeabi_* 中的任意一個;其中,__aeabi_memcpy__aeabi_memclr 可能最常見。

這個問題已記錄在問題 126

找不到 rand 符號

針對下列錯誤記錄訊息:

UnsatisfiedLinkError:dlopen 失敗:找不到「rand」符號

請參閱提供詳細資訊的 Stack Overflow 解答

未定義對 __atomic_* 的參照

問題:部分 ABI 需要 libatomic 以執行特定原子作業實作。

解決方法:在連結時加上 -latomic

針對以下錯誤訊息:

錯誤:未定義對「__atomic_exchange_4」的參照

這裡的實際符號可能是前置字元為 __atomic_ 的任何符號。

RTTI/例外狀況功能無法跨程式庫邊界執行

問題:在共用程式庫邊界擲回例外狀況或 dynamic_cast 發生錯誤時,無法偵測到例外狀況。

解決方法:為您的類型新增一項金鑰函式。金鑰函式是特定類型的第一個非純函式的外部虛擬函式。如需查看範例,請參閱問題 533 中的討論。

C++ ABI 規定,只有在兩個物件的 type_info 指標相同時,這兩個物件才具有相同類型。只有在偵測的 type_info 與擲回的例外狀況相符時,才能偵測到例外狀況。這項規則同樣適用於 dynamic_cast

如果類型沒有金鑰函式,其 typeinfo 將會以弱符號形式發出,並在載入程式庫時將比對類型資訊合併。如果在執行檔載入後動態載入程式庫 (也就是透過 dlopenSystem.loadLibrary 載入),則載入器可能無法將所載入程式庫的類型資訊合併。發生這種情況時,系統不會將這兩種類型視為相同類型。

使用不相符的預先建構程式庫

在應用程式中使用預先建構的程式庫 (這些通常是第三方程式庫) 時,需要特別注意。一般來說,請留意下列規則:

  • 產生的應用程式的最低 API 級別是應用程式所有程式庫的最大 minSdkVersion 值。

    如果 minSdkVersion 為 16,但您使用透過 21 版建構的預先建構程式庫,則所產生應用程式的最低 API 級別為 21。如果預先建構的程式庫為靜態程式庫,則會在建構期間顯示違反這項規則的違規情形,但如果是預先建構的共用程式庫,可能要在執行時才會顯示。

  • 應使用相同的 NDK 版本產生所有程式庫。

    由於違規情形極少發生,因此這項規則的靈活度比起大多數規則更佳,但無法保證以不同主要版本的 NDK 建構的程式庫之間能夠相容。C++ ABI 並非穩定版,過去曾有變動。

  • 如果應用程式擁有多個共用程式庫,便必須使用共用的 STL

    至於 STL 不相符的情況,只要夠謹慎就能避免由此引發的問題,但最好可以直接避免使用不相符的 STL。為此,最好避免在應用程式中使用多個共用程式庫。