本文件針對您在使用 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
,而非 mmap
。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 被參照,則這個 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
將會以弱符號形式發出,並在載入程式庫時將比對類型資訊合併。如果在執行檔載入後動態載入程式庫 (也就是透過 dlopen
或 System.loadLibrary
載入),則載入器可能無法將所載入程式庫的類型資訊合併。發生這種情況時,系統不會將這兩種類型視為相同類型。
使用不相符的預先建構程式庫
在應用程式中使用預先建構的程式庫 (這些通常是第三方程式庫) 時,需要特別注意。一般來說,請留意下列規則:
產生的應用程式的最低 API 級別是應用程式所有程式庫的最大
minSdkVersion
值。如果
minSdkVersion
為 16,但您使用透過 21 版建構的預先建構程式庫,則所產生應用程式的最低 API 級別為 21。如果預先建構的程式庫為靜態程式庫,則會在建構期間顯示違反這項規則的違規情形,但如果是預先建構的共用程式庫,可能要在執行時才會顯示。應使用相同的 NDK 版本產生所有程式庫。
由於違規情形極少發生,因此這項規則的靈活度比起大多數規則更佳,但無法保證以不同主要版本的 NDK 建構的程式庫之間能夠相容。C++ ABI 並非穩定版,過去曾有變動。
如果應用程式擁有多個共用程式庫,便必須使用共用的 STL。
至於 STL 不相符的情況,只要夠謹慎就能避免由此引發的問題,但最好可以直接避免使用不相符的 STL。為此,最好避免在應用程式中使用多個共用程式庫。