C++ लाइब्रेरी से जुड़ी सहायता

NDK, कई C++ रनटाइम लाइब्रेरी के साथ काम करता है. यह दस्तावेज़ उपलब्ध कराता है इन लाइब्रेरी के बारे में जानकारी, इसमें हुए नुकसान, और इन्हें इस्तेमाल करने का तरीका.

C++ रनटाइम लाइब्रेरी

टेबल 1. NDK C++ रनटाइम और सुविधाएं.

नाम सुविधाएं
libc++ C++ की नई सुविधाएं.
सिस्टम new और delete. (r18 में अब काम नहीं करता.)
कोई नहीं कोई हेडर नहीं, C++ की संख्या सीमित है.

libc++, स्टैटिक और शेयर की गई लाइब्रेरी, दोनों के तौर पर उपलब्ध है.

libc++

LLVM का libc++ C++ स्टैंडर्ड है ऐसी लाइब्रेरी जिसका इस्तेमाल Android OS में Lollipop से और NDK r18 के बाद से किया जा रहा है एनडीके में सिर्फ़ एसटीएल उपलब्ध है.

C++ clang के किसी भी वर्शन के लिए डिफ़ॉल्ट रूप से C+ का इस्तेमाल करें (फ़िलहाल, C++14 है), इसलिए, आपको स्टैंडर्ड CMAKE_CXX_STANDARD को सही वैल्यू पर सेट करना होगा अपनी CMakeLists.txt फ़ाइल में C++17 या उसके बाद के वर्शन की सुविधाओं का इस्तेमाल करें. CMaker देखें CMAKE_CXX_STANDARD का दस्तावेज़ देखें.

ndk-build डिफ़ॉल्ट रूप से, ndk-build उपयोगकर्ता को चुनने का फ़ैसला करता है को APP_CPPFLAGS का इस्तेमाल करके -std=c++17 या अपनी पसंद की कोई भी चीज़ जोड़नी चाहिए.

libc++ की शेयर की गई लाइब्रेरी libc++_shared.so और स्टैटिक है लाइब्रेरी libc++_static.a है. सामान्य मामलों में बिल्ड सिस्टम, इस्तेमाल करने और इन लाइब्रेरी को पैक करने का काम करता है. असामान्य मामलों के लिए या अपना बिल्ड सिस्टम लागू करते समय, बिल्ड सिस्टम मेंटेनर देखें गाइड या अन्य बिल्ड सिस्टम का इस्तेमाल करने के बारे में जानकारी देने वाली गाइड.

एलएलवीएम प्रोजेक्ट, एलएलवीएम अपवादों के साथ Apache लाइसेंस v2.0 में उपलब्ध है. ज़्यादा के लिए तो लाइसेंस फ़ाइल देखें.

सिस्‍टम

सिस्टम का रनटाइम, /system/lib/libstdc++.so से जुड़ा है. इस लाइब्रेरी को ये नहीं करना चाहिए और GNU के सभी सुविधाओं वाले libstdc++ में उलझन में पड़ सकता है. Android पर, libstdc++ बस new और delete. सभी सुविधाओं वाली C++ स्टैंडर्ड लाइब्रेरी के लिए, libc++ का इस्तेमाल करें.

सिस्टम C++ रनटाइम, बेसिक C++ रनटाइम एबीआई के साथ काम करता है. दरअसल, इस लाइब्रेरी में new और delete मौजूद हैं. इसके विपरीत एनडीके में उपलब्ध विकल्प हैं, लेकिन अपवाद के तौर पर हैंडल करने के लिए कोई सहायता उपलब्ध नहीं है या आरटीआई.

C के लिए C++ रैपर के अलावा कोई मानक लाइब्रेरी काम नहीं करती है लाइब्रेरी हेडर, जैसे कि <cstdio>. अगर आपको STL कॉन्टेंट चाहिए, तो इनमें से किसी एक का इस्तेमाल करें: इस पेज पर दिए गए अन्य विकल्पों के बारे में ज़्यादा जानें.

कोई नहीं

ऐसा भी हो सकता है कि कोई एसटीएल न हो. कोई लिंक या लाइसेंस नहीं है ज़रूरी शर्तें पूरी की है. C++ स्टैंडर्ड हेडर उपलब्ध नहीं हैं.

C++ रनटाइम चुनना

सीमेक

CMake का डिफ़ॉल्ट मान c++_static है.

आप इसका इस्तेमाल करके c++_shared, c++_static, none या system तय कर सकते हैं आपकी मॉड्यूल-लेवल की build.gradle फ़ाइल में ANDROID_STL वैरिएबल. ज़्यादा जानने के लिए, इसमें ANDROID_STL के लिए दस्तावेज़ देखें सीमेक करें.

एनडीके-बिल्ड

Nndk-build के लिए डिफ़ॉल्ट, none है.

आप इसका इस्तेमाल करके c++_shared, c++_static, none या system तय कर सकते हैं आपकी Application.mk फ़ाइल में APP_STL वैरिएबल. उदाहरण के लिए:

APP_STL := c++_shared

