সাধারণ সমস্যা এবং সমাধান

এই ডকুমেন্টটিতে এনডিকে (NDK) ব্যবহার করার সময় আপনি সাধারণত যেসব নন-বাগ-এর সম্মুখীন হতে পারেন, সেগুলোর একটি আংশিক তালিকা এবং সেগুলোর সমাধান (যদি থাকে) দেওয়া হয়েছে।

পুরানো API লেভেলগুলির সাথে _FILE_OFFSET_BITS=64 ব্যবহার করা

ইউনিফাইড হেডার আসার আগে, NDK _FILE_OFFSET_BITS=64 সমর্থন করত না। আপনার অ্যাপ বিল্ড করার সময় যদি আপনি এটি নির্ধারণ করতেন, তবে তা নীরবে উপেক্ষা করা হতো। _FILE_OFFSET_BITS=64 অপশনটি এখন ইউনিফাইড হেডারের সাথে সমর্থিত, কিন্তু অ্যান্ড্রয়েডের পুরোনো সংস্করণগুলিতে off_t API-গুলোর খুব কম সংখ্যকই off64_t ভ্যারিয়েন্ট হিসেবে উপলব্ধ ছিল। তাই, পুরোনো API লেভেলের সাথে এই ফিচারটি ব্যবহার করলে কম সংখ্যক ফাংশন উপলব্ধ হয়।

এই সমস্যাটি r16 ব্লগ পোস্টে এবং বায়োনিক ডকুমেন্টেশনে বিস্তারিতভাবে ব্যাখ্যা করা হয়েছে।

সমস্যা : আপনার বিল্ড এমন API চাইছে যা আপনার minSdkVersion এ নেই।

সমাধান : _FILE_OFFSET_BITS=64 নিষ্ক্রিয় করুন অথবা আপনার minSdkVersion বাড়িয়ে দিন।

mmap এর অঘোষিত বা অন্তর্নিহিত সংজ্ঞা

আপনি C++ এ নিম্নলিখিত ত্রুটিটি দেখতে পারেন:

ত্রুটি: 'mmap' নামক একটি অঘোষিত আইডেন্টিফায়ারের ব্যবহার

অথবা C-তে নিম্নলিখিত ত্রুটি:

সতর্কীকরণ: C99-এ 'mmap' ফাংশনের অন্তর্নিহিত ঘোষণা অবৈধ।

_FILE_OFFSET_BITS=64 ব্যবহার করলে C লাইব্রেরিকে mmap এর পরিবর্তে mmap64 ব্যবহার করার নির্দেশ দেওয়া হয়। android-21 এর আগে mmap64 উপলব্ধ ছিল না। যদি আপনার minSdkVersion মান 21-এর চেয়ে কম হয়, তাহলে C লাইব্রেরিতে _FILE_OFFSET_BITS=64 এর সাথে সামঞ্জস্যপূর্ণ কোনো mmap থাকে না, ফলে ফাংশনটি উপলব্ধ হয় না।

minSdkVersion ডিভাইস API লেভেলের চেয়ে উচ্চতর সেট করা হয়েছে

এনডিকে (NDK) ব্যবহার করে আপনি যে এপিআই লেভেলের (API level) উপর ভিত্তি করে বিল্ড করেন, তার অর্থ জাভার (Java) compileSdkVersion অর্থ থেকে সম্পূর্ণ ভিন্ন। এনডিকে এপিআই লেভেল হলো আপনার অ্যাপের সর্বনিম্ন সমর্থিত এপিআই লেভেল। ndk-build-এ, এটি হলো আপনার APP_PLATFORM সেটিং। সিমেকের (CMake) ক্ষেত্রে, এটি হলো -DANDROID_PLATFORM

