इस दस्तावेज़ में, एनडीके का इस्तेमाल करते समय होने वाली उन सामान्य समस्याओं की सूची दी गई है जो बग नहीं हैं. साथ ही, इनमें उन समस्याओं को हल करने के तरीके भी बताए गए हैं (अगर उपलब्ध हों).
पुराने एपीआई लेवल के साथ _FILE_OFFSET_BITS=64 का इस्तेमाल करना
यूनिफ़ाइड हेडर से पहले, एनडीके, _FILE_OFFSET_BITS=64 के साथ काम नहीं करता था. अगर आपने अपना ऐप्लिकेशन बनाते समय इसे तय किया था, तो इसे अनदेखा कर दिया गया था. अब यूनिफ़ाइड हेडर के साथ _FILE_OFFSET_BITS=64 विकल्प काम करता है. हालांकि, Android के पुराने वर्शन में, off_t एपीआई में से बहुत कम एपीआई, off64_t वैरिएंट के तौर पर उपलब्ध थे. इसलिए, पुराने एपीआई लेवल के साथ इस सुविधा का इस्तेमाल करने पर, कम फ़ंक्शन उपलब्ध होते हैं.
इस समस्या के बारे में ज़्यादा जानकारी, r16 के ब्लॉग पोस्ट और bionic के दस्तावेज़ में दी गई है.
समस्या: आपका बिल्ड, ऐसे एपीआई के लिए अनुरोध कर रहा है जो आपके
minSdkVersion में मौजूद नहीं हैं.
हल: _FILE_OFFSET_BITS=64 को बंद करें या अपने minSdkVersion को बढ़ाएं.
mmap की जानकारी न देना या इसका मतलब साफ़ तौर पर न बताना
आपको C++ में यह गड़बड़ी दिख सकती है:
error: use of undeclared identifier 'mmap'
या C में यह गड़बड़ी दिख सकती है:
warning: implicit declaration of function 'mmap' is invalid in C99
_FILE_OFFSET_BITS=64 का इस्तेमाल करने पर, C लाइब्रेरी को
mmap के बजाय mmap64 का इस्तेमाल करने का निर्देश मिलता है. mmap64, android-21 तक उपलब्ध नहीं था. अगर आपके minSdkVersion की वैल्यू 21 से कम है, तो C लाइब्रेरी में ऐसा mmap नहीं होता जो _FILE_OFFSET_BITS=64 के साथ काम कर सके. इसलिए, यह फ़ंक्शन उपलब्ध नहीं होता.
डिवाइस के एपीआई लेवल से ज़्यादा minSdkVersion सेट करना
एनडीके के साथ जिस एपीआई लेवल के लिए बिल्ड किया जाता है उसका मतलब, Java के लिए compileSdkVersion के मतलब से अलग होता है. एनडीके एपीआई लेवल, आपके ऐप्लिकेशन का कम से कम ऐसा एपीआई लेवल होता है जिस पर वह काम कर सकता है. ndk-build में, यह आपकी APP_PLATFORM सेटिंग होती है. CMake में, यह -DANDROID_PLATFORM होती है.
आम तौर पर, फ़ंक्शन के रेफ़रंस तब हल किए जाते हैं, जब लाइब्रेरी लोड की जाती हैं. न कि तब, जब उन्हें पहली बार कॉल किया जाता है. इसलिए, ऐसे एपीआई को रेफ़रंस नहीं किया जा सकता जो हमेशा मौजूद नहीं होते. साथ ही, एपीआई लेवल की जांच करके उनके इस्तेमाल को सुरक्षित नहीं किया जा सकता. अगर उन्हें रेफ़रंस किया जाता है, तो वे मौजूद होने चाहिए.
समस्या: आपका एनडीके एपीआई लेवल, आपके डिवाइस के एपीआई लेवल से ज़्यादा है.
हल: अपने एनडीके एपीआई लेवल (APP_PLATFORM) को Android के उस कम से कम वर्शन
पर सेट करें जिस पर आपका ऐप्लिकेशन काम करता है.
| बिल्ड सिस्टम | सेटिंग |
|---|---|
| ndk-build | APP_PLATFORM |
| CMake | ANDROID_PLATFORM |
| externalNativeBuild | android.minSdkVersion |
अन्य बिल्ड सिस्टम के लिए, अन्य बिल्ड सिस्टम के साथ एनडीके का इस्तेमाल करना लेख पढ़ें.
__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 जोड़ें.
गड़बड़ी के इस मैसेज के लिए:
error: undefined reference to '
__atomic_exchange_4'
यहां असल सिंबल, __atomic_ से शुरू होने वाला कोई भी सिंबल हो सकता है.
लाइब्रेरी की सीमाओं के बीच, RTTI/अपवाद काम नहीं कर रहे हैं
समस्या: शेयर की गई लाइब्रेरी की सीमाओं के बीच, अपवादों को पकड़ा नहीं जा रहा है या dynamic_cast काम नहीं कर रहा है.
हल: अपने टाइप में एक मुख्य फ़ंक्शन जोड़ें. मुख्य फ़ंक्शन, किसी टाइप के लिए पहला नॉन-प्योर, आउट-ऑफ़-लाइन वर्चुअल फ़ंक्शन होता है. उदाहरण के लिए, समस्या 533 पर चर्चा देखें.
C++ ABI के मुताबिक, दो ऑब्जेक्ट का टाइप एक ही होता है, अगर और
सिर्फ़ तब, जब उनके type_info पॉइंटर एक जैसे हों. अपवाद सिर्फ़ तब पकड़े जा सकते हैं, जब कैच के लिए type_info, थ्रो किए गए अपवाद से मेल खाता हो. dynamic_cast के लिए भी यही नियम लागू होता है.
जब किसी टाइप में मुख्य फ़ंक्शन नहीं होता, तो उसका typeinfo एक कमज़ोर सिंबल के तौर पर दिखता है. साथ ही, लाइब्रेरी लोड होने पर, मैच करने वाले टाइप की जानकारी मर्ज हो जाती है. जब एक्ज़ीक्यूटेबल लोड होने के बाद, लाइब्रेरी को डाइनैमिक तरीके से लोड किया जाता है (दूसरे शब्दों में, dlopen या System.loadLibrary के ज़रिए), तो हो सकता है कि लोडर, लोड की गई लाइब्रेरी के लिए टाइप की जानकारी मर्ज न कर पाए. ऐसा होने पर, दोनों टाइप को एक जैसा नहीं माना जाता.
पहले से बनी हुई, अलग-अलग लाइब्रेरी का इस्तेमाल करना
अपने ऐप्लिकेशन में पहले से बनी हुई लाइब्रेरी का इस्तेमाल करने के लिए, ज़्यादा सावधानी बरतनी पड़ती है. आम तौर पर, ये तीसरे पक्ष की लाइब्रेरी होती हैं. आम तौर पर, इन नियमों के बारे में जानें:
बनने वाले ऐप्लिकेशन का कम से कम एपीआई लेवल, ऐप्लिकेशन की सभी लाइब्रेरी के
minSdkVersionमें से सबसे ज़्यादा होता है.अगर आपका
minSdkVersion16 है, लेकिन आपने पहले से बनी हुई ऐसी लाइब्रेरी का इस्तेमाल किया है जिसे 21 के लिए बनाया गया है, तो बनने वाले ऐप्लिकेशन का कम से कम एपीआई लेवल 21 होगा. अगर पहले से बनी हुई लाइब्रेरी स्टैटिक है, तो बिल्ड टाइम पर इस नियम का पालन न करने पर गड़बड़ी दिखेगी. हालांकि, शेयर की गई पहले से बनी हुई लाइब्रेरी के लिए, रन टाइम तक गड़बड़ी नहीं दिख सकती है.सभी लाइब्रेरी, एनडीके के एक ही वर्शन से जनरेट की जानी चाहिए.
यह नियम, ज़्यादातर नियमों की तुलना में थोड़ा ज़्यादा फ़्लेक्सिबल है, क्योंकि इसमें गड़बड़ियां कम होती हैं. हालांकि, एनडीके के अलग-अलग मुख्य वर्शन से बनाई गई लाइब्रेरी के बीच, कंपैटिबिलिटी की कोई गारंटी नहीं होती. C++ ABI स्टेबल नहीं है और इसमें पहले भी बदलाव हो चुके हैं.
शेयर की गई एक से ज़्यादा लाइब्रेरी वाले ऐप्लिकेशन में, शेयर की गई एसटीएल का इस्तेमाल करना ज़रूरी है.
अलग-अलग एसटीएल की तरह, इस वजह से होने वाली समस्याओं से भी बचा जा सकता है. हालांकि, इसके लिए ज़्यादा सावधानी बरतनी पड़ती है. इसलिए, बेहतर है कि इस समस्या से बचा जाए. इस समस्या से बचने का सबसे अच्छा तरीका है कि अपने ऐप्लिकेशन में शेयर की गई एक से ज़्यादा लाइब्रेरी का इस्तेमाल न किया जाए.