ndk-build आपको अपने ऐप्लिकेशन के लिए सिर्फ़ एक रनटाइम चुनने देता है. ऐसा सिर्फ़ Application.mk.

सीधे clang का इस्तेमाल करें

अगर आपने सीधे अपने बिल्ड सिस्टम में clang का इस्तेमाल किया है, तो clang++ डिफ़ॉल्ट रूप से c++_shared. स्टैटिक वैरिएंट का इस्तेमाल करने के लिए, -static-libstdc++ को इसमें जोड़ें आपके लिंकर फ़्लैग. ध्यान दें कि हालांकि, इस विकल्प में "libstdc++" नाम का इस्तेमाल किया जाएगा इसके लिए ऐतिहासिक वजहों से, यह libc++ के लिए भी सही है.

ज़रूरी बातें

स्टैटिक रनटाइम

अगर आपके ऐप्लिकेशन का पूरा कोड, शेयर की गई किसी एक ही जगह पर है लाइब्रेरी के तौर पर, हम स्टैटिक रनटाइम का इस्तेमाल करने का सुझाव देते हैं. इससे लिंकर को इस्तेमाल न होने वाले कोड को इनलाइन और छोटा करें. इससे, सबसे सही तरीके से ऑप्टिमाइज़ किया जा सकता है और सबसे छोटा प्रयोग संभव है. यह PackageManager और डाइनैमिक Android के पुराने वर्शन में मौजूद लिंकर से जुड़ी गड़बड़ियां, जो कई शेयर की जाने वाली चीज़ों को मैनेज करती हैं मुश्किल है और गड़बड़ी की संभावना है.

इसलिए, C++ में एक ही फ़ाइल की एक से ज़्यादा कॉपी किसी एक प्रोग्राम में फ़ंक्शन या ऑब्जेक्ट का इस्तेमाल करते हैं. यह पब्लिशर के लिए वन डेफ़िनिशन का नियम, C++ स्टैंडर्ड में मौजूद है.

स्टैटिक रनटाइम (और आम तौर पर स्टैटिक लाइब्रेरी) का इस्तेमाल करते समय, गलती से इस नियम को तोड़ा जा सकता है. उदाहरण के लिए, नीचे दिया गया ऐप्लिकेशन इसे नियम:

# Application.mk
APP_STL := c++_static
# Android.mk