যেহেতু ফাংশনের রেফারেন্সগুলো সাধারণত প্রথমবার কল করার সময় নয়, বরং লাইব্রেরি লোড হওয়ার সময় সমাধান করা হয়, তাই আপনি এমন API-কে রেফারেন্স করতে পারবেন না যা সবসময় উপস্থিত থাকে না এবং API লেভেল চেকের মাধ্যমে সেগুলোর ব্যবহার সুরক্ষিত করতে পারবেন না। যদি সেগুলোকে আদৌ রেফারেন্স করা হয়, তবে সেগুলোকে অবশ্যই উপস্থিত থাকতে হবে।

সমস্যা : আপনার NDK API লেভেলটি আপনার ডিভাইস দ্বারা সমর্থিত API-এর চেয়ে উচ্চতর।

সমাধান : আপনার অ্যাপ যে সর্বনিম্ন অ্যান্ড্রয়েড সংস্করণটি সমর্থন করে, সেই অনুযায়ী আপনার NDK API লেভেল ( APP_PLATFORM ) সেট করুন।

বিল্ড সিস্টেম সেটিং
এনডিকে-বিল্ড APP_PLATFORM
CMake ANDROID_PLATFORM
এক্সটার্নালনেটিভবিল্ড android.minSdkVersion

অন্যান্য বিল্ড সিস্টেমের জন্য, “অন্যান্য বিল্ড সিস্টেমের সাথে এনডিকে ব্যবহার করুন” দেখুন।

__aeabi প্রতীকগুলো খুঁজে পাওয়া যাচ্ছে না

নিম্নলিখিত বার্তা:

UnsatisfiedLinkError: dlopen ব্যর্থ হয়েছে: " __aeabi_memcpy " প্রতীকটি সনাক্ত করা যাচ্ছে না

এটি সম্ভাব্য রানটাইম ত্রুটির একটি উদাহরণ। আপনি যখন আপনার নেটিভ লাইব্রেরিগুলো লোড করার চেষ্টা করেন, তখন এই ত্রুটিগুলো লগে দেখা যায়। সিম্বলটি __aeabi_* এর যেকোনো একটি হতে পারে; __aeabi_memcpy এবং __aeabi_memclr সবচেয়ে সাধারণ বলে মনে হয়।

এই সমস্যাটি ইস্যু ১২৬- এ নথিভুক্ত করা হয়েছে।

প্রতীক rand সনাক্ত করা যাচ্ছে না

নিম্নলিখিত ত্রুটি লগ বার্তার জন্য:

UnsatisfiedLinkError: dlopen ব্যর্থ হয়েছে: " rand " প্রতীকটি সনাক্ত করা যাচ্ছে না

এই বিস্তারিত স্ট্যাক ওভারফ্লো উত্তরটি দেখুন।

__atomic_* এর অনির্ধারিত রেফারেন্স

সমস্যা : কিছু ABI-এর অ্যাটমিক অপারেশনের জন্য libatomic নির্দিষ্ট ইমপ্লিমেন্টেশন প্রয়োজন হয়।

সমাধান : লিঙ্কিং করার সময় -latomic যোগ করুন।

নিম্নলিখিত ত্রুটি বার্তার জন্য:

ত্রুটি: ' __atomic_exchange_4 ' এর অনির্ধারিত রেফারেন্স

এখানে প্রকৃত প্রতীকটি __atomic_ উপসর্গযুক্ত যেকোনো কিছুই হতে পারে।

RTTI/ব্যতিক্রমগুলি লাইব্রেরির সীমানা জুড়ে কাজ করছে না

সমস্যা : শেয়ার্ড লাইব্রেরির সীমানা পেরিয়ে এক্সেপশন থ্রো করা হলে তা ধরা পড়ছে না, অথবা dynamic_cast ব্যর্থ হচ্ছে।

সমাধান : আপনার টাইপগুলোতে একটি কী ফাংশন যোগ করুন। কী ফাংশন হলো কোনো টাইপের প্রথম নন-পিওর, আউট-অফ-লাইন ভার্চুয়াল ফাংশন। একটি উদাহরণের জন্য, ইস্যু ৫৩৩- এর আলোচনা দেখুন।

