Android NDK, आपके ऐप्लिकेशन के लिए C और C++ कोड कंपाइल करने के लिए CMake का इस्तेमाल करने की सुविधा देता है. इस पेज पर, Android Gradle प्लग इन के ExternalNativeBuild के ज़रिए या सीधे CMake को कॉल करके, NDK के साथ CMake का इस्तेमाल करने का तरीका बताया गया है.
CMake टूलचेन फ़ाइल
NDK, टूलचेन फ़ाइल के ज़रिए CMake के साथ काम करता है. टूलचेन फ़ाइलें, CMake फ़ाइलें होती हैं. ये क्रॉस-कंपाइलिंग के लिए, टूलचेन के व्यवहार को पसंद के मुताबिक बनाती हैं. NDK के लिए इस्तेमाल की जाने वाली टूलचेन
फ़ाइल, NDK में
<NDK>/build/cmake/android.toolchain.cmake पर मौजूद होती है.
cmake को कॉल करते समय, बिल्ड पैरामीटर जैसे कि एबीआई, minSdkVersion वगैरह, कमांड लाइन पर दिए जाते हैं. काम करने वाले आर्ग्युमेंट की सूची देखने के लिए, टूलचेन आर्ग्युमेंट सेक्शन देखें.
"नई" टूलचेन फ़ाइल
NDK के पुराने वर्शन में, टूलचेन फ़ाइल के नए तरीके को आज़माया गया था. इससे, NDK की टूलचेन फ़ाइल और CMake की पहले से मौजूद सहायता का इस्तेमाल करने के बीच के अंतर को कम किया जा सकता था. हालांकि, इसमें काफ़ी काम करना पड़ा (जो अब तक पूरा नहीं हुआ है). साथ ही, इससे व्यवहार में कोई सुधार नहीं हुआ. इसलिए, हम अब इस पर काम नहीं कर रहे हैं.
"नई" टूलचेन फ़ाइल के व्यवहार में, "लेगसी" टूलचेन फ़ाइल की तुलना में गड़बड़ियां हैं. हमारा सुझाव है कि डिफ़ॉल्ट सेटिंग का इस्तेमाल करें. अगर -DANDROID_USE_LEGACY_TOOLCHAIN_FILE=OFF का इस्तेमाल किया जा रहा है, तो हमारा सुझाव है कि अपने बिल्ड से उस फ़्लैग को हटा दें. नई टूलचेन फ़ाइल, लेगसी टूलचेन फ़ाइल के बराबर नहीं है. इसलिए, इसके व्यवहार में गड़बड़ियां हो सकती हैं.
हालांकि, हमारा सुझाव है कि नई टूलचेन फ़ाइल का इस्तेमाल न करें. फ़िलहाल, इसे NDK से हटाने की कोई योजना नहीं है. ऐसा करने से, उन बिल्ड में गड़बड़ी आ सकती है जो नई और लेगसी टूलचेन फ़ाइलों के बीच के अंतर पर निर्भर करते हैं. साथ ही, इस विकल्प का नाम बदलकर यह साफ़ करना भी मुश्किल है कि "लेगसी" का इस्तेमाल करने का सुझाव दिया जाता है. ऐसा करने से, इस विकल्प का इस्तेमाल करने वाले लोगों को भी परेशानी होगी. अगर नई टूलचेन फ़ाइल का इस्तेमाल करने में कोई समस्या नहीं आ रही है, तो आपको माइग्रेट करने की ज़रूरत नहीं है. हालांकि, ध्यान रखें कि नई टूलचेन फ़ाइल के व्यवहार से जुड़ी किसी भी गड़बड़ी को शायद ठीक न किया जाए. ऐसे में, आपको माइग्रेट करना होगा.
इस्तेमाल
ग्रेडल
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 की मदद से बिल्ड करने पर,
android.defaultConfig.externalNativeBuild.cmake.arguments में आर्ग्युमेंट जोड़ें. इसके लिए,
ExternalNativeBuild के दस्तावेज़ में दिया गया तरीका अपनाएं. कमांड लाइन से बिल्ड करने पर, -D के साथ CMake में आर्ग्युमेंट पास करें. उदाहरण के लिए, armeabi-v7a को Neon सहायता के बिना बिल्ड करने के लिए, -DANDROID_ARM_NEON=FALSE पास करें.
ANDROID_ABI
टारगेट एबीआई. काम करने वाले एबीआई के बारे में जानने के लिए, Android एबीआई देखें.
ग्रेडल
Gradle, यह आर्ग्युमेंट अपने-आप देता है. अपनी build.gradle फ़ाइल में, इस आर्ग्युमेंट को साफ़ तौर पर सेट न करें. यह कंट्रोल करने के लिए कि Gradle किन एबीआई को टारगेट करता है,
abiFilters का इस्तेमाल करें, जैसा कि Android एबीआई में बताया गया है.
आदेश पंक्ति
CMake, हर बिल्ड के लिए एक टारगेट बनाता है. एक से ज़्यादा Android एबीआई को टारगेट करने के लिए, हर एबीआई के लिए एक बार बिल्ड करना ज़रूरी है. हमारा सुझाव है कि हर एबीआई के लिए अलग-अलग बिल्ड डायरेक्ट्री का इस्तेमाल करें, ताकि बिल्ड के बीच टकराव न हो.
| मान | नोट |
|---|---|
armeabi-v7a |
|
armeabi-v7a with NEON |
armeabi-v7a के जैसा. |
arm64-v8a |
|
x86 |
|
x86_64 |
ANDROID_ARM_MODE
इससे पता चलता है कि armeabi-v7a के लिए, arm या thumb निर्देश जनरेट करने हैं या नहीं. इसका अन्य एबीआई पर कोई असर नहीं पड़ता. ज़्यादा जानकारी के लिए, Android एबीआई के दस्तावेज़ देखें.
| मान | नोट |
|---|---|
| arm | |
| thumb | डिफ़ॉल्ट सेटिंग. |
ANDROID_NATIVE_API_LEVEL
यह ANDROID_PLATFORM का एलियास है.
ANDROID_PLATFORM
इससे पता चलता है कि ऐप्लिकेशन या लाइब्रेरी, कम से कम किस एपीआई लेवल पर काम कर सकती है. यह वैल्यू, ऐप्लिकेशन के minSdkVersion से मेल खाती है.
ग्रेडल
Android Gradle प्लग इन का इस्तेमाल करने पर, यह वैल्यू ऐप्लिकेशन के minSdkVersion से मेल खाने के लिए अपने-आप सेट हो जाती है. इसे मैन्युअल तरीके से सेट नहीं करना चाहिए.
आदेश पंक्ति
सीधे CMake को कॉल करने पर, यह वैल्यू डिफ़ॉल्ट रूप से उस एपीआई लेवल पर सेट होती है जिस पर इस्तेमाल किया जा रहा NDK काम करता है. उदाहरण के लिए, NDK r20 के साथ, यह वैल्यू डिफ़ॉल्ट रूप से एपीआई लेवल 16 पर सेट होती है.
ANDROID_PLATFORM
इस पैरामीटर के लिए, कई फ़ॉर्मैट स्वीकार किए जाते हैं:
android-$API_LEVEL$API_LEVELandroid-$API_LETTER
$API_LETTER फ़ॉर्मैट की मदद से, android-N को उस रिलीज़ से जुड़े नंबर का पता लगाए बिना भी सेट किया जा सकता है. ध्यान दें कि कुछ रिलीज़ में, एपीआई लेवल में बढ़ोतरी हुई है, लेकिन रिलीज़ के नाम में कोई बदलाव नहीं हुआ है. इन एपीआई को -MR1 सफ़िक्स जोड़कर सेट किया जा सकता है. उदाहरण के लिए, एपीआई लेवल 25, android-N-MR1 है.
ANDROID_STL
इससे पता चलता है कि इस ऐप्लिकेशन के लिए, किस एसटीएल का इस्तेमाल करना है. ज़्यादा जानकारी के लिए, C++
लाइब्रेरी की सहायता देखें. डिफ़ॉल्ट रूप से, c++_static का इस्तेमाल किया जाएगा.
| मान | नोट |
|---|---|
| c++_shared | libc++ की शेयर की गई लाइब्रेरी का वैरिएंट. |
| c++_static | libc++ की स्टैटिक लाइब्रेरी का वैरिएंट. |
| none | C++ स्टैंडर्ड लाइब्रेरी की सहायता उपलब्ध नहीं है. |
| system | द सिस्टम एसटीएल |
कंपाइलर फ़्लैग मैनेज करना
अगर आपको अपने बिल्ड के लिए, कंपाइलर या लिंकर में खास फ़्लैग पास करने हैं, तो set_target_compile_options और उससे जुड़े विकल्पों के बारे में जानने के लिए, CMake के दस्तावेज़ देखें. उस पेज पर सबसे नीचे मौजूद "यह भी देखें" सेक्शन में कुछ काम के सुझाव दिए गए हैं.
आम तौर पर, कंपाइलर फ़्लैग को सबसे छोटे उपलब्ध स्कोप के तौर पर लागू करना सबसे सही तरीका है. जिन फ़्लैग को अपने सभी टारगेट पर लागू करना है (जैसे, -Werror), उन्हें हर मॉड्यूल के लिए दोहराना मुश्किल होता है. हालांकि, उन्हें ग्लोबल तौर पर (CMAKE_CXX_FLAGS) भी बहुत कम लागू करना चाहिए, क्योंकि इससे आपके प्रोजेक्ट में तीसरे पक्ष की डिपेंडेंसी पर गलत असर पड़ सकता है. ऐसे मामलों में, फ़्लैग को डायरेक्ट्री-स्कोप (add_compile_options) पर लागू किया जा सकता है.
कंपाइलर फ़्लैग के छोटे सबसेट के लिए, इन्हें cppFlags या मिलती-जुलती प्रॉपर्टी का इस्तेमाल करके, अपनी build.gradle फ़ाइल में भी सेट किया जा सकता है. आपको ऐसा नहीं करना चाहिए. Gradle से CMake में पास किए गए फ़्लैग, कुछ मामलों में, Android कोड बनाने के लिए ज़रूरी, लागू करने के तरीके से साफ़ तौर पर पास किए गए फ़्लैग को बदल सकते हैं. हमेशा CMake में सीधे CMake के व्यवहार को मैनेज करने का सुझाव दिया जाता है. अगर आपको हर AGP buildType,
के लिए कंपाइलर फ़्लैग कंट्रोल करने हैं, तो CMake में AGP बिल्ड टाइप के साथ काम करना लेख देखें.
CMake में AGP बिल्ड टाइप के साथ काम करना
अगर आपको CMake के व्यवहार को पसंद के मुताबिक बनाए गए Gradle buildType के हिसाब से बनाना है, तो उस बिल्ड टाइप का इस्तेमाल करके, CMake का एक अतिरिक्त फ़्लैग (कंपाइलर फ़्लैग नहीं) पास करें. इसे आपकी CMake बिल्ड स्क्रिप्ट पढ़ सकती हैं. उदाहरण के लिए, अगर आपके पास "फ़्री" और "प्रीमियम" बिल्ड वैरिएंट हैं, जिन्हें आपकी 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_ प्रीफ़िक्स न हो, ताकि मौजूदा फ़्लैग के साथ टकराव या भ्रम की स्थिति न हो.
उदाहरण के लिए, सैनिटाइज़र NDK सैंपल देखें.
CMake बिल्ड कमांड के बारे में जानकारी
CMake बिल्ड की समस्याओं को डीबग करते समय, उन खास बिल्ड आर्ग्युमेंट के बारे में जानना मददगार होता है जिनका इस्तेमाल Gradle, Android के लिए क्रॉस-कंपाइलिंग करते समय करता है.
Android Gradle प्लग इन, हर एबीआई और बिल्ड टाइप पेयर के लिए, CMake बिल्ड को एक्ज़ीक्यूट करने के लिए इस्तेमाल किए जाने वाले बिल्ड आर्ग्युमेंट को build_command.txt में सेव करता है. ये फ़ाइलें, इस डायरेक्ट्री में मौजूद होती हैं:
<project-root>/<module-root>/.cxx/cmake/<build-type>/<ABI>/
यहां दिए गए स्निपेट में, armeabi-v7a आर्किटेक्चर को टारगेट करने वाले hello-jni सैंपल के डीबग किए जा सकने वाले रिलीज़ को बिल्ड करने के लिए, CMake आर्ग्युमेंट का एक उदाहरण दिखाया गया है.
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 के साथ पहले से बनी
लाइब्रेरी का इस्तेमाल करने के निर्देश देखने के लिए, add_library दस्तावेज़ में IMPORTED
टारगेट के बारे में CMake मैन्युअल देखें.
तीसरे पक्ष का कोड बिल्ड करना
तीसरे पक्ष के कोड को अपने CMake प्रोजेक्ट के हिस्से के तौर पर बिल्ड करने के कुछ तरीके हैं. आपके लिए कौनसा विकल्प सबसे सही है, यह आपकी स्थिति पर निर्भर करेगा. अक्सर, सबसे सही विकल्प यह होता है कि ऐसा न किया जाए. इसके बजाय, लाइब्रेरी के लिए AAR बनाएं और उसे अपने ऐप्लिकेशन में इस्तेमाल करें. ज़रूरी नहीं है कि उस AAR को पब्लिश किया जाए. यह आपके Gradle प्रोजेक्ट के अंदरूनी तौर पर इस्तेमाल किया जा सकता है.
अगर यह विकल्प नहीं है, तो:
- तीसरे पक्ष के सोर्स को अपनी रिपॉज़िटरी में कॉपी करें और उसे बिल्ड करने के लिए add_subdirectory का इस्तेमाल करें. यह सिर्फ़ तब काम करता है, जब दूसरी लाइब्रेरी भी CMake की मदद से बिल्ड की गई हो.
- एक ExternalProject तय करें.
- लाइब्रेरी को अपने प्रोजेक्ट से अलग बिल्ड करें और उसे पहले से बने तौर पर इंपोर्ट करने के लिए, पहले से बनी लाइब्रेरी का इस्तेमाल करना लेख में दिया गया तरीका अपनाएं.
CMake में YASM की सहायता
NDK, x86 और x86-64 आर्किटेक्चर पर चलने के लिए, YASM में लिखे गए असेंबली कोड को बिल्ड करने के लिए, CMake की सहायता उपलब्ध कराता है. YASM, x86 और x86-64 आर्किटेक्चर के लिए एक ओपन-सोर्स असेंबलर है. यह NASM असेंबलर पर आधारित है.
CMake की मदद से असेंबली कोड बिल्ड करने के लिए, अपने प्रोजेक्ट की CMakeLists.txt में ये बदलाव करें:
enable_languageकोASM_NASMपर सेट की गई वैल्यू के साथ कॉल करें.- यह इस पर निर्भर करता है कि शेयर की गई लाइब्रेरी या एक्ज़ीक्यूटेबल
बाइनरी बिल्ड की जा रही है या नहीं. इसके लिए,
add_libraryयाadd_executableको कॉल करें. आर्ग्युमेंट में, सोर्स फ़ाइलों की सूची पास करें. इसमें YASM में असेंबली प्रोग्राम के लिए.asmफ़ाइलें और उससे जुड़ी C लाइब्रेरी या फ़ंक्शन के लिए.cफ़ाइलें शामिल हों.
यहां दिए गए स्निपेट में, शेयर की गई लाइब्रेरी के तौर पर YASM प्रोग्राम को बिल्ड करने के लिए, CMakeLists.txt को कॉन्फ़िगर करने का तरीका दिखाया गया है.
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 में गड़बड़ी की शिकायत करें.