مشکلات و راه حل های رایج

این سند فهرستی ناقص از رایج‌ترین مشکلات غیرباگ (nonbugs) است که ممکن است هنگام استفاده از NDK با آنها مواجه شوید و راه‌حل‌های آنها (در صورت وجود) نیز ارائه شده است.

استفاده از _FILE_OFFSET_BITS=64 با سطوح API قدیمی‌تر

قبل از سرآیندهای یکپارچه ، NDK _FILE_OFFSET_BITS=64 پشتیبانی نمی‌کرد. اگر هنگام ساخت برنامه آن را تعریف می‌کردید، بی‌سروصدا نادیده گرفته می‌شد. گزینه _FILE_OFFSET_BITS=64 اکنون با سرآیندهای یکپارچه پشتیبانی می‌شود، اما در نسخه‌های قدیمی اندروید تعداد بسیار کمی از APIهای off_t به عنوان یک نوع off64_t در دسترس بودند. بنابراین، استفاده از این ویژگی با سطوح API قدیمی منجر به در دسترس بودن توابع کمتری می‌شود.

این مشکل به طور مفصل در پست وبلاگ r16 و در مستندات bionic توضیح داده شده است.

مشکل : نسخه شما APIهایی را درخواست می‌کند که در minSdkVersion شما وجود ندارند.

راه حل : _FILE_OFFSET_BITS=64 را غیرفعال کنید یا minSdkVersion خود را افزایش دهید.

تعریف اعلام نشده یا ضمنی mmap

ممکن است در زبان برنامه‌نویسی ++C با خطای زیر مواجه شوید:

خطا: استفاده از شناسه‌ی تعریف نشده‌ی 'mmap'

یا خطای زیر در زبان C:

هشدار: اعلان ضمنی تابع 'mmap' در C99 نامعتبر است

استفاده از _FILE_OFFSET_BITS=64 به کتابخانه C دستور می‌دهد که به جای mmap از mmap64 استفاده کند. mmap64 تا زمان android-21 در دسترس نبود. اگر مقدار minSdkVersion شما کمتر از 21 باشد، کتابخانه C حاوی mmap سازگار با _FILE_OFFSET_BITS=64 نیست، بنابراین تابع در دسترس نیست.

minSdkVersion بالاتر از سطح API دستگاه تنظیم شده است

سطح API که شما با NDK می‌سازید، معنای بسیار متفاوتی نسبت به compileSdkVersion برای جاوا دارد. سطح API NDK حداقل سطح API پشتیبانی شده برنامه شماست. در ndk-build، این تنظیم APP_PLATFORM شماست. با CMake، این تنظیم -DANDROID_PLATFORM است.

از آنجایی که ارجاعات به توابع معمولاً هنگام بارگذاری کتابخانه‌ها و نه هنگام اولین فراخوانی آنها، برطرف می‌شوند، نمی‌توانید به APIهایی که همیشه وجود ندارند، ارجاع دهید و استفاده از آنها را با بررسی‌های سطح API محافظت کنید. اگر اصلاً به آنها ارجاع داده می‌شود، باید وجود داشته باشند.

مشکل : سطح API NDK شما بالاتر از API پشتیبانی شده توسط دستگاهتان است.

راه حل : سطح API NDK خود ( APP_PLATFORM ) را روی حداقل نسخه اندرویدی که برنامه شما پشتیبانی می‌کند، تنظیم کنید.

سیستم ساخت تنظیم
ساخت ndk APP_PLATFORM
سی‌میک ANDROID_PLATFORM
externalNativeBuild android.minSdkVersion

برای سایر سیستم‌های ساخت، به بخش «استفاده از NDK با سایر سیستم‌های ساخت» مراجعه کنید.

نمادهای __aeabi قابل پیدا کردن نیستند

پیام زیر:

خطای UnsatisfiedLinkError: dlopen ناموفق بود: نمی‌توان نماد " __aeabi_memcpy " را پیدا کرد

این یک نمونه از خطاهای احتمالی زمان اجرا است. این خطاها هنگام تلاش برای بارگذاری کتابخانه‌های بومی خود در گزارش ظاهر می‌شوند. نماد آن می‌تواند هر یک از __aeabi_* باشد؛ به نظر می‌رسد __aeabi_memcpy و __aeabi_memclr رایج‌ترین آنها باشند.

این مشکل در شماره ۱۲۶ مستند شده است.

نماد rand نمی‌توان پیدا کرد

برای پیام خطای زیر:

خطای UnsatisfiedLinkError: dlopen ناموفق بود: نمی‌توان نماد « rand » را پیدا کرد

به این پاسخ مفصل Stack Overflow مراجعه کنید.

ارجاع تعریف نشده به __atomic_*

مشکل : برخی از ABIها برای ارائه برخی پیاده‌سازی‌ها برای عملیات اتمیک libatomic نیاز دارند.

راه حل : هنگام پیوند دادن، -latomic ‎ را اضافه کنید.

برای پیام خطای زیر:

خطا: ارجاع تعریف نشده به ' __atomic_exchange_4 '

نماد واقعی در اینجا می‌تواند هر چیزی باشد که با پیشوند __atomic_ شروع شود.

RTTI/استثنائات در مرزهای کتابخانه کار نمی‌کنند

مشکل : استثنائات هنگام عبور از مرزهای کتابخانه مشترک، دریافت نمی‌شوند، یا dynamic_cast با شکست مواجه می‌شود.

راه حل : یک تابع کلیدی به انواع خود اضافه کنید. یک تابع کلیدی اولین تابع مجازی غیر خالص و خارج از خط برای یک نوع است. برای مثال، به بحث شماره ۵۳۳ مراجعه کنید.

C++ ABI بیان می‌کند که دو شیء نوع یکسانی دارند اگر و تنها اگر اشاره‌گرهای type_info آنها یکسان باشند. استثناها فقط در صورتی می‌توانند دریافت شوند که type_info مربوط به catch با استثنای ارسالی مطابقت داشته باشد. همین قانون برای dynamic_cast نیز صدق می‌کند.

وقتی یک نوع تابع کلید ندارد، typeinfo آن به عنوان یک نماد ضعیف منتشر می‌شود و اطلاعات نوع منطبق هنگام بارگذاری کتابخانه‌ها ادغام می‌شوند. هنگام بارگذاری پویای کتابخانه‌ها پس از بارگذاری فایل اجرایی (به عبارت دیگر، از طریق dlopen یا System.loadLibrary )، ممکن است لودر نتواند اطلاعات نوع کتابخانه‌های بارگذاری شده را ادغام کند. وقتی این اتفاق می‌افتد، دو نوع برابر در نظر گرفته نمی‌شوند.

استفاده از کتابخانه‌های از پیش ساخته شده‌ی ناهماهنگ

استفاده از کتابخانه‌های از پیش ساخته شده - که معمولاً کتابخانه‌های شخص ثالث هستند - در برنامه شما نیاز به کمی دقت بیشتر دارد. به طور کلی، از قوانین زیر آگاه باشید:

  • حداقل سطح API برنامه‌ی حاصل، حداکثرِ minSdkVersion های تمام کتابخانه‌های برنامه است.

    اگر minSdkVersion شما ۱۶ باشد، اما از یک کتابخانه‌ی از پیش ساخته شده که بر اساس ۲۱ ساخته شده است استفاده می‌کنید، حداقل سطح API برنامه‌ی حاصل ۲۱ خواهد بود. عدم رعایت این مورد در زمان ساخت، در صورت استاتیک بودن کتابخانه‌ی از پیش ساخته شده، قابل مشاهده خواهد بود، اما در مورد کتابخانه‌های اشتراکی از پیش ساخته شده، ممکن است تا زمان اجرا ظاهر نشود.

  • همه کتابخانه‌ها باید با نسخه NDK یکسانی تولید شوند.

    این قانون کمی انعطاف‌پذیرتر از اکثر قوانین است زیرا موارد نقض نادر هستند، اما سازگاری بین کتابخانه‌هایی که با نسخه‌های اصلی مختلف NDK ساخته شده‌اند تضمین شده نیست. C++ ABI پایدار نیست و در گذشته تغییر کرده است.

  • برنامه‌هایی که چندین کتابخانه مشترک دارند باید از یک STL مشترک استفاده کنند.

    همانند STL های نامتناسب، در صورت دقت زیاد می‌توان از مشکلات ناشی از این مورد جلوگیری کرد، اما بهتر است از بروز مشکل جلوگیری شود. بهترین راه برای جلوگیری از این مشکل، جلوگیری از داشتن چندین کتابخانه مشترک در برنامه شماست.