आम समस्याएं और उनके समाधान

इस दस्तावेज़ में, NDK का इस्तेमाल करते समय आम तौर पर आने वाली उन समस्याओं की सूची दी गई है जो बग नहीं हैं. साथ ही, इनमें से कुछ समस्याओं को हल करने के तरीके भी बताए गए हैं.

एपीआई के पुराने लेवल के साथ _FILE_OFFSET_BITS=64 का इस्तेमाल करना

यूनिफ़ाइड हेडर से पहले, NDK में _FILE_OFFSET_BITS=64 काम नहीं करता था. अगर आपने ऐप्लिकेशन बनाते समय इसे तय किया था, तो इसे अनदेखा कर दिया गया था. _FILE_OFFSET_BITS=64 विकल्प अब यूनिफ़ाइड हेडर के साथ काम करता है. हालांकि, Android के पुराने वर्शन पर off_t एपीआई के बहुत कम off64_t वैरिएंट उपलब्ध थे. इसलिए, पुराने एपीआई लेवल के साथ इस सुविधा का इस्तेमाल करने पर, कम फ़ंक्शन उपलब्ध होते हैं.

इस समस्या के बारे में r16 ब्लॉग पोस्ट और बायोनिक के दस्तावेज़ में ज़्यादा जानकारी दी गई है.

समस्या: आपका बिल्ड, ऐसे एपीआई का अनुरोध कर रहा है जो आपके minSdkVersion में मौजूद नहीं हैं.

समाधान: _FILE_OFFSET_BITS=64 को बंद करें या minSdkVersion को बढ़ाएं.

mmap की परिभाषा का एलान न करना या उसे साफ़ तौर पर न बताना

आपको C++ में यह गड़बड़ी दिख सकती है:

गड़बड़ी: 'mmap' आइडेंटिफ़ायर का इस्तेमाल किया गया है, लेकिन इसे घोषित नहीं किया गया है

या C में यह गड़बड़ी दिखती है:

चेतावनी: C99 में, फ़ंक्शन 'mmap' का इंप्लिसिट एलान अमान्य है

_FILE_OFFSET_BITS=64 का इस्तेमाल करने पर, C लाइब्रेरी को mmap के बजाय mmap64 का इस्तेमाल करने का निर्देश मिलता है. mmap64, android-21 तक उपलब्ध नहीं था. अगर आपकी minSdkVersion वैल्यू 21 से कम है, तो C लाइब्रेरी में ऐसा mmap नहीं है जो _FILE_OFFSET_BITS=64 के साथ काम करता हो. इसलिए, यह फ़ंक्शन उपलब्ध नहीं है.

minSdkVersion को डिवाइस के एपीआई लेवल से ज़्यादा पर सेट किया गया हो

एनडीके के साथ जिस एपीआई लेवल के लिए ऐप्लिकेशन बनाया जाता है उसका मतलब, compileSdkVersion के लिए बनाए गए एपीआई लेवल से बहुत अलग होता है. एनडीके एपीआई लेवल, आपके ऐप्लिकेशन के लिए कम से कम सपोर्ट किया जाने वाला एपीआई लेवल होता है. ndk-build में, यह आपकी APP_PLATFORM सेटिंग है. CMake के साथ, यह -DANDROID_PLATFORM है.

फ़ंक्शन के रेफ़रंस आम तौर पर तब हल किए जाते हैं, जब लाइब्रेरी लोड की जाती हैं. ऐसा तब नहीं होता, जब उन्हें पहली बार कॉल किया जाता है. इसलिए, ऐसे एपीआई को रेफ़रंस नहीं किया जा सकता जो हमेशा मौजूद नहीं होते. साथ ही, एपीआई लेवल की जांचों के साथ उनके इस्तेमाल को सुरक्षित नहीं किया जा सकता. अगर उन्हें शामिल किया गया है, तो उन्हें मौजूद होना चाहिए.

समस्या: आपके डिवाइस पर काम करने वाले एपीआई से ज़्यादा एपीआई लेवल वाला NDK इस्तेमाल किया जा रहा है.

समाधान: अपने NDK एपीआई लेवल (APP_PLATFORM) को Android के उस वर्शन पर सेट करें जिस पर आपका ऐप्लिकेशन काम करता है.

बिल्ड सिस्टम सेटिंग
ndk-build APP_PLATFORM
CMake ANDROID_PLATFORM
externalNativeBuild android.minSdkVersion

अन्य बिल्ड सिस्टम के लिए, अन्य बिल्ड सिस्टम के साथ NDK का इस्तेमाल करना लेख पढ़ें.

__aeabi सिंबल नहीं मिल रहे हैं

यह मैसेज:

UnsatisfiedLinkError: dlopen failed: cannot locate symbol "__aeabi_memcpy"

रनटाइम में होने वाली गड़बड़ियों का एक उदाहरण है. नेटिव लाइब्रेरी लोड करने की कोशिश करते समय, ये गड़बड़ियां लॉग में दिखती हैं. सिंबल इनमें से कोई भी हो सकता है: __aeabi_*; __aeabi_memcpy और __aeabi_memclr सबसे आम सिंबल हैं.

इस समस्या के बारे में समस्या 126 में बताया गया है

सिंबल rand नहीं मिल रहा है

गड़बड़ी के लॉग मैसेज के लिए:

