أثناء التطوير ، أحب تغيير المجمّعين ، وإنشاء أوضاع ، وإصدارات التبعية ، وإجراء تحليل ثابت ، وقياس الأداء ، وجمع التغطية ، وإنشاء الوثائق ، وما إلى ذلك. وأنا أحب حقًا CMake لأنه يسمح لي بفعل ما أريد.
كثيرون يوبخون CMake ، وغالبًا ما يكونون مستحقين ، لكن إذا نظرت ، فهذا ليس سيئًا للغاية ، ولكن مؤخرًا ليس سيئا على الإطلاق، واتجاه التنمية إيجابي جدا.
في هذه الملاحظة ، أريد أن أخبرك بمدى سهولة تنظيم مكتبة رأس C ++ في نظام CMake للحصول على الوظائف التالية:
حَشد؛
اختبارات التشغيل التلقائي
قياس تغطية الكود ؛
تثبيت؛
التوثيق التلقائي
جيل رمل على الإنترنت ؛
التحليل الساكن.
من يفهم بالفعل الإيجابيات و si-make يمكنه فقط تحميل قالب المشروع وابدأ في استخدامه.
بادئ ذي بدء ، تحتاج إلى طلب الإصدار المطلوب من نظام CMake. CMake يطور ، توقيعات الأوامر تتغير ، السلوك في ظل ظروف مختلفة. لكي تفهم CM على الفور ما نريده منها ، نحتاج إلى إصلاح متطلباتنا لها على الفور.
cmake_minimum_required(VERSION 3.13)
ثم نشير إلى مشروعنا واسمه وإصداره واللغات المستخدمة وما إلى ذلك. команду project).
في هذه الحالة ، حدد اللغة CXX (وهو ما يعني C ++) بحيث لا يكلف CMake عناء البحث عن مترجم C (افتراضيًا ، يتم تضمين لغتين في CMake: C و C ++).
project(Mylib VERSION 1.0 LANGUAGES CXX)
هنا يمكنك التحقق على الفور مما إذا كان مشروعنا مدرجًا في مشروع آخر كمشروع فرعي. هذا سوف يساعد كثيرا في المستقبل.
الخيار الأول هو MYLIB_TESTING - لتعطيل اختبارات الوحدة. قد تكون هناك حاجة إلى ذلك إذا كنا متأكدين من أن كل شيء متوافق مع الاختبارات ، ونريد ، على سبيل المثال ، تثبيت مشروعنا أو حزمه فقط. أو يتم تضمين مشروعنا كمشروع فرعي - في هذه الحالة ، لا يهتم مستخدم مشروعنا بإجراء اختباراتنا. أنت لا تختبر التبعيات التي تستخدمها ، أليس كذلك؟
تتكون مكتبتنا من ملفات رأس فقط ، مما يعني أنه ليس لدينا أي مخرجات في شكل مكتبات ثابتة أو ديناميكية. من ناحية أخرى ، من أجل استخدام مكتبتنا من الخارج ، تحتاج إلى تثبيتها ، يجب أن تكون قادرًا على العثور عليها في النظام وربطها بمشروعك ، وفي نفس الوقت هذه الرؤوس أيضًا ، ربما بعض الخصائص الإضافية.
لهذا الغرض ، نقوم بإنشاء مكتبة واجهة.
add_library(mylib INTERFACE)
نقوم بربط الرؤوس بمكتبة الواجهة الخاصة بنا.
الاستخدام الحديث والعصري والشبابي لـ CMake يعني أن الرؤوس والخصائص وما إلى ذلك. تنتقل من خلال هدف واحد. لذلك يكفي القول target_link_libraries(target PRIVATE dependency)، وكافة الرؤوس المرتبطة بالهدف dependency، ستكون متاحة للمصادر التي تنتمي إلى الهدف target. ولست بحاجة إلى أي منها [target_]include_directories. سيتم توضيح ذلك أدناه عند التحليل CMake البرنامج النصي لاختبارات الوحدة.
يربط هذا الأمر الرؤوس التي نحتاجها بمكتبة واجهتنا ، وإذا كانت مكتبتنا متصلة بأي هدف ضمن نفس التسلسل الهرمي CMake ، فسيتم ربط الرؤوس من الدليل بها ${CMAKE_CURRENT_SOURCE_DIR}/include، وإذا كانت مكتبتنا مثبتة على النظام ومتصلة بمشروع آخر باستخدام الأمر find_package، ثم سيتم إقران الرؤوس من الدليل به include بالنسبة إلى دليل التثبيت.
اضبط معيار اللغة. بالطبع الأحدث. في الوقت نفسه ، لا نقوم بتضمين المعيار فحسب ، بل نوزعه أيضًا على أولئك الذين سيستخدمون مكتبتنا. يتم تحقيق ذلك من خلال جعل الخاصية المحددة لها فئة INTERFACE (راجع. الأمر target_compile_features).
نحصل على اسم مستعار لمكتبتنا. وبالنسبة للجمال ، سيكون في "مساحة اسم" خاصة. سيكون هذا مفيدًا عندما تظهر وحدات مختلفة في مكتبتنا ، ونذهب لربطها بشكل مستقل عن بعضها البعض. كما في بوستا ، على سبيل المثال.
يجب فهم التعويذة التالية على هذا النحو. عندما نكون في مشروع جانبي نسمي الأمر find_package(Mylib 1.2.3 REQUIRED)، وفي نفس الوقت النسخة الحقيقية للمكتبة المثبتة ستكون غير متوافقة مع الإصدار 1.2.3، سيقوم CMake تلقائيًا بإنشاء خطأ. أي أنك لن تحتاج إلى تتبع الإصدارات يدويًا.
إذا تم تعطيل الاختبارات بشكل صريح باستخدام الخيار المقابل أو مشروعنا هو مشروع فرعي ، أي أنه متصل بمشروع CMake آخر باستخدام الأمر add_subdirectory، نحن لا نذهب إلى أسفل التسلسل الهرمي ، والبرنامج النصي ، الذي يصف أوامر إنشاء الاختبارات وتشغيلها ، لا يبدأ ببساطة.
if(NOT MYLIB_TESTING)
message(STATUS "Тестирование проекта Mylib выключено")
elseif(IS_SUBPROJECT)
message(STATUS "Mylib не тестируется в режиме подмодуля")
else()
add_subdirectory(test)
endif()
نحن نربط التبعيات. يرجى ملاحظة أننا قمنا بإرفاق أهداف CMake التي نحتاجها بالثنائي الخاص بنا فقط ، ولم نستدعي الأمر target_include_directories. رؤوس من إطار الاختبار ومن Mylib::mylib، بالإضافة إلى خيارات الإنشاء (في حالتنا ، معيار لغة C ++) التي تم الزحف إليها جنبًا إلى جنب مع هذه الأهداف.
أخيرًا ، أنشأنا هدفًا وهميًا يعادل "بناءه" تشغيل الاختبارات ، وأضف هذا الهدف إلى البنية الافتراضية (هذه هي مسؤولية السمة ALL). هذا يعني أن البنية الافتراضية ستؤدي إلى تشغيل الاختبارات ، مما يعني أننا لن ننسى أبدًا تشغيلها.
add_custom_target(check ALL COMMAND mylib-unit-tests)
بعد ذلك ، قم بتشغيل قياس تغطية الكود ، إذا تم تعيين الخيار المقابل. لن أخوض في التفاصيل ، لأنها مرتبطة بأداة قياس التغطية أكثر من CMake. من المهم فقط ملاحظة أن النتائج ستخلق هدفًا coverage، والتي من الملائم أن تبدأ في قياس التغطية.
find_program(GCOVR_EXECUTABLE gcovr)
if(MYLIB_COVERAGE AND GCOVR_EXECUTABLE)
message(STATUS "Измерение покрытия кода тестами включено")
target_compile_options(mylib-unit-tests PRIVATE --coverage)
target_link_libraries(mylib-unit-tests PRIVATE gcov)
add_custom_target(coverage
COMMAND
${GCOVR_EXECUTABLE}
--root=${PROJECT_SOURCE_DIR}/include/
--object-directory=${CMAKE_CURRENT_BINARY_DIR}
DEPENDS
check
)
elseif(MYLIB_COVERAGE AND NOT GCOVR_EXECUTABLE)
set(MYLIB_COVERAGE OFF)
message(WARNING "Для замеров покрытия кода тестами требуется программа gcovr")
endif()
بعد ذلك ، نتحقق مما إذا كان المستخدم قد تم تعيين المتغير مع اللغة. إذا كانت الإجابة بنعم ، فإننا لا نتطرق إليها ، وإلا فإننا نأخذ اللغة الروسية. ثم نقوم بتهيئة ملفات نظام Doxygen. تصل جميع المتغيرات الضرورية ، بما في ذلك اللغة ، إلى هناك أثناء عملية التكوين (انظر. команду configure_file).
ثم نصنع هدفا doc، والتي ستبدأ في إنشاء الوثائق. نظرًا لأن إنشاء التوثيق ليس الحاجة الأكبر في عملية التطوير ، فلن يتم تضمين الهدف افتراضيًا ، وسيتعين تشغيله بشكل صريح.
if (Doxygen_FOUND)
if (NOT MYLIB_DOXYGEN_LANGUAGE)
set(MYLIB_DOXYGEN_LANGUAGE Russian)
endif()
message(STATUS "Doxygen documentation will be generated in ${MYLIB_DOXYGEN_LANGUAGE}")
configure_file(Doxyfile.in Doxyfile)
add_custom_target(doc COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
endif ()
هنا نجد Python الثالثة وننشئ هدفًا wandbox، والذي ينشئ طلبًا مطابقًا لواجهة برمجة التطبيقات للخدمة wandboxويرسلها. ردا على ذلك ، يأتي رابط إلى Sandbox النهائي.
find_program(PYTHON3_EXECUTABLE python3)
if(PYTHON3_EXECUTABLE)
set(WANDBOX_URL "https://wandbox.org/api/compile.json")
add_custom_target(wandbox
COMMAND
${PYTHON3_EXECUTABLE} wandbox.py mylib-example.cpp "${PROJECT_SOURCE_DIR}" include |
curl -H "Content-type: application/json" -d @- ${WANDBOX_URL}
WORKING_DIRECTORY
${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS
mylib-unit-tests
)
else()
message(WARNING "Для создания онлайн-песочницы требуется интерпретатор ЯП python 3-й версии")
endif()
في الواقع ، الإصدار 3.13 من CMake مطلوب فقط لتشغيل بعض أوامر وحدة التحكم الموضحة في هذه التعليمات. من وجهة نظر بناء جملة نصوص CMake ، يكون الإصدار 3.8 كافيًا إذا تم استدعاء الجيل بطرق أخرى.
CMake هو نظام قوي ومرن للغاية يسمح لك بتنفيذ وظائف لكل ذوق ولون. وعلى الرغم من أن بناء الجملة يترك في بعض الأحيان الكثير مما هو مرغوب فيه ، إلا أن الشيطان لا يزال ليس فظيعًا كما هو مرسوم. استخدم نظام CMake build لصالح المجتمع والصحة.