فهم CMakeLists
CMake
في دليلنا التمهيدي، استخدمنا CMake كنظام بناء لتطبيقنا، لكننا ركزنا فقط على أحد ملفات CMakeLists.txt الخاصة بنا. هنا، سنستعرض كيفية عمله بمزيد من التفصيل.
CMake مفيد لأنه يسمح لنا بأتمتة الكثير من الأمور التي يجب القيام بها قبل التجميع.
ملف CMakeLists.txt الجذر
قد تتذكر ملف CMakeLists.txt هذا من الدليل الأول:
| |
السطر الأول، cmake_minimum_required() يضبط إصدار CMake الذي سنستدعيه.
بعد ذلك، project(kirigami-tutorial) يُعرِّف اسم المشروع.
ثم نصل إلى قسم حيث نضمّن عددًا من إعدادات CMake وكيدي الضرورية باستخدام extra-cmake-modules. توفر مجموعة من الأدوات المفيدة:
- يوفر KDEInstallDirs متغيرات تسهيلية مثل
${KDE_INSTALL_TARGETS_DEFAULT_ARGS}و${KDE_INSTALL_QMLDIR}و${KDE_INSTALL_BINDIR}و${KDE_INSTALL_LIBDIR}. - يوفر KDECMakeSettings أشياء مثل
CMAKE_AUTORCC ON، وهدفuninstallيمكن استخدامه معcmake --build build/ --target uninstall، وENABLE_CLAZY. - يوفر KDECompilerSettings معيار C++ أدنى، وعلميات مترجم مثل
-pedantic، ووحدات ماكرو لأفضل الممارسات مثل-DQT_NO_CAST_FROM_ASCIIلطلب تحويلات صريحة مثلQStringLiteral(). - يوفر ECMFindQmlModule طريقة لضمان العثور على تبعية QML وقت التشغيل في وقت التجميع.
- يوفر ECMQmlModule أوامر CMake مثل
ecm_add_qml_module()وecm_target_qml_sources().
القسم التالي مهم، لأنه يحدد التبعيات التي سنضيفها في وقت التجميع. لننظر إلى الأول:
| |
- يجد find_package() المكتبة الخارجية ومكوناتها ويحملها.
- يخبر
REQUIREDCMake بالخروج مع خطأ إذا تعذر العثور على الحزمة. COMPONENTSهو معامل يسبق المكونات المحددة للإطار الذي سنضمّنه.- كل كلمة بعد
COMPONENTSتشير إلى مكون محدد من المكتبة.
ملاحظة
إذا كنت تبحث عن إضافة أي مكونات مدرجة في توثيق API كيدي إلى تطبيقك، يمكنك التحقق من الشريط الجانبي الأيمن لكيفية إضافة المكون باستخدام CMake. على سبيل المثال، بالنسبة لـ Kirigami، ستجد شيئًا مثل find_package(KF6Kirigami)، والذي مع إضافة ECM يصبح:
find_package(KF6 COMPONENTS Kirigami)انتبه جيدًا للمكونات المضمّنة، لأن حذف المكونات المستخدمة في الكود سيوقف تطبيقنا عن التجميع.
يوجه سطر التثبيت CMake لتثبيت ملف سطح المكتب في ${KDE_INSTALL_APPDIR}، والذي يُترجم على لينكس إلى $XDG_DATA_DIRS/applications، عادةً /usr/share/applications، وعلى ويندوز يُترجم إلى C:/Program Files/${PROJECT_NAME}/bin/data/applications:
| |
يسمح السطر الأخير لـ CMake بطباعة الحزم التي وجدها، ويجعل التجميع يفشل فورًا إذا واجه خطأً:
| |
وفوق ذلك، يشير add_subdirectory(src) إلى CMake داخل الدليل src/، حيث يجد ملف CMakeLists.txt آخر.
src/CMakeLists.txt
| |
بينما تعامل الملف الأول مع البيانات الوصفية وإيجاد المكتبات، سيتكون هذا الملف من معالجة التبعيات وتثبيت التطبيق. يحتوي على استدعاءات CMake التالية:
- ينشئ add_executable() الهدف القابل للتنفيذ الذي سنستخدمه لتشغيل مشروعنا.
- ينشئ
ecm_add_qml_module()هدف وحدة QML سيكون متاحًا عبر الاستيراد "org.kde.tutorial". - يضيف target_sources() ملفات مصدر C++ إلى الهدف القابل للتنفيذ.
- يضيف
ecm_target_qml_sources()ملفات QML إلى الوحدة. - يربط target_link_libraries() مكتبات C++ المستخدمة في كودنا بملفنا القابل للتنفيذ. لم تُدرج Kirigami هنا لأننا نستخدم وحدة QML الخاصة بها فقط.
- يثبت install() الملف القابل للتنفيذ في النظام.
يمكن العثور على توثيق الأمرين ECM في واجهة برمجة تطبيقات extra-cmake-modules لوحدة ECMQmlModule.
استُخدم استدعاء ecm_add_qml_module() هنا لتعديل الهدف القابل للتنفيذ التقليدي لرمز C++ المصدر وتحويله إلى شيء يمكنه قبول ملفات QML ورمز C++ المصدر الذي يمكن الوصول إليه من QML فيما يُسمى استخدام الملف القابل للتنفيذ كهدف داعم لوحدة QML. هذا يعني أن ملفات QML تُشغّل مباشرة كجزء من التطبيق، وهو الحال غالبًا للتطبيقات.
يمكنك أيضًا إنشاء وحدة QML منفصلة لا تستخدم الملف القابل للتنفيذ كهدف داعم باستخدام ecm_add_qml_module(). في هذه الحالة، ستنشئ هدف مكتبة باستخدام add_library()، وتربطه بهدف قابل للتنفيذ موجود باستخدام target_link_libraries()، وبالإضافة إلى تثبيت المكتبة بـ install() ستحتاج إلى إنهاء وحدة QML بـ ecm_finalize_qml_module() حتى تتمكن من إنشاء ملفين: qmldir و qmltypes. تُستخدم هذه الملفات بواسطة تطبيقات QtQuick لإيجاد وحدات QML المنفصلة.
طريقة إنشاء وحدة QML منفصلة موضحة بشكل أفضل في استخدام ملفات منفصلة.
هذه إضافات مقدمة من extra-cmake-modules لتسهيل استخدام تسجيل Qt التصريحي (بديل ملفات موارد Qt).
ملاحظة
يجب أن تطابق هذه المكتبات المكونات التي أدرجناها في ملفCMakeLists.txt السابق، وإلا فلن تُدرج هذه المكونات ولن يترجم تطبيقنا.يمكن العثور على توثيق الأوامر الثلاثة في واجهة برمجة تطبيقات extra-cmake-modules لوحدة ECMQmlModule.
src/components/CMakeLists.txt
في البرنامج التعليمي حول كيفية تقسيم كودك إلى ملفات منفصلة، قُدّم ملف CMake جديد للسماح بوحدات QML منفصلة:
| |
شرط قراءة هذا الملف بواسطة CMake هو إضافة استدعاء لـ add_subdirectory() في src/CMakeLists.txt يشير إليه.
ننشئ هدفًا جديدًا يُدعى kirigami-hello-components ثم نحوله إلى وحدة QML باستعمال ecm_add_qml_module() تحت اسم الاستيراد org.kde.tutorial.components ونضيف ملفات QML ذات الصلة.
ينشئ استدعاء add_library() هدفًا جديدًا يُسمى kirigami-hello-components. سيكون لهذا الهدف مجموعته الخاصة من ملفات الكود المصدري وملفات QML ويربط مكتباته الخاصة وهكذا، لكنه يحتاج إلى الربط بالملف القابل للتنفيذ، ولكن بمجرد ترجمته يحتاج إلى الربط بالملف القابل للتنفيذ الذي أُنشئ في src/CMakeLists.txt. يتم ذلك بإضافة اسم الهدف إلى قائمة المكتبات التي سترتبط بالملف القابل للتنفيذ في target_link_libraries().
يغير استدعاء ecm_add_qml_module() المكتبة للسماح لها بقبول ملفات QML كما في السابق، لكن هذه المرة نحتاج إلى استخدام GENERATE_PLUGIN_SOURCE. عندما يُستخدم الملف القابل للتنفيذ كهدف داعم (مثل kirigami-hello) لا يحتاج إلى إنشاء كود إضافة لأنه مدمج في الملف القابل للتنفيذ؛ مع وحدات QML المنفصلة مثل kirigami-hello-components يكون كود الإضافة ضروريًا.
ينشئ qt_add_qml_module() الخاص بـ Qt المنبع افتراضيًا إضافة مع وحدة QML، لكن ecm_add_qml_module() الخاص بـ كيدي لا يفعل ذلك افتراضيًا للتوافق مع الإصدارات السابقة.
شيء آخر ضروري لوحدات QML المنفصلة هو إنهاء الهدف. هذا يعني بشكل أساسي أن CMake ينشئ ملفين، qmldir و qmltypes، يصفان وحدات QML التي لدينا ويصدران رموزها للاستخدام في المكتبة. إنها مهمة عند تثبيت تطبيقك حتى يتمكن الملف القابل للتنفيذ الذي يُشغّل من العثور على مكان ملفات QML لكل وحدة، لذا تُضاف تلقائيًا إلى الهدف.
يمكنك بعد ذلك تثبيت الهدف كما في السابق.
في المرة القادمة التي تحتاج فيها إلى إضافة المزيد من ملفات QML، تذكر تضمينها في هذا الملف. يمكن أيضًا إضافة ملفات C++ التي تستخدم الكلمة المفتاحية QML_ELEMENT والتي سنراها لاحقًا في البرنامج التعليمي هنا باستخدام target_sources(). يمكنك فصل كودك منطقيًا عن طريق إنشاء المزيد من وحدات QML باستيرادات مختلفة حسب الحاجة.
سيكون هذا الإعداد مفيدًا عند تطوير معظم تطبيقات Kirigami.