Әзірлеу барысында мен компиляторларды өзгертуді, режимдерді құруды, тәуелділік нұсқаларын жасауды, статикалық талдауды орындауды, өнімділікті өлшеуді, қамтуды жинауды, құжаттаманы жасауды және т.б. Мен CMake-ді шынымен жақсы көремін, өйткені ол маған қалағанның бәрін жасауға мүмкіндік береді.
Көптеген адамдар CMake-ді сынайды, және көбінесе бұл лайықты, бірақ егер сіз оған қарасаңыз, бәрі соншалықты жаман емес, және жақында мүлде жаман емес, ал даму бағыты айтарлықтай оңды.
Бұл жазбада мен келесі функцияларды алу үшін CMake жүйесінде C++ тілінде тақырып кітапханасын жай қалай ұйымдастыру керектігін айтқым келеді:
Ассамблея;
Автоматты іске қосу сынақтары;
Кодты қамтуды өлшеу;
Орнату;
Автоқұжаттау;
Онлайн құм жәшігін құру;
Статикалық талдау.
Артықшылықтарды және C-жасауды түсінетін кез келген адам оңай жасай алады жоба үлгісін жүктеп алыңыз және оны пайдалануды бастаңыз.
Біз негізінен CMake сценарийлерін қалай ұйымдастыру керектігі туралы айтатын боламыз, сондықтан олар егжей-тегжейлі талқыланады. Қалған файлдарды кез келген адам тікелей көре алады үлгі жобасы бетінде.
Ең алдымен, CMake жүйесінің қажетті нұсқасын сұрау керек. CMake дамып келеді, пәрмен қолтаңбалары және әртүрлі жағдайларда мінез-құлық өзгереді. CMake біздің одан не қалайтынымызды бірден түсінуі үшін біз оған қойылатын талаптарымызды дереу жазып алуымыз керек.
cmake_minimum_required(VERSION 3.13)
Содан кейін біз жобамызды, оның атауын, нұсқасын, қолданылатын тілдерді және т.б. белгілейміз (қараңыз. команду project).
Бұл жағдайда біз тілді көрсетеміз CXX (және бұл C++ дегенді білдіреді), сондықтан CMake Си тілінің компиляторын шиеленістірмейді және іздемейді (әдепкі бойынша 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 командасы).
Кітапханамызға бүркеншік ат жасап көрейік. Оның үстіне сұлулық үшін ол арнайы «аттар кеңістігінде» болады. Бұл біздің кітапханада әртүрлі модульдер пайда болған кезде пайдалы болады және біз оларды бір-бірінен тәуелсіз қосуға барамыз. Мысалы, Бустадағы сияқты.
Жүйеге тақырыптарымызды орнату. Мұнда бәрі қарапайым. Біз барлық тақырыптары бар қалта каталогқа кіруі керек деп айтамыз include орнату орнына қатысты.
Әрі қарай, біз құрастыру жүйесіне үшінші тарап жобаларында пәрменді шақыру мүмкіндігіміз туралы хабарлаймыз 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()
Біз тәуелділіктерді байланыстырамыз. Біз екілік жүйеге қажет 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 құрастыру жүйесін қоғам мен денсаулық үшін пайдаланыңыз.