include $(CLEAR_VARS)
LOCAL_MODULE := foo
LOCAL_SRC_FILES := foo.cpp
include $(BUILD_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := bar
LOCAL_SRC_FILES := bar.cpp
LOCAL_SHARED_LIBRARIES := foo
include $(BUILD_SHARED_LIBRARY)

इस स्थिति में, STL, ग्लोबल डेटा और स्टैटिक कंस्ट्रक्टर, दोनों लाइब्रेरी में मौजूद होगा. इस ऐप्लिकेशन का रनटाइम व्यवहार यह है के बारे में जानकारी नहीं है. साथ ही, असल में क्रैश होना काफ़ी आम बात है. अन्य संभावित समस्याएं शामिल करें:

  • एक लाइब्रेरी में असाइन की गई मेमोरी और दूसरी लाइब्रेरी में खाली होने की वजह से, मेमोरी लीक या हीप खराब हो जाता है.
  • libfoo.so में जो अपवाद हैं वे libbar.so में लागू नहीं हो पाए. इसकी वजह से आपका ऐप क्रैश हो जाता है.
  • std::cout की बफ़रिंग ठीक तरह से काम नहीं कर रही है.

व्यवहार से जुड़ी समस्याओं के अलावा, स्टैटिक रनटाइम को एक से ज़्यादा प्रॉम्प्ट से लिंक करना लाइब्रेरी, शेयर की गई हर लाइब्रेरी के कोड की डुप्लीकेट कॉपी बनाएंगी. इससे लाइब्रेरी का साइज़ बढ़ जाएगा आपका ऐप्लिकेशन.

आम तौर पर, C++ रनटाइम के स्टैटिक वैरिएंट का इस्तेमाल सिर्फ़ तब किया जा सकता है, जब आपके पास कोई हो और आपके ऐप्लिकेशन में सिर्फ़ एक शेयर की गई लाइब्रेरी हो.

शेयर किए गए रनटाइम

अगर आपके ऐप्लिकेशन में एक से ज़्यादा शेयर की गई लाइब्रेरी शामिल हैं, तो आपको libc++_shared.so.

Android पर, एनडीके में इस्तेमाल किया जाने वाला libc++, जो इस हिस्से का हिस्सा है ओएस वाले डिवाइस के नाम हैं. इससे NDK के उपयोगकर्ताओं को libc++ की नई सुविधाओं और बग का ऐक्सेस मिलता है और Android के पुराने वर्शन को टारगेट करते समय भी सुधार किए जा सकते हैं. समस्या यह है कि अगर आपको libc++_shared.so का इस्तेमाल करते हैं, तो आपको इसे अपने ऐप्लिकेशन में शामिल करना होगा. अगर आपको ऐप्लिकेशन को Gradle के साथ कैसे मैनेज किया जाता है. इसे अपने-आप मैनेज किया जाता है.

Android के पुराने वर्शन में PackageManager और डाइनैमिक लिंकर में गड़बड़ियां थीं जिसकी वजह से नेटिव लाइब्रेरी को इंस्टॉल, अपडेट, और लोड करने में भरोसेमंद नहीं है. खास तौर पर, अगर आपका ऐप्लिकेशन Android के किसी पुराने वर्शन को टारगेट करता है और libc++_shared.so का इस्तेमाल करते हैं, तो को इस पर निर्भर किसी अन्य लाइब्रेरी से पहले शेयर की गई लाइब्रेरी लोड करनी चाहिए.

ReLinker प्रोजेक्ट आम तौर पर, नेटिव लाइब्रेरी लोड होने में आने वाली सभी समस्याओं को ठीक करने के तरीके हैं. आम तौर पर, सुझाव है, जिससे बेहतर होगा कि आप कोई तरीका न लिखें.

हर ऐप्लिकेशन के लिए एक एसटीएल

अब तक NDK, libc++ के अलावा, GNU libstdc++ और STLport का इस्तेमाल करता था. अगर आपका ऐप्लिकेशन पहले से बनी ऐसी लाइब्रेरी पर निर्भर है जिसे एनडीके से बनाया गया था जो आपका ऐप्लिकेशन बनाने में इस्तेमाल किया गया है, उससे अलग है, तो आपको पक्का करना होगा कि कि वह ऐसा संगत तरीके से करे.

किसी ऐप्लिकेशन को एक से ज़्यादा C++ रनटाइम का इस्तेमाल नहीं करना चाहिए. अलग-अलग एसटीएल एक-दूसरे के साथ काम नहीं करते. उदाहरण के लिए, std::string का लेआउट libc++ में, ग्नुस्टल के मुताबिक़ अलग-अलग है. एक एसटीएल के लिए लिखा गया कोड किसी अन्य के ख़िलाफ़ लिखी गई चीज़ों का इस्तेमाल करने में सक्षम न हो. यह सिर्फ़ एक उदाहरण है; साथ ही, कई गड़बड़ियां हो सकती हैं.

यह नियम आपके कोड के अलावा अन्य जगहों पर भी लागू होता है. आपकी सभी डिपेंडेंसी एक ही तरह से इस्तेमाल होनी चाहिए वह एसटीएल जो आपने चुना है. अगर आप किसी क्लोज़्ड सोर्स के तीसरे पक्ष पर निर्भर हैं ऐसी डिपेंडेंसी जो एसटीएल का इस्तेमाल करती है और हर एसटीएल के लिए लाइब्रेरी उपलब्ध नहीं कराती, STL में कोई विकल्प होता है. आपको उसी एसटीएल का इस्तेमाल करना होगा जिसका इस्तेमाल आपकी डिपेंडेंसी के लिए किया गया है.

यह संभव है कि आप दो परस्पर असंगत लाइब्रेरी पर निर्भर रहें. तय सीमा में ऐसी स्थिति में, किसी एक निर्भरता को छोड़ना या रखरखाव करने वाला होगा, ताकि अन्य एसटीएल के लिए बनाई गई लाइब्रेरी हो.

C++ अपवाद

C++ अपवाद, libc++ में काम करते हैं, लेकिन वे ndk-build. इसकी वजह यह है कि C++ के पुराने अपवाद, एनडीके. CMake और स्टैंडअलोन टूलचेन में, C++ अपवाद डिफ़ॉल्ट रूप से चालू होते हैं.

ndk-build में अपने पूरे ऐप्लिकेशन में अपवादों को चालू करने के लिए, आपकी Application.mk फ़ाइल के लिए:

APP_CPPFLAGS := -fexceptions

किसी एनडीके-बिल्ड मॉड्यूल के लिए अपवादों को चालू करने के लिए, नीचे दी गई लाइन जोड़ें दिए गए मॉड्यूल को उसके Android.mk में:

LOCAL_CPP_FEATURES := exceptions

इसके अलावा, ये तरीके भी इस्तेमाल किए जा सकते हैं:

LOCAL_CPPFLAGS := -fexceptions

आरटीटीआई

अपवादों की तरह, RTTI libc++ पर भी काम करता है. हालांकि, यह डिफ़ॉल्ट रूप से ndk-build. CMake और स्टैंडअलोन टूलचेन में, आरटीआई डिफ़ॉल्ट रूप से चालू होता है.

ndk-build में अपने पूरे ऐप्लिकेशन में RTTI चालू करने के लिए, इन्हें जोड़ें लाइन को अपनी Application.mk फ़ाइल में जोड़ें:

APP_CPPFLAGS := -frtti

सिंगल एनडीके-बिल्ड मॉड्यूल के लिए आरटीटीआई को चालू करने के लिए, नीचे दी गई लाइन इसके Android.mk में दिया गया मॉड्यूल:

LOCAL_CPP_FEATURES := rtti

इसके अलावा, ये तरीके भी इस्तेमाल किए जा सकते हैं:

LOCAL_CPPFLAGS := -frtti