البرمجة

حل مشكلة ربط الرموز في Android Studio باستخدام CMake

بمجرد صدور إصدار Android Studio 2.2 بشكل رسمي، قررت الانتقال من عملية البناء القديمة التي كنت أستخدم فيها ndk-build إلى استخدام CMake داخل بيئة Android Studio. وبما أنني أدمج العديد من قواعد الشفرة من داخل شركتي (التي لا يمكنني تعديلها) والتي تستخدم بشكل كبير لغة البرمجة C++11 (بما في ذلك الطريقة المرعبة std::to_string())، فإن الطريقة الوحيدة التي يمكنني بها تجميع الشفرة هي باستخدام بعض الخيارات المحددة – والتي اكتشفتها سابقًا عند بدء العمل مع ndk-build.

لذا، بعد تجميع كل شيء مرة أخرى، وتوليد ملف APK، وأتحقق بنسبة 100٪ من وجود مكتبة الإخراج المشتركة في APK، ولكنني غير قادر على استخدام System.loadLibrary(‘mylibrary’) بنجاح – ويتبين أن هذا بسبب عدم توفر الاعتمادية libc++_shared.so.

بمعنى آخر، أحصل على الخطأ التالي:

java.lang.UnsatisfiedLinkError: فشل dlopen: مكتبة “libc++_shared.so” غير موجودة

في عملية ndk-build القديمة، كنت دائمًا أحصل على المكتبتين (mylibrary.so و libc++_shared.so) في مجلد الإخراج الخاص بي، والذي بدوره تم تجميعهما معًا في التطبيق. يبدو أن سلسلة أدوات CMake لا تقوم بتجميع libc++_shared.so على الإطلاق (فهو لا يوجد في APK).

لقد ضربت رأسي في هذا الموضوع لمدة 6 ساعات. هل يمكنني بطريقة ما جعل سلسلة أدوات CMake تجمع هذه المكتبة المفقودة؟ هل هناك أي مؤشرات؟

إعداداتي:

في gradle.build:

externalNativeBuild {
cmake {
arguments ‘-DANDROID_STL=c++_shared’, ‘-DANDROID_TOOLCHAIN=gcc’, ‘-DANDROID_PLATFORM=android-16’
}
}

وفي CMakeLists.txt (تم حذف أسماء الملفات لأسباب الإيجاز):

cmake_minimum_required(VERSION 3.4.1)

set(CMAKE_CXX_FLAGS “${CMAKE_C_FLAGS} -std=gnu++11”)

include_directories(.)
include_directories(./other)

set(my_SRCS jniInterface.cpp
etc.cpp)

add_library(mylibrary SHARED ${my_SRCS})

target_link_libraries(mylibrary atomic log)

في الواقع، هذا هو مشكلة شائعة تواجه مطوري الأندرويد الذين يستخدمون مكتبات C++ مع Android Studio و CMake. تبين أنه عند استخدام مكتبة C++ مع Android Studio و CMake، يتم تضمين مكتبة libc++_shared.so بشكل افتراضي. لكن يجب على المطورين التحقق من إعداداتهم للتأكد من أن الإعدادات الصحيحة تم استخدامها.

المزيد من المعلومات

الحل لهذه المشكلة يكمن في تكوين سلاسل أدوات CMake بشكل صحيح لضمان تضمين مكتبة libc++_shared.so في التطبيق النهائي. لتحقيق ذلك، يمكنك اتباع الخطوات التالية:

أولاً، يجب التأكد من أن تم تضمين استخدام مكتبة libc++_shared.so في مشروعك من خلال gradle.build. يمكنك فعل ذلك عن طريق إضافة السطر التالي داخل كتلة externalNativeBuild:

javascript
externalNativeBuild { cmake { arguments '-DANDROID_STL=c++_shared' } }

بعد ذلك، يجب التأكد من أن ملف CMakeLists.txt مكون بشكل صحيح. يجب أن يشمل السطر التالي لتضمين مكتبة libc++_shared.so:

scss
target_link_libraries(mylibrary c++_shared)

وبعد أن تقوم بتكوين سلاسل أدوات CMake بهذه الطريقة، ينبغي عليك إعادة بناء مشروعك من جديد.

وفي حال استمرت المشكلة، يمكنك محاولة إضافة السطر التالي أيضًا داخل كتلة externalNativeBuild في gradle.build:

javascript
arguments '-DANDROID_TOOLCHAIN=clang'

هذا الخيار يُفضل في العديد من الحالات بدلاً من استخدام GCC كسلسلة أدوات، وقد يؤدي إلى حل المشكلة.

في النهاية، يجب أن يؤدي تكوين سلاسل أدوات CMake بشكل صحيح إلى تضمين مكتبة libc++_shared.so في تطبيقك النهائي وبالتالي حل مشكلة ربط الرموز التي تواجهك. إذا استمرت المشكلة، يمكنك أيضًا استكشاف الخيارات البديلة مثل تضمين المكتبة يدويًا أو البحث عن حلول أخرى في المنتديات الخاصة بتطوير Android.

زر الذهاب إلى الأعلى