Android NDK 支援使用 CMake 為應用程式編譯 C 和 C++ 程式碼。本頁面說明如何透過 Android Gradle 外掛程式的 ExternalNativeBuild
,或透過直接叫用 CMake,將 NDK 與 CMake 搭配使用。
CMake 工具鏈檔案
NDK 透過工具鏈檔案支援 CMake。工具鏈檔案是 CMake 檔案,用於自訂跨平台程式碼編譯的工具鏈行為。用於 NDK 的工具鏈檔案位於 NDK 的 <NDK>/build/cmake/android.toolchain.cmake
中。
叫用 cmake
時,指令列會提供 ABI、minSdkVersion
等建構參數。如需支援的引數清單,請參閱「工具鏈引數」一節。
「全新」工具鍊檔案
先前 NDK 嘗試了新的工具鍊檔案實作, 可減少使用 NDK 工具鍊檔案和 使用內建的 CMake 支援功能。但最後卻需要產生 但並沒有真正改善行為 因此我們不會再處理
「全新」工具鍊檔案的行為迴歸 (與「舊版」相比)
工具鍊檔案。預設行為為建議的工作流程。如果您是
使用 -DANDROID_USE_LEGACY_TOOLCHAIN_FILE=OFF
,建議您移除該標記
建構容器新的工具鍊檔案永遠無法與舊版檔案保持一致
工具鍊檔案,因此可能會發生行為迴歸問題。
雖然我們建議不要使用新的工具鍊檔案,但是目前還沒有 並計劃從 NDK 中移除。這樣做會導致依賴該物件的建構作業 新版與舊版工具鍊檔案的行為差異。 重新命名選項將名稱標示為「舊版」其實是 也可能打斷使用者選擇如果您滿意地使用 您不需要遷移的新工具鍊檔案,但請務必留意 可能無法修正新的工具鍊檔案行為, 您需要遷移這些資料
用量
Gradle
使用 externalNativeBuild
時,系統會自動使用 CMake 工具鏈檔案。詳情請參閱 Android Studio 的將 C 和 C++ 程式碼新增至專案指南。
指令列
在 Gradle 之外使用 CMake 進行建構時,必須將工具鏈檔案及其引數傳遞至 CMake,例如:
$ cmake \
-DCMAKE_TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=$ABI \
-DANDROID_PLATFORM=android-$MINSDKVERSION \
$OTHER_ARGS
工具鏈引數
下列引數可傳遞至 CMake 工具鏈檔案。如果使用 Gradle 建構,請按照 ExternalNativeBuild 說明文件所述,將引數新增至 android.defaultConfig.externalNativeBuild.cmake.arguments
。如果是透過指令列進行建構,請使用 -D
將引數傳遞至 CMake。例如,強迫 armeabi-v7a 不要使用 Neon 進行建構
支援,請傳遞 -DANDROID_ARM_NEON=FALSE
。
ANDROID_ABI
目標 ABI。如需瞭解支援的 ABI,請參閱 Android ABI。
Gradle
Gradle 會自動提供這個引數。請勿在您的 build.gradle
檔案中明確設定這個引數。如要控管 ABI Gradle 的目標,請依照 Android ABI 中所述使用 abiFilters
。
指令列
CMake 針對每項建構作業的單一目標進行建構。如要設定多個 Android ABI 目標,則必須為每個 ABI 建構一次。建議針對每個 ABI 使用不同的建構目錄,以免建構作業之間發生衝突。
值 | 附註 |
---|---|
armeabi-v7a |
|
armeabi-v7a with NEON |
與 armeabi-v7a 相同。 |
arm64-v8a |
|
x86 |
|
x86_64 |
ANDROID_ARM_MODE
指定是否為 armeabi-v7a 產生 arm 或 thumb 指令。不會影響其他 ABI。詳情請參閱 Android ABI 說明文件。
值 | 附註 |
---|---|
arm | |
thumb | 預設行為。 |
ANDROID_NATIVE_API_LEVEL
ANDROID_PLATFORM 的別名。
ANDROID_PLATFORM
指定應用程式或程式庫支援的最低 API 級別。這個值對應應用程式的 minSdkVersion
。
Gradle
使用 Android Gradle 外掛程式時,系統會自動將這個值設為與應用程式的 minSdkVersion
相符,因此不應手動設定。
指令列
直接叫用 CMake 時,這個值會預設為使用的 NDK 所支援的最低 API 級別。例如,針對 NDK r20,這個值預設為 API 級別 16。
這個參數支援多種格式:
android-$API_LEVEL
$API_LEVEL
android-$API_LETTER
$API_LETTER
格式可讓您指定 android-N
,而無需確定該版本編號。請注意,部分版本增加了 API,但字母沒有增加。您可以透過附加 -MR1
後置字串來指定這些 API。例如,API 級別 25 是 android-N-MR1
。
ANDROID_STL
指定這個應用程式要使用的 STL。詳情請參閱 C++ 程式庫支援。根據預設,系統會使用 c++_static
。
值 | 附註 |
---|---|
c++_shared | libc++ 的共用程式庫變化版本。 |
c++_static | libc++ 的靜態程式庫變化版本。 |
none | 不支援 C++ 標準程式庫。 |
system | 系統 STL |
管理編譯器標記
如果您需要將特定標記傳遞至版本的編譯器或連結器, 請參閱 set_target_compile_options 的 CMake 說明文件,以及 一起做出選擇「另請參閱」該網頁最下方的部分 一些有用的線索
一般而言,最佳做法是將編譯器標記套用至最小範圍
可用的範圍您要套用至所有指定目標的旗標 (例如
-Werror
) 對每個模組重複比較方便,但還是很少見
全域套用 (CMAKE_CXX_FLAGS
),因為這些設定可能對
專案中的第三方依附元件在這種情況下,標記可能會
已套用至目錄範圍 (add_compile_options
)。
針對少數編譯器旗標,您也可以在 build.gradle 中設定
透過 cppFlags
或類似屬性管理檔案請勿這麼做。旗幟
從 Gradle 傳遞至 CMake 時,會有非預期的優先順序行為。
覆寫被實作的標記,
來建構 Android 程式碼一律偏好處理 CMake 行為
直接整合到 CMake 中如需根據 AGP buildType
控制編譯器標記,
請參閱「在 CMake 中使用 AGP 建構類型」。
在 CMake 中使用 AGP 建構類型
如果您需要為自訂 Gradle buildType
自訂 CMake 行為,請使用該程式碼
建構型別來傳遞另一個 CMake 標記 (而非編譯器標記),
可讀取 CMake 建構指令碼。舉例來說,如果您擁有「免費」以及「Premium」
建構變數,並由 build.gradle.kts 控管,因此您需要傳遞
將資料提供給 CMake:
android {
buildTypes {
free {
externalNativeBuild {
cmake {
arguments.add("-DPRODUCT_VARIANT_PREMIUM=OFF")
}
}
}
premium {
externalNativeBuild {
cmake {
arguments.add("-DPRODUCT_VARIANT_PREMIUM=ON")
}
}
}
}
}
接著在 CMakeLists.txt 中:
if (DPRODUCT_VARIANT_PREMIUM)
# Do stuff for the premium build.
else()
# Do stuff for the free build.
endif()
您可以自行決定變數名稱,但請務必避免使用
ANDROID_
、APP_
或 CMAKE_
前置字元,以免發生衝突或混淆
和一些現有標記
如需範例,請參閱 Sanitizers NDK 範例。
瞭解 CMake 建構指令
如要對 CMake 建構問題偵錯,建議您先瞭解為 Android 執行跨平台程式碼編譯作業時,Gradle 使用哪些特定建構引數。
Android Gradle 外掛程式會針對每個 ABI 及與 build_command.txt
配對的建構類型的 CMake 建構作業,儲存執行此類作業時使用的建構引數。這些檔案位於以下目錄中:
<project-root>/<module-root>/.cxx/cmake/<build-type>/<ABI>/
您可以使用 CMake 引數建構 hello-jni
範例的可偵錯版本並指定 armeabi-v7a
架構,如以下程式碼片段範例所示:
Executable : ${HOME}/Android/Sdk/cmake/3.10.2.4988404/bin/cmake
arguments :
-H${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/src/main/cpp
-DCMAKE_FIND_ROOT_PATH=${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/.cxx/cmake/universalDebug/prefab/armeabi-v7a/prefab
-DCMAKE_BUILD_TYPE=Debug
-DCMAKE_TOOLCHAIN_FILE=${HOME}/Android/Sdk/ndk/22.1.7171670/build/cmake/android.toolchain.cmake
-DANDROID_ABI=armeabi-v7a
-DANDROID_NDK=${HOME}/Android/Sdk/ndk/22.1.7171670
-DANDROID_PLATFORM=android-23
-DCMAKE_ANDROID_ARCH_ABI=armeabi-v7a
-DCMAKE_ANDROID_NDK=${HOME}/Android/Sdk/ndk/22.1.7171670
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/build/intermediates/cmake/universalDebug/obj/armeabi-v7a
-DCMAKE_RUNTIME_OUTPUT_DIRECTORY=${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/build/intermediates/cmake/universalDebug/obj/armeabi-v7a
-DCMAKE_MAKE_PROGRAM=${HOME}/Android/Sdk/cmake/3.10.2.4988404/bin/ninja
-DCMAKE_SYSTEM_NAME=Android
-DCMAKE_SYSTEM_VERSION=23
-B${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/.cxx/cmake/universalDebug/armeabi-v7a
-GNinja
jvmArgs :
Build command args: []
Version: 1
使用預先建構的程式庫
如果需要匯入的預先建構程式庫是發布為 AAR,請按照 Studio 依附元件說明文件所述,匯入和使用這類程式庫。如果不是使用 AGP,可以按照 https://google.github.io/prefab/example-workflow.html 的指示操作,但改用 AGP 可能更簡單。
如果程式庫並非發布為 AAR,請參閱 CMake 使用手冊中有關 IMPORTED
目標的 add_library
說明文件,瞭解如何透過 CMake 使用預先建構的程式庫。
建構第三方程式碼
在 CMake 專案中建構第三方程式碼的實用方法有很多,哪種方法最合適需視情況而定,但最佳做法通常是完全不建構第三方程式碼。請改為針對程式庫建構 AAR,並在應用程式中取用。您不必「發布」AAR,AAR 可位於 Gradle 專案內部。
如果不適合這種做法:
- 將第三方來源提供 (即複製) 到存放區,並使用 add_subdirectory 建構。只有在其他程式庫也使用 CMake 來建構時,才能使用這種做法。
- 定義 ExternalProject。
- 從專案中單獨建構程式庫,並按照「使用預先建構的程式庫」所述,將其匯入為預先建構程式庫。
CMake 中的 YASM 支援
NDK 針對建構以 YASM 編寫的組譯程式碼提供 CMake 支援,以便在 x86 和 x86-64 架構上執行。YASM 是 x86 和 x86-64 架構的開放原始碼組譯工具,以 NASM 組譯工具為基礎。
如要使用 CMake 建構組譯程式碼,請在專案的 CMakeLists.txt
中進行下列變更:
- 呼叫
enable_language
,並將值設為ASM_NASM
。 - 如要建構共用程式庫,請呼叫
add_library
;如要建構可執行的二進位檔,則呼叫add_executable
。在引數中傳遞來源檔案清單,當中包含 YASM 組合程式的.asm
檔案,以及相關 C 程式庫或函式的.c
檔案。
下列程式碼片段展示如何設定 CMakeLists.txt
,以將 YASM 程式建構為共用程式庫。
cmake_minimum_required(VERSION 3.6.0)
enable_language(ASM_NASM)
add_library(test-yasm SHARED jni/test-yasm.c jni/print_hello.asm)
如需查看示範將 YASM 程式建構為執行檔的範例,請參閱 NDK Git 存放區中的 YASM 測試。
回報問題
如果遇到 NDK 或其 CMake 工具鏈檔案的相關問題,請透過 GitHub 的 android-ndk/ndk 問題追蹤工具回報這類問題。假如遇到 Gradle 或 Android Gradle 外掛程式的問題,請改為回報 Studio 錯誤。