C++ ABI অনুযায়ী, দুটি অবজেক্টের টাইপ একই হবে যদি এবং কেবল যদি তাদের type_info পয়েন্টারগুলো অভিন্ন হয়। এক্সেপশন কেবল তখনই ধরা যেতে পারে, যখন catch-এর type_info thrown এক্সেপশনের সাথে মেলে। dynamic_cast এর ক্ষেত্রেও একই নিয়ম প্রযোজ্য।

যখন কোনো টাইপের কোনো কী ফাংশন থাকে না, তখন তার typeinfo একটি উইক সিম্বল হিসেবে নির্গত হয় এবং লাইব্রেরি লোড করার সময় মিলে যাওয়া টাইপইনফোগুলোকে একত্রিত করা হয়। এক্সিকিউটেবল লোড হওয়ার পরে যখন ডায়নামিকভাবে লাইব্রেরি লোড করা হয় (অন্য কথায়, dlopen বা System.loadLibrary মাধ্যমে), তখন লোডারের পক্ষে লোড করা লাইব্রেরিগুলোর টাইপইনফো একত্রিত করা সম্ভব নাও হতে পারে। যখন এমনটা ঘটে, তখন দুটি টাইপকে সমান বলে গণ্য করা হয় না।

অমিল পূর্ব-নির্মিত লাইব্রেরি ব্যবহার করা

আপনার অ্যাপ্লিকেশনে আগে থেকে তৈরি লাইব্রেরি—যা সাধারণত থার্ড-পার্টি লাইব্রেরি হয়ে থাকে—ব্যবহার করার জন্য কিছুটা বাড়তি সতর্কতার প্রয়োজন। সাধারণভাবে, নিম্নলিখিত নিয়মগুলো সম্পর্কে সচেতন থাকুন:

  • ফলস্বরূপ অ্যাপটির সর্বনিম্ন এপিআই লেভেল হবে অ্যাপটির সমস্ত লাইব্রেরির minSdkVersion গুলোর মধ্যে সর্বোচ্চটি।

    যদি আপনার minSdkVersion ১৬ হয়, কিন্তু আপনি এমন একটি প্রি-বিল্ট লাইব্রেরি ব্যবহার করেন যা ২১-এর জন্য তৈরি করা হয়েছে, তাহলে ফলস্বরূপ অ্যাপটির সর্বনিম্ন API লেভেল হবে ২১। এই নিয়মটি না মানার বিষয়টি প্রি-বিল্ট লাইব্রেরিটি স্ট্যাটিক হলে বিল্ড করার সময়েই চোখে পড়বে, কিন্তু প্রি-বিল্ট শেয়ার্ড লাইব্রেরির ক্ষেত্রে এটি রান টাইমের আগে নাও দেখা যেতে পারে।

  • সকল লাইব্রেরি একই NDK সংস্করণ দিয়ে তৈরি করা উচিত।

    এই নিয়মটি বেশিরভাগের চেয়ে কিছুটা বেশি নমনীয়, কারণ এতে সমস্যা খুব কমই হয়, কিন্তু NDK-এর বিভিন্ন প্রধান সংস্করণ দিয়ে তৈরি লাইব্রেরিগুলোর মধ্যে সামঞ্জস্যের নিশ্চয়তা দেওয়া হয় না। C++ ABI স্থিতিশীল নয় এবং অতীতে এটি পরিবর্তিত হয়েছে।

  • যেসব অ্যাপে একাধিক শেয়ার্ড লাইব্রেরি রয়েছে, সেগুলোতে অবশ্যই একটি শেয়ার্ড STL ব্যবহার করতে হবে।

    বেমানান STL ফাইলের মতোই, যথেষ্ট সতর্কতা অবলম্বন করলে এর কারণে সৃষ্ট সমস্যাগুলো এড়ানো সম্ভব, তবে সমস্যাটি এড়িয়ে চলাই শ্রেয়। এই সমস্যা এড়ানোর সেরা উপায় হলো আপনার অ্যাপে একাধিক শেয়ার্ড লাইব্রেরি ব্যবহার না করা।