تتوافق اتفاقية عدم الإفشاء مع مكتبات وقت التشغيل التي تستخدم C++. يقدّم هذا المستند معلومات عن هذه المكتبات والمفاضلات وطريقة استخدامها.
مكتبات وقت تشغيل C++
الجدول 1: أوقات تشغيل وميزات CND C++
الاسم | الميزات |
---|---|
libc++ | إتاحة خدمات C++ حديثة |
النظام | new وdelete (تم إيقاف العمل به في الإصدار r18). |
بلا | لا توجد عناوين، C++ محدود. |
تتوفر مكتبة libc+ كمكتبة ثابتة ومشتركة.
libc+
مكتبة LLVM + + هي مكتبة C++ العادية التي يستخدمها نظام التشغيل Android منذ Lollipop، واعتبارًا من NDK r18 هو اشتراك STL الوحيد المتاح في NDK.
اضبط Cالإعدادات التلقائية على أي إصدار من لغة C++ التلقائية وضبطها حاليًا على C++14، لذلك ستحتاج إلى ضبط القيمة CMAKE_CXX_STANDARD
العادية على القيمة المناسبة في ملف CMakeLists.txt
لاستخدام الميزات C++17 أو الإصدارات الأحدث. اطّلِع على مستندات CCMAKE_CXX_STANDARD
الخاصة بـ CMAKE_CXX_STANDARD
للحصول على مزيد من التفاصيل.
يترك ndk-build أيضًا القرار بالانتماء إلى مجموعة، لذلك يجب على مستخدمي الإصدار ndk استخدام APP_CPPFLAGS
لإضافة -std=c++17
أو ما يريدونه بدلاً من ذلك.
المكتبة المشتركة للإصدار libc+ هي libc++_shared.so
والمكتبة الثابتة هي libc++_static.a
. في الحالات العادية، سيعالج نظام الإصدار
هذه المكتبات وتعبّئها حسب الحاجة للمستخدم. بالنسبة إلى الحالات غير النموذجية
أو عند تنفيذ نظام الإصدار الخاص بك، يُرجى الاطّلاع على دليل أدوات نظام النظام
أو دليل استخدام أنظمة الإصدار الأخرى.
يخضع مشروع LLVM بموجب الإصدار 2.0 من ترخيص Apache مع استثناءات LLVM. لمزيد من المعلومات، يمكنك الاطّلاع على ملف الترخيص.
النظام
وقت تشغيل النظام يشير إلى /system/lib/libstdc++.so
. يجب عدم الخلط بين هذه المكتبة ومكتبة libstdc+ التي تضمّ الميزات الكاملة في GNU. وعلى نظامَي التشغيل Android، فإنّ libstdc++ هي فقط
new
وdelete
. استخدِم libc+ لإنشاء مكتبة C++ عادية كاملة الميزات.
يوفر وقت تشغيل النظام C++ الدعم لواجهة برمجة التطبيقات الأساسية وقت التشغيل C++.
في الأساس، توفّر هذه المكتبة new
وdelete
. على عكس الخيارات الأخرى المتاحة في اتفاقية عدم الإفشاء، لا يتوفر دعم لمعالجة الاستثناءات أو بروتوكول RTTI.
لا يتوفر دعم مكتبة عادي بخلاف برامج تضمين C++ لعناوين المكتبة C مثل <cstdio>
. وإذا أردت الحصول على خدمة STL، عليك استخدام أحد
الخيارات الأخرى المعروضة في هذه الصفحة.
ما من علاقة
ويتوفّر أيضًا خيار عدم توفّر STL. وما مِن متطلبات ربط أو ترخيص في هذه الحالة. لا تتوفّر عناوين C++ العادية.
اختيار وقت تشغيل C++
صناعة
الإعداد التلقائي في CMake هو c++_static
.
يمكنك تحديد c++_shared
أو c++_static
أو none
أو system
باستخدام المتغيّر ANDROID_STL
في ملف build.gradle
على مستوى الوحدة. لمعرفة المزيد من المعلومات،
يمكنك الاطّلاع على مستندات ANDROID_STL في
CMake.
إنشاء إصدارات جديدة
الإعداد التلقائي لإصدار ndk هو none
.
يمكنك تحديد c++_shared
أو c++_static
أو none
أو system
باستخدام المتغيّر APP_STL
في ملف Application.mk. على سبيل المثال:
APP_STL := c++_shared
يتيح لك ndk-build اختيار وقت تشغيل واحد فقط لتطبيقك، ويمكنه فقط تنفيذ ذلك في Application.mk.
استخدام المجموعة مباشرةً
إذا كنت تستخدم المجموعة مباشرةً في نظام الإصدار الخاص بك، سيستخدم clang++
c++_shared
تلقائيًا. لاستخدام الخيار الثابت، أضِف -static-libstdc++
إلى علامات الرابط. تجدر الإشارة إلى أنه على الرغم من أن الخيار يستخدم الاسم "libstdc++" لأسباب تاريخية، فإنه ينطبق على libc++ أيضًا.
اعتبارات مهمة
أوقات التشغيل الثابتة
إذا كان كل الرمز الأصلي لتطبيقك مضمّنًا في مكتبة مشتركة واحدة، نقترح استخدام وقت التشغيل الثابت. ويسمح هذا للرابط بتضمين أكبر عدد ممكن من الرموز غير المُستخدمة ويحوّلها، ما يؤدي إلى تطبيق أكبر حجم ومحسّن. وتتجنّب الحزمة أيضًا PackageManager وأخطاء الروابط الديناميكية في إصدارات Android القديمة التي تصعّب التعامل مع المكتبات المشتركة وتعرّضها للخطأ.
ومع ذلك، في C++ ، لا يُعد تحديد أكثر من نسخة واحدة من الدالة أو الكائن نفسه في برنامج واحد آمنًا. وهذا جانب واحد من قاعدة التعريف الواحدة المتوفرة في معيار C++.
عند استخدام وقت تشغيل ثابت (والمكتبات الثابتة بشكل عام)، من السهل إيقاف هذه القاعدة عن غير قصد. على سبيل المثال، يخالف التطبيق التالي هذه القاعدة:
# Application.mk
APP_STL := c++_static
# Android.mk
include $(CLEAR_VARS)
LOCAL_MODULE := foo
LOCAL_SRC_FILES := foo.cpp
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := bar
LOCAL_SRC_FILES := bar.cpp
LOCAL_SHARED_LIBRARIES := foo
include $(BUILD_SHARED_LIBRARY)
في هذه الحالة، ستكون البروتوكول STL، بما في ذلك البيانات العالمية والبرامج الثابتة الثابتة، متوفّرًا في كلتا المكتبتَين. يعد سلوك وقت تشغيل هذا التطبيق غير محدد وأعطال التطبيق شائعة جدًا. وتشمل المشاكل المحتملة الأخرى ما يلي:
- الذاكرة مخصّصة في إحدى المكتبة، ويتم إخلاءها في المكتبة الأخرى، ما يؤدي إلى تسرّب الذاكرة أو تلف الذاكرة
- الاستثناءات التي تم رفعها في
libfoo.so
لم يتم إجراؤها فيlibbar.so
، ما أدى إلى تعطُّل تطبيقك. - لا يعمل التخزين المؤقت لـ
std::cout
بشكل صحيح.
بالإضافة إلى المشاكل المتعلقة بالسلوك، يؤدي ربط وقت التشغيل الثابت إلى مكتبات متعددة إلى تكرار الرمز في كل مكتبة مشتركة، ما يزيد من حجم تطبيقك.
بشكل عام، يمكنك فقط استخدام صيغة ثابتة من وقت التشغيل C++ إذا كانت لديك مكتبة مشتركة واحدة فقط في تطبيقك.
أوقات التشغيل المشتركة
إذا كان التطبيق يتضمن مكتبات مشتركة متعددة، يجب استخدام libc++_shared.so
.
على نظام التشغيل Android، لا تكون libc++ المستخدمة بواسطة NDK مطابقة للجزء الذي تم استخدامه
في نظام التشغيل. ويتيح ذلك لمستخدمي منصّة NDK إمكانية الوصول إلى أحدث ميزات libc+ والإصدارات التي تم إصلاحها
حتى عند استهداف الإصدارات القديمة من Android. المقايضة هي أنه إذا
استخدمت libc++_shared.so
، عليك تضمينه في تطبيقك. وإذا كنت تنشئ
تطبيقك باستخدام Gradle، ستتم معالجة هذا تلقائيًا.
كانت الإصدارات القديمة من نظام التشغيل Android تتضمّن أخطاء في PackageManager والرابط الديناميكي الذي
تسبّب في تثبيت موثوقية المكتبات الأصلية وتحديثها وتحميلها
بشكل غير موثوق. وعلى وجه الخصوص، إذا كان تطبيقك يستهدف إصدارًا من Android أقدم من Android 4.3 (المستوى 18 من واجهة برمجة تطبيقات Android) وكنت تستخدم libc++_shared.so
، عليك تحميل المكتبة المشتركة قبل أي مكتبة أخرى تعتمد عليها.
يقدّم مشروع ReLinker حلول بديلة لحل جميع المشاكل المعروفة في تحميل المكتبة الأصلية، ويمثّل عادةً خيارًا أفضل من كتابة حلولك الخاصة.
رقم STL واحد لكل تطبيق
في السابق، كانت منصّة NDK متوافقة مع منصّة GNU libstdc+ وSTLport بالإضافة إلى الترميزَين libc++ . إذا كان تطبيقك يعتمد على المكتبات المصمّمة مسبقًا والتي تم إنشاؤها وفقًا لـ NDK غير تلك المستخدمة لإنشاء تطبيقك، ستحتاج إلى التأكّد من أنّه تم تنفيذ هذا الإجراء بطريقة متوافقة.
يجب ألا يستخدم التطبيق أكثر من وقت تشغيل واحد C++. وهذه البروتوكولات المختلفة
غير متوافقة مع بعضها البعض. على سبيل المثال، إنّ تنسيق std::string
في libc++ ليس هو نفسه في gnustl. لن يتمكّن الرمز المكتوب مقابل بروتوكول STL
من استخدام عناصر مكتوبة على لغة أخرى. وهذا مثال واحد فقط،
وبعض حالات عدم التوافق عديدة.
تمتد هذه القاعدة إلى ما بعد الرمز البرمجي. يجب أن تستخدم جميع ملحقاتك STL نفسه الذي اخترته. إذا كنت تعتمد على مصدر تابع تابع لجهة خارجية يستخدم STL ولا يوفّر مكتبة لكل STL، لن يتوفّر لك خيار في STL. يجب استخدام البروتوكول STL نفسه كملحق لك.
وبإمكانك الاعتماد على مكتبتَين غير متوافقتَين. وفي هذه الحالة، يتمثّل الحل الوحيد في تجاهل إحدى المهام التابعة أو الطلب من المسؤول عن توفير مكتبة مصمَّمة على واجهة STL الأخرى.
استثناءات C++
مع توفير استثناءات C++ باستخدام libc++ ، يتم إيقافها تلقائيًا في ndk-build. ويرجع ذلك إلى أنّ استثناءات C++ تاريخيًا لم تكن متوفرة في اتفاقية NDK. ويتم بشكل تلقائي تفعيل C++ عند استخدام سلاسل الأدوات الخاصة بالأدوات المستقلة والمسجّلة.
لتفعيل الاستثناءات في تطبيقك بالكامل في ndk-build، أضِف السطر التالي إلى ملف Application.mk:
APP_CPPFLAGS := -fexceptions
لتفعيل الاستثناءات لوحدة ndk-build واحدة، أضِف السطر التالي إلى الوحدة المحددة في Android.mk:
LOCAL_CPP_FEATURES := exceptions
وبدلاً من ذلك، يمكنك استخدام:
LOCAL_CPPFLAGS := -fexceptions
ميزة RTT
وكما هو الحال مع الاستثناءات، يتوافق الإصدار RTTI مع الإصدار libc+ والإصدارات الأحدث، ولكن يكون غير مفعّل تلقائيًا في الإصدار ndk-build. يتم تفعيل ميزة RTTI تلقائيًا من خلال سلسلة الأدوات الخاصة بالأدوات والمنتجات المستقلة.
لتفعيل ميزة RTTI في تطبيقك بالكامل في ndk-build، عليك إضافة السطر التالي إلى الملف Application.mk:
APP_CPPFLAGS := -frtti
لتفعيل ميزة RTTI لوحدة ndk-build واحدة، أضِف السطر التالي إلى الوحدة الممنوحة في Android.mk:
LOCAL_CPP_FEATURES := rtti
وبدلاً من ذلك، يمكنك استخدام:
LOCAL_CPPFLAGS := -frtti