UnsatisfiedLinkError: dlopen failed: cannot locate symbol "rand"

इस बारे में ज़्यादा जानकारी के लिए, Stack Overflow का यह जवाब देखें.

__atomic_* का रेफ़रंस नहीं दिया गया है

समस्या: कुछ एबीआइ को एटॉमिक ऑपरेशनों के लिए, कुछ लागू करने की सुविधा देने के लिए libatomic की ज़रूरत होती है.

समाधान: लिंक करते समय -latomic जोड़ें.

गड़बड़ी के इस मैसेज के लिए:

गड़बड़ी: '__atomic_exchange_4' का रेफ़रंस तय नहीं किया गया है

यहां मौजूद असली सिंबल, __atomic_ से शुरू होने वाला कोई भी सिंबल हो सकता है.

लाइब्रेरी की सीमाओं के हिसाब से, आरटीटीआई/अपवाद काम नहीं कर रहे हैं

समस्या: शेयर की गई लाइब्रेरी की सीमाओं के पार थ्रो किए जाने पर, अपवादों को पकड़ा नहीं जा रहा है या dynamic_cast काम नहीं कर रहा है.

समाधान: अपने टाइप में कुंजी फ़ंक्शन जोड़ें. मुख्य फ़ंक्शन, किसी टाइप के लिए पहला नॉन-प्योर, आउट-ऑफ़-लाइन वर्चुअल फ़ंक्शन होता है. उदाहरण के लिए, समस्या 533 पर हुई चर्चा देखें.

C++ ABI के मुताबिक, दो ऑब्जेक्ट का टाइप एक जैसा तब होता है, जब उनके type_info पॉइंटर एक जैसे हों. अपवाद सिर्फ़ तब पकड़े जा सकते हैं, जब कैच के लिए type_info, थ्रो किए गए अपवाद से मेल खाता हो. dynamic_cast के लिए भी यही नियम लागू होता है.

जब किसी टाइप में मुख्य फ़ंक्शन नहीं होता है, तो उसके typeinfo को कमज़ोर सिंबल के तौर पर दिखाया जाता है. साथ ही, लाइब्रेरी लोड होने पर, मेल खाने वाली टाइप इन्फ़ो को मर्ज कर दिया जाता है. एक्ज़ीक्यूटेबल लोड होने के बाद, लाइब्रेरी को डाइनैमिक तरीके से लोड करने पर (दूसरे शब्दों में कहें, तो dlopen या System.loadLibrary के ज़रिए), ऐसा हो सकता है कि लोडर, लोड की गई लाइब्रेरी के लिए टाइप की जानकारी को मर्ज न कर पाए. ऐसा होने पर, दोनों टाइप को एक जैसा नहीं माना जाता.

पहले से बनी हुई ऐसी लाइब्रेरी का इस्तेमाल करना जो मेल नहीं खाती हैं

अपने ऐप्लिकेशन में पहले से बनी लाइब्रेरी का इस्तेमाल करने के लिए, आपको कुछ अतिरिक्त बातों का ध्यान रखना होगा. आम तौर पर, ये तीसरे पक्ष की लाइब्रेरी होती हैं. आम तौर पर, इन नियमों के बारे में जानें:

  • ऐप्लिकेशन का सबसे निचला एपीआई लेवल, ऐप्लिकेशन की सभी लाइब्रेरी के minSdkVersions में से सबसे ज़्यादा होता है.

    अगर आपका minSdkVersion 16 है, लेकिन आपने पहले से बनी हुई ऐसी लाइब्रेरी का इस्तेमाल किया है जिसे 21 के हिसाब से बनाया गया था, तो ऐप्लिकेशन का कम से कम एपीआई लेवल 21 होगा. इसका पालन न करने पर, बिल्ड टाइम में यह दिखेगा. हालांकि, ऐसा तब होगा, जब पहले से बनी लाइब्रेरी स्टैटिक हो. पहले से बनी शेयर की गई लाइब्रेरी के लिए, यह रन टाइम तक नहीं दिख सकता.

  • सभी लाइब्रेरी, एक ही NDK वर्शन से जनरेट की जानी चाहिए.

    यह नियम ज़्यादातर नियमों की तुलना में थोड़ा ज़्यादा लचीला है, क्योंकि इसमें लाइब्रेरी के टूटने की समस्या कम ही होती है. हालांकि, अलग-अलग मुख्य वर्शन वाले NDK से बनाई गई लाइब्रेरी के बीच कंपैटिबिलिटी की गारंटी नहीं दी जाती. C++ ABI स्थिर नहीं है और इसमें पहले भी बदलाव हो चुका है.

  • एक से ज़्यादा शेयर की गई लाइब्रेरी वाले ऐप्लिकेशन को शेयर की गई एसटीएल का इस्तेमाल करना होगा.

    एसटीएल फ़ाइलों के मेल न खाने की वजह से होने वाली समस्याओं से बचा जा सकता है. हालांकि, इसके लिए बहुत सावधानी बरतनी पड़ती है. इसलिए, बेहतर होगा कि इस समस्या से बचा जाए. इस समस्या से बचने का सबसे अच्छा तरीका यह है कि अपने ऐप्लिकेशन में एक से ज़्यादा शेयर की गई लाइब्रेरी न रखें.