सीमेक

Android NDK, आपके ऐप्लिकेशन के लिए C और C++ कोड को संकलित करने के लिए, CMake का इस्तेमाल करता है. इस पेज पर, Android Gradle प्लग इन के ExternalNativeBuild के ज़रिए NDK के साथ CMake का इस्तेमाल करने या सीधे तौर पर CMake को शुरू करने का तरीका बताया गया है.

CMake टूलचेन फ़ाइल

NDK, टूलचेन फ़ाइल की मदद से CMake के साथ काम करता है. टूलचेन फ़ाइलें, CMake फ़ाइलें होती हैं. ये क्रॉस-कंपाइल करने के लिए, टूलचेन के काम करने के तरीके को पसंद के मुताबिक बनाती हैं. एनडीके के लिए इस्तेमाल की जाने वाली टूलचेन फ़ाइल, <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 का इस्तेमाल करके बाइनरी बनाई जा रही है, तो android.defaultConfig.externalNativeBuild.cmake.arguments में आर्ग्युमेंट जोड़ें. इसके लिए, ExternalNativeBuild के दस्तावेज़ में दिया गया तरीका अपनाएं. अगर कमांड लाइन से बिल्ड किया जा रहा है, तो -D के साथ CMake को आर्ग्युमेंट पास करें. उदाहरण के लिए, armeabi-v7a को नियॉन सहायता के साथ न बनाने के लिए, -DANDROID_ARM_NEON=FALSE को पास करें.

ANDROID_ABI

टारगेट एबीआई. काम करने वाले एबीआई के बारे में जानकारी पाने के लिए, Android एबीआई लेख पढ़ें.

Gradle

Gradle यह आर्ग्युमेंट अपने-आप उपलब्ध कराता है. इस तर्क को अपनी build.gradle फ़ाइल में साफ़ तौर पर सेट न करें. एबीआई के ग्रेडल टूल को कंट्रोल करने के लिए, Android एबीआई में बताए गए तरीके के मुताबिक abiFilters का इस्तेमाल करें.

कमांड लाइन

CMake हर बिल्ड के लिए एक टारगेट के लिए बिल्ड करता है. एक से ज़्यादा Android एबीआई को टारगेट करने के लिए, आपको हर एबीआई के लिए एक बार बिल्ड करना होगा. हमारा सुझाव है कि हर एबीआई के लिए अलग-अलग बिल्ड डायरेक्ट्री का इस्तेमाल करें, ताकि बिल्ड के बीच कोई गड़बड़ी न हो.

वैल्यू नोट
armeabi-v7a
armeabi-v7a with NEON armeabi-v7a के बराबर है.
arm64-v8a
x86
x86_64

ANDROID_ARM_MODE

इससे पता चलता है कि armeabi-v7a के लिए, arm या thumb निर्देश जनरेट करने हैं या नहीं. इससे अन्य एबीआई पर कोई असर नहीं पड़ता. ज़्यादा जानकारी के लिए, Android ABIs के दस्तावेज़ देखें.

वैल्यू नोट
बांह
अंगूठा डिफ़ॉल्ट सेटिंग.

ANDROID_NATIVE_API_LEVEL

ANDROID_PLATFORM के लिए उपनाम.

ANDROID_PLATFORM

ऐप्लिकेशन या लाइब्रेरी के साथ काम करने वाला कम से कम एपीआई लेवल तय करता है. यह वैल्यू, ऐप्लिकेशन के minSdkVersion से मेल खाती है.

Gradle

'Android Gradle प्लग इन' का इस्तेमाल करते समय, यह वैल्यू अपने-आप ऐप्लिकेशन के minSdkVersion से मेल खाने के लिए सेट हो जाती है और इसे मैन्युअल रूप से सेट नहीं किया जाना चाहिए.

कमांड लाइन

सीधे CMake का इस्तेमाल करने पर, यह वैल्यू डिफ़ॉल्ट रूप से एनडीके के साथ काम करने वाले सबसे निचले एपीआई लेवल पर सेट हो जाती है. उदाहरण के लिए, NDK r20 के साथ यह वैल्यू डिफ़ॉल्ट रूप से एपीआई लेवल 16 पर सेट होती है.

इस पैरामीटर के लिए एक से ज़्यादा फ़ॉर्मैट स्वीकार किए जाते हैं:

  • android-$API_LEVEL
  • $API_LEVEL
  • android-$API_LETTER

$API_LETTER फ़ॉर्मैट की मदद से, android-N को तय किया जा सकता है. इसके लिए, आपको उस रिलीज़ से जुड़े नंबर का पता लगाने की ज़रूरत नहीं है. ध्यान दें कि कुछ रिलीज़ को बिना अक्षर बढ़ाए ही एपीआई में बढ़ोतरी मिली. इन एपीआई के बारे में बताने के लिए, -MR1 सफ़िक्स जोड़ें. उदाहरण के लिए, एपीआई लेवल 25 को android-N-MR1 लिखा जाता है.

ANDROID_STL

इससे पता चलता है कि इस ऐप्लिकेशन के लिए किस STL का इस्तेमाल करना है. ज़्यादा जानकारी के लिए, C++ लाइब्रेरी के लिए सहायता देखें. डिफ़ॉल्ट रूप से, c++_static का इस्तेमाल किया जाएगा.

वैल्यू नोट
c++_shared libc++ की शेयर की गई लाइब्रेरी का वैरिएंट.
c++_static libc++ का स्टैटिक लाइब्रेरी वैरिएंट.
कोई नहीं C++ स्टैंडर्ड लाइब्रेरी के साथ काम नहीं करता.
सिस्‍टम सिस्टम STL

कंपाइलर फ़्लैग मैनेज करें

अगर आपको अपने बिल्ड के लिए कंपाइलर या लिंकर को खास फ़्लैग पास करने हैं, तो 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_ प्रीफ़िक्स वाले नामों से बचें, ताकि मौजूदा फ़्लैग के साथ कोई गड़बड़ी या भ्रम न हो.

उदाहरण के लिए, Sanitizers NDK सैंपल देखें.

CMake बिल्ड कमांड को समझना

CMake बिल्ड की समस्याओं को डीबग करते समय, आपके लिए उन खास बिल्ड तर्क को जानना मददगार होगा जिनका इस्तेमाल Gradle, Android के लिए क्रॉस-कंपाइलिंग करते समय करता है.

Android Gradle प्लग इन, build_command.txt में हर एबीआई और बिल्ड टाइप के जोड़े के लिए, CMake बिल्ड को लागू करने के लिए इस्तेमाल किए जाने वाले बिल्ड आर्ग्युमेंट सेव करता है. ये फ़ाइलें इस डायरेक्ट्री में मिलती हैं:

<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 के साथ पहले से बनी लाइब्रेरी इस्तेमाल करने के निर्देश देखें. इसके लिए, CMake मैन्युअल में add_library IMPORTED टारगेट के बारे में दस्तावेज़ देखें.

तीसरे पक्ष का कोड बनाना

CMake प्रोजेक्ट के हिस्से के तौर पर, तीसरे पक्ष का कोड बनाने के कुछ तरीके हैं. हालांकि, कौनसा विकल्प सबसे सही रहेगा, यह आपकी स्थिति पर निर्भर करेगा. आम तौर पर, ऐसा न करना ही सबसे अच्छा विकल्प होता है. इसके बजाय, लाइब्रेरी के लिए एक AAR बनाएं और उसे अपने ऐप्लिकेशन में इस्तेमाल करें. हालांकि, आपको उस AAR को पब्लिश करने की ज़रूरत नहीं है. यह आपके Gradle प्रोजेक्ट के लिए इंटरनल हो सकता है.

अगर ऐसा नहीं किया जा सकता, तो:

  • तीसरे पक्ष के सोर्स को अपनी रिपॉज़िटरी में वेंडर (यानी कॉपी) करें और उसे बनाने के लिए, add_subdirectory का इस्तेमाल करें. यह सिर्फ़ तब काम करता है, जब दूसरी लाइब्रेरी को भी CMake की मदद से बनाया गया हो.
  • ExternalProject तय करें.
  • लाइब्रेरी को अपने प्रोजेक्ट से अलग बनाएं और उसे पहले से बने लाइब्रेरी के तौर पर इंपोर्ट करने के लिए, पहले से बने लाइब्रेरी का इस्तेमाल करें लेख पढ़ें.

CMake में YASM की सुविधा

NDK, CMake की सुविधा देता है. इसकी मदद से, YASM में लिखे गए असेंबली कोड को x86 और x86-64 आर्किटेक्चर पर चलाने के लिए बनाया जा सकता है. YASM, NASM असेंबलर पर आधारित, x86 और x86-64 आर्किटेक्चर के लिए एक ओपन-सोर्स असेंबलर है.

CMake की मदद से असेंबली कोड बनाने के लिए, अपने प्रोजेक्ट के CMakeLists.txt में ये बदलाव करें:

  1. ASM_NASM पर सेट की गई वैल्यू के साथ enable_language को कॉल करें.
  2. आप शेयर की गई लाइब्रेरी बना रहे हैं या एक्ज़ीक्यूटेबल बाइनरी, इसके आधार पर, 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 test देखें.

समस्याओं की शिकायत करना

अगर आपको एनडीके या इसकी CMake टूलचेन फ़ाइल में कोई समस्या आती है, तो GitHub पर android-ndk/ndk समस्या को ट्रैक करने वाले टूल की मदद से उनकी शिकायत करें. Gradle या Android Gradle प्लग इन की समस्याओं के लिए, Studio की गड़बड़ी की शिकायत करें.