المشاكل الشائعة وحلولها

يُعد هذا المستند قائمة جزئية بالأخطاء الشائعة التي قد تواجهها عند استخدام 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:

تحذير: التعريف الضمني للدالة 'mmap' غير صالح في C99

يؤدي استخدام _FILE_OFFSET_BITS=64 إلى توجيه مكتبة C إلى استخدام mmap64 بدلاً من mmap. لم يكن mmap64 متاحًا حتى android-21. إذا كانت قيمة minSdkVersion أقل من 21، لن تحتوي المكتبة C على mmap متوافق مع _FILE_OFFSET_BITS=64، وبالتالي تكون الدالة غير متاحة.

تم ضبط minSdkVersion على مستوى أعلى من مستوى واجهة برمجة التطبيقات للجهاز.

يحمل مستوى واجهة برمجة التطبيقات الذي يتم إنشاؤه باستخدام NDK معنى مختلف تمامًا عن معنى compileSdkVersion في لغة Java. مستوى NDK API هو الحد الأدنى من مستوى واجهة برمجة التطبيقات المتوافق في تطبيقك. في ndk-build، هذا هو إعداد APP_PLATFORM. مع CMake، يمثل -DANDROID_PLATFORM.

وبما أنّ مراجع الدوال يتم حلها عادةً عند تحميل المكتبات بدلاً من استدعائها أول مرة، لا يمكنك الرجوع إلى واجهات برمجة التطبيقات غير المتوفّرة دائمًا والتي تحمي استخدامها من خلال عمليات فحص مستوى واجهة برمجة التطبيقات. إذا يُشار إليها على الإطلاق، فيجب أن تكون موجودة.

المشكلة: مستوى واجهة برمجة تطبيقات NDK أعلى من مستوى واجهة برمجة التطبيقات المتوافق مع جهازك.

الحل: عليك ضبط مستوى واجهة برمجة تطبيقات NDK (APP_PLATFORM) على الحد الأدنى من إصدار Android الذي يتوافق مع تطبيقك.

نظام الإصدار الإعداد
نموذج ndk APP_PLATFORM
أداة CMaker ANDROID_PLATFORM
externalNativeBuild android.minSdkVersion

وبالنسبة إلى أنظمة الإصدار الأخرى، راجِع استخدام NDK مع أنظمة الإصدار الأخرى.

يتعذّر تحديد موقع رموز __aeabi

الرسالة التالية:

UnsatisfiedLinkError: dlopen تعذّر: لا يمكن تحديد موقع الرمز "__aeabi_memcpy"

هو أحد الأمثلة على أخطاء وقت التشغيل المحتملة. وتظهر هذه الأخطاء في السجلّ عند محاولة تحميل مكتباتك الأصلية. قد يكون الرمز أيًا من __aeabi_*، و__aeabi_memcpy و__aeabi_memclr هما الأكثر شيوعًا.

تم توثيق هذه المشكلة في العدد 126

يتعذّر تحديد موقع الرمز rand

بالنسبة إلى رسالة سجلّ الخطأ التالية:

UnsatisfiedLinkError: dlopen تعذّر: لا يمكن تحديد موقع الرمز "rand"

اطّلع على إجابة Stack Overflow التفصيلية هذه.

مرجع غير محدّد إلى __atomic_*.

المشكلة: تحتاج بعض واجهات ABI إلى libatomic لتوفير بعض أوجه التنفيذ للعمليات الذرية.

الحل: أضِف -latomic عند الربط.

بالنسبة إلى رسالة الخطأ التالية:

خطأ: مرجع غير معروف إلى '__atomic_exchange_4'.

قد يكون الرمز الفعلي هنا أي شيء يبدأ بـ __atomic_.

لا تعمل ميزة "المراسلة النصية في الوقت الفعلي" (RTTI)/الاستثناءات خارج حدود المكتبة

المشكلة: لا يتم اكتشاف الاستثناءات عند طرحها عبر حدود المكتبة المشتركة، أو عند إخفاق dynamic_cast.

الحل: أضف دالة رئيسية إلى أنواعك. الدالة الرئيسية هي أول دالة افتراضية غير نقية خارجة عن السطر لنوع ما. على سبيل المثال، راجِع المناقشة بشأن المشكلة 533.

تنص C++ ABI على أنّ كائنين لهما النوع نفسه إذا كانت مؤشرات type_info متطابقة. قد لا يتم رصد الاستثناءات إلا إذا كان type_info للاصطياد يتطابق مع الاستثناء الذي يتم تنفيذه. تنطبق القاعدة نفسها على dynamic_cast

في حال عدم وجود وظيفة رئيسية لأحد الأنواع، يتم إطلاق typeinfo كرمز ضعيف ويتم دمج معلومات نوع المطابقة عند تحميل المكتبات. عند تحميل المكتبات ديناميكيًا بعد تحميل الملفات القابلة للتنفيذ (بكلمات أخرى، عبر dlopen أو System.loadLibrary)، قد لا يتمكّن المحمِّل من دمج معلومات النوع للمكتبات التي تم تحميلها. عندما يحدث هذا، لا يعتبر النوعان متساويين.

استخدام مكتبات غير متطابقة مسبقة الإنشاء

يتطلب استخدام المكتبات المُنشأة مسبقًا، التي عادةً ما تكون مكتبات تابعة لجهات خارجية، في تطبيقك عناية إضافية. بشكل عام، انتبه إلى القواعد التالية:

  • إنّ الحدّ الأدنى لمستوى واجهة برمجة التطبيقات الناتج للتطبيق هو الحدّ الأقصى لعدد minSdkVersion من مكتبات التطبيق.

    إذا كان عمر minSdkVersion 16 سنة، وكنت تستخدم مكتبة تم إنشاؤها مسبقًا حسب 21، يكون الحدّ الأدنى لمستوى واجهة برمجة التطبيقات الناتج للتطبيق هو 21. إذا كانت المكتبة التي تم إنشاؤها مسبقًا ثابتة، قد يظهر عدم التزامها بذلك في وقت الإنشاء، ولكنّها قد لا تظهر إلا بعد وقت تشغيل المكتبات المشتركة التي تم إنشاؤها مسبقًا.

  • يجب إنشاء جميع المكتبات باستخدام إصدار NDK نفسه.

    تُعد هذه القاعدة أكثر مرونة قليلاً من معظمها نظرًا لندرة حدوث الأعطال، ولكن لا يمكن ضمان التوافق بين المكتبات التي تم إنشاؤها باستخدام إصدارات رئيسية مختلفة من NDK. واجهة التطبيق الثنائية (ABI) في لغة C++ غير مستقرة وتغيرت في الماضي.

  • يجب أن تستخدم التطبيقات ذات المكتبات المشتركة المتعددة STL مشتركة.

    كما هو الحال مع أخطاء STL غير المتطابقة، يمكن تجنب المشكلات الناتجة عن ذلك إذا تم توخي الحذر الشديد، ولكن من الأفضل تجنب المشكلة. أفضل طريقة لتجنب هذه المشكلة هي تجنب وجود مكتبات مشتركة متعددة في تطبيقك.