ترقی کے دوران، میں کمپائلرز کو تبدیل کرنا، موڈز بنانا، انحصاری ورژن بنانا، جامد تجزیہ کرنا، کارکردگی کی پیمائش کرنا، کوریج اکٹھا کرنا، دستاویزات بنانا وغیرہ پسند کرتا ہوں۔ اور میں واقعی CMake سے محبت کرتا ہوں کیونکہ یہ مجھے ہر وہ کام کرنے کی اجازت دیتا ہے جو میں چاہتا ہوں۔
بہت سے لوگ CMake پر تنقید کرتے ہیں، اور اکثر اس کے مستحق ہیں، لیکن اگر آپ اسے دیکھیں تو سب کچھ اتنا برا نہیں ہے، اور حال ہی میں بالکل برا نہیں، اور ترقی کی سمت کافی مثبت ہے۔
اس نوٹ میں، میں آپ کو بتانا چاہتا ہوں کہ درج ذیل فعالیت کو حاصل کرنے کے لیے C++ میں C++ میں ہیڈر لائبریری کو کس طرح منظم کیا جائے:
اسمبلی;
آٹورن ٹیسٹ؛
کوڈ کوریج کی پیمائش؛
تنصیب؛
خودکار دستاویزات؛
آن لائن سینڈ باکس جنریشن؛
جامد تجزیہ۔
کوئی بھی جو پہلے سے ہی فوائد کو سمجھتا ہے اور سی میک کر سکتا ہے۔ پروجیکٹ ٹیمپلیٹ ڈاؤن لوڈ کریں۔ اور اسے استعمال کرنا شروع کریں۔
ہم بنیادی طور پر اس بارے میں بات کریں گے کہ CMake اسکرپٹس کو کیسے ترتیب دیا جائے، اس لیے ان پر تفصیل سے بات کی جائے گی۔ کوئی بھی باقی فائلوں کو براہ راست دیکھ سکتا ہے۔ ٹیمپلیٹ پروجیکٹ کے صفحے پر.
سب سے پہلے، آپ کو CMake سسٹم کے مطلوبہ ورژن کی درخواست کرنے کی ضرورت ہے۔ CMake تیار ہو رہا ہے، مختلف حالات میں کمانڈ کے دستخط اور برتاؤ تبدیل ہو رہا ہے۔ CMake کو فوری طور پر سمجھنے کے لیے کہ ہم اس سے کیا چاہتے ہیں، ہمیں فوری طور پر اس کے لیے اپنی ضروریات کو ریکارڈ کرنے کی ضرورت ہے۔
cmake_minimum_required(VERSION 3.13)
پھر ہم اپنے پروجیکٹ، اس کا نام، ورژن، استعمال ہونے والی زبانیں، وغیرہ کا تعین کریں گے (دیکھیں۔ команду project).
اس صورت میں ہم زبان کی طرف اشارہ کرتے ہیں۔ CXX (اور اس کا مطلب ہے C++) تاکہ CMake C زبان کے مرتب کرنے والے کو دبانے اور تلاش نہ کرے (بطور ڈیفالٹ، CMake میں دو زبانیں شامل ہیں: C اور C++)۔
project(Mylib VERSION 1.0 LANGUAGES CXX)
یہاں آپ فوری طور پر چیک کر سکتے ہیں کہ آیا ہمارا پروجیکٹ کسی دوسرے پروجیکٹ میں بطور ذیلی پروجیکٹ شامل ہے۔ اس سے مستقبل میں بہت مدد ملے گی۔
پہلا آپشن ہے۔ MYLIB_TESTING - یونٹ ٹیسٹ کو غیر فعال کرنے کے لیے۔ یہ ضروری ہو سکتا ہے اگر ہمیں یقین ہو کہ ٹیسٹ کے ساتھ سب کچھ ٹھیک ہے، لیکن ہم صرف یہ چاہتے ہیں، مثال کے طور پر، اپنے پروجیکٹ کو انسٹال یا پیک کرنا۔ یا ہمارا پروجیکٹ ایک ذیلی پروجیکٹ کے طور پر شامل ہے - اس صورت میں، ہمارے پروجیکٹ کا صارف ہمارے ٹیسٹ چلانے میں دلچسپی نہیں رکھتا ہے۔ آپ ان انحصاروں کی جانچ نہیں کرتے جو آپ استعمال کرتے ہیں، کیا آپ؟
اس کے علاوہ، ہم ایک علیحدہ آپشن بنائیں گے۔ MYLIB_COVERAGE ٹیسٹ کے ذریعے کوڈ کوریج کی پیمائش کے لیے، لیکن اس کے لیے اضافی ٹولز کی ضرورت ہوگی، اس لیے اسے واضح طور پر فعال کرنے کی ضرورت ہوگی۔
ہماری لائبریری صرف ہیڈر فائلوں پر مشتمل ہے، جس کا مطلب ہے کہ ہمارے پاس جامد یا متحرک لائبریریوں کی شکل میں کوئی ایگزاسٹ نہیں ہے۔ دوسری طرف، ہماری لائبریری کو بیرونی طور پر استعمال کرنے کے لیے، اسے انسٹال کرنے کی ضرورت ہے، اسے سسٹم میں قابل شناخت ہونے اور آپ کے پروجیکٹ سے منسلک ہونے کی ضرورت ہے، اور ساتھ ہی ساتھ یہ وہی ہیڈرز، نیز ممکنہ طور پر کچھ اضافی، اس کی خصوصیات سے منسلک ہیں۔
اس مقصد کے لیے ہم ایک انٹرفیس لائبریری بناتے ہیں۔
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) اور ایک مقصد حاصل کریں Mylib::mylib.
اگلے ہجے کو اس طرح سمجھنا چاہیے۔ جب تھرڈ پارٹی پروجیکٹ میں ہم کمانڈ کو کال کرتے ہیں۔ find_package(Mylib 1.2.3 REQUIRED)، اور انسٹال شدہ لائبریری کا اصل ورژن ورژن سے مطابقت نہیں رکھتا 1.2.3CMake خود بخود ایک خرابی پیدا کرے گا۔ یعنی، آپ کو دستی طور پر ورژن کو ٹریک کرنے کی ضرورت نہیں ہوگی۔
اگر ٹیسٹ واضح طور پر استعمال کرنے سے معذور ہیں۔ متعلقہ اختیار یا ہمارا پروجیکٹ ایک ذیلی پروجیکٹ ہے، یعنی یہ کمانڈ کا استعمال کرتے ہوئے دوسرے CMake پروجیکٹ سے منسلک ہے۔ add_subdirectory، ہم درجہ بندی کے ساتھ مزید آگے نہیں بڑھتے ہیں، اور اسکرپٹ، جو ٹیسٹ بنانے اور چلانے کے لیے کمانڈز کی وضاحت کرتی ہے، بس نہیں چلتی۔
if(NOT MYLIB_TESTING)
message(STATUS "Тестирование проекта Mylib выключено")
elseif(IS_SUBPROJECT)
message(STATUS "Mylib не тестируется в режиме подмодуля")
else()
add_subdirectory(test)
endif()
سب سے پہلے، ہمیں مطلوبہ ٹیسٹ فریم ورک کے ساتھ ایک پیکج ملتا ہے (اپنے پسندیدہ سے بدل دیں)۔
find_package(doctest 2.3.3 REQUIRED)
آئیے ٹیسٹ کے ساتھ اپنی ایگزیکیوٹیبل فائل بنائیں۔ عام طور پر میں براہ راست ایگزیکیوٹیبل بائنری میں صرف وہی فائل شامل کرتا ہوں جس میں فنکشن ہوتا ہے۔ main.
add_executable(mylib-unit-tests test_main.cpp)
اور میں ایسی فائلیں شامل کرتا ہوں جن میں ٹیسٹ خود بعد میں بیان کیے جاتے ہیں۔ لیکن آپ کو ایسا کرنے کی ضرورت نہیں ہے۔
ہم انحصار کو جوڑتے ہیں۔ براہ کرم نوٹ کریں کہ ہم نے صرف 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، جو سروس API کے مطابق ایک درخواست تیار کرتا ہے۔ وینڈ باکس، اور اسے بھیج دیتا ہے۔ جواب تیار شدہ سینڈ باکس کے لنک کے ساتھ آتا ہے۔
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()
یونٹ ٹیسٹ کی تعمیر اور ہدف کو غیر فعال کرنے کی صلاحیت فراہم کرتا ہے۔ check. نتیجے کے طور پر، ٹیسٹ کے ذریعے کوڈ کوریج کی پیمائش بند کر دی گئی ہے (دیکھیں۔ MYLIB_COVERAGE).
اگر پروجیکٹ کمانڈ کا استعمال کرتے ہوئے ذیلی پروجیکٹ کے طور پر کسی دوسرے پروجیکٹ سے منسلک ہے تو جانچ بھی خود بخود غیر فعال ہوجاتی ہے۔ add_subdirectory.
اس کے لیے سروس استعمال کی جاتی ہے۔ وینڈ باکس. میں نہیں جانتا کہ ان کے سرور کتنے لچکدار ہیں، لیکن میں سمجھتا ہوں کہ اس موقع کا غلط استعمال نہیں کیا جانا چاہیے۔
درحقیقت، CMake ورژن 3.13 صرف اس مدد میں بیان کردہ کچھ کنسول کمانڈز کو چلانے کے لیے درکار ہے۔ CMake اسکرپٹس کے نحو کے نقطہ نظر سے، اگر جنریشن کو دوسرے طریقوں سے بلایا جائے تو ورژن 3.8 کافی ہے۔
CMake ایک بہت طاقتور اور لچکدار نظام ہے جو آپ کو ہر ذائقہ اور رنگ کے لیے فعالیت کو نافذ کرنے کی اجازت دیتا ہے۔ اور، اگرچہ نحو بعض اوقات مطلوبہ حد تک بہت کچھ چھوڑ دیتا ہے، لیکن شیطان اب بھی اتنا خوفناک نہیں ہے جتنا اسے پینٹ کیا گیا ہے۔ معاشرے اور صحت کے فائدے کے لیے CMake بلڈ سسٹم کا استعمال کریں۔