Počas vývoja rád mením kompilátory, zostavujem režimy, verzie závislostí, vykonávam statickú analýzu, meriam výkon, zbieram pokrytie, generujem dokumentáciu atď. A naozaj milujem CMake, pretože mi umožňuje robiť všetko, čo chcem.
Mnoho ľudí kritizuje CMake a často zaslúžene, ale ak sa na to pozriete, nie je všetko také zlé a nedávno Vôbec nie zléa smer vývoja je celkom pozitívny.
V tejto poznámke vám chcem povedať, ako jednoducho zorganizovať knižnicu hlavičiek v C++ v systéme CMake, aby ste získali nasledujúce funkcie:
zhromaždenie;
Testy automatického spustenia;
meranie pokrytia kódom;
Inštalácia;
Automatická dokumentácia;
Generovanie online karantény;
Statická analýza.
Každý, kto už chápe výhody a C-make, môže jednoducho stiahnuť šablónu projektu a začnite ho používať.
Budeme sa baviť hlavne o tom, ako organizovať skripty CMake, takže sa o nich budeme podrobne rozprávať. Ktokoľvek si môže pozrieť zvyšok súborov priamo na stránke projektu šablóny.
V prvom rade si treba vyžiadať požadovanú verziu systému CMake. CMake sa vyvíja, podpisy príkazov a správanie v rôznych podmienkach sa menia. Aby CMake okamžite pochopil, čo od neho chceme, musíme naň okamžite zaznamenať naše požiadavky.
cmake_minimum_required(VERSION 3.13)
Potom označíme náš projekt, jeho názov, verziu, používané jazyky atď. (viď. команду project).
V tomto prípade uvádzame jazyk CXX (a to znamená C++), aby sa CMake nenamáhal a nehľadal kompilátor jazyka C (štandardne CMake obsahuje dva jazyky: C a C++).
project(Mylib VERSION 1.0 LANGUAGES CXX)
Tu si môžete ihneď skontrolovať, či je náš projekt zaradený do iného projektu ako podprojekt. V budúcnosti to veľmi pomôže.
Prvá možnosť je MYLIB_TESTING — zakázať testy jednotiek. To môže byť potrebné, ak sme si istí, že je všetko v poriadku s testami, ale chceme napríklad iba nainštalovať alebo zabaliť náš projekt. Alebo je náš projekt zahrnutý ako podprojekt – v tomto prípade používateľ nášho projektu nemá záujem spustiť naše testy. Netestuješ závislosti, ktoré používaš, však?
Okrem toho urobíme samostatnú možnosť MYLIB_COVERAGE na meranie pokrytia kódu testami, ale bude to vyžadovať ďalšie nástroje, takže bude potrebné explicitne povoliť.
Naša knižnica pozostáva iba z hlavičkových súborov, čo znamená, že nemáme žiadne výfuky vo forme statických alebo dynamických knižníc. Na druhej strane, aby sme mohli našu knižnicu používať externe, musí byť nainštalovaná, musí byť detekovateľná v systéme a prepojená s vaším projektom a zároveň tieto isté hlavičky, ako aj prípadne nejaké doplnkové, sú k nemu pripojené vlastnosti.
Na tento účel vytvoríme knižnicu rozhrania.
add_library(mylib INTERFACE)
Hlavičky viažeme na našu knižnicu rozhrania.
Moderné, módne používanie CMake pre mládež znamená, že hlavičky, vlastnosti atď. prenášané cez jeden jediný cieľ. Takže stačí povedať target_link_libraries(target PRIVATE dependency)a všetky hlavičky, ktoré sú priradené k cieľu dependency, bude k dispozícii pre zdroje patriace do cieľa target. A nepotrebuješ žiadne [target_]include_directories. To bude demonštrované nižšie v analýze CMake skript pre unit testy.
Tento príkaz spája hlavičky, ktoré potrebujeme, s našou knižnicou rozhrania a ak je naša knižnica pripojená k akémukoľvek cieľu v rámci rovnakej hierarchie CMake, budú k nej priradené hlavičky z adresára. ${CMAKE_CURRENT_SOURCE_DIR}/includea ak je naša knižnica nainštalovaná v systéme a pripojená k inému projektu pomocou príkazu find_package, potom k nemu budú priradené hlavičky z adresára include vzhľadom na inštalačný adresár.
Stanovme si jazykový štandard. Samozrejme, že úplne posledný. Zároveň štandard nielen zaraďujeme, ale rozširujeme aj na tých, ktorí budú našu knižnicu využívať. To sa dosiahne vďaka skutočnosti, že nastavená vlastnosť má kategóriu INTERFACE (Viď. target_compile_features).
Vytvorme alias pre našu knižnicu. Navyše pre krásu bude v špeciálnom „namespace“. Bude to užitočné, keď sa v našej knižnici objavia rôzne moduly a prepojíme ich nezávisle od seba. Ako napríklad v Buste.
Inštalácia našich hlavičiek do systému. Všetko je tu jednoduché. Hovoríme, že priečinok so všetkými hlavičkami by mal ísť do adresára include vzhľadom na miesto inštalácie.
Nasledujúce kúzlo by sa malo chápať takto. V projekte tretej strany voláme príkaz find_package(Mylib 1.2.3 REQUIRED)a skutočná verzia nainštalovanej knižnice bude nekompatibilná s verziou 1.2.3CMake automaticky vygeneruje chybu. To znamená, že nebudete musieť sledovať verzie manuálne.
Ak sú testy zakázané explicitne pomocou zodpovedajúca možnosť alebo náš projekt je podprojekt, to znamená, že je pripojený k inému projektu CMake pomocou príkazu add_subdirectory, ďalej sa v hierarchii neposúvame a skript, ktorý popisuje príkazy na generovanie a spúšťanie testov, sa jednoducho nespustí.
if(NOT MYLIB_TESTING)
message(STATUS "Тестирование проекта Mylib выключено")
elseif(IS_SUBPROJECT)
message(STATUS "Mylib не тестируется в режиме подмодуля")
else()
add_subdirectory(test)
endif()
V prvom rade nájdeme balík s požadovaným testovacím rámcom (nahraďte ho obľúbeným).
find_package(doctest 2.3.3 REQUIRED)
Poďme vytvoriť náš spustiteľný súbor s testami. Zvyčajne pridávam priamo do spustiteľného binárneho súboru iba súbor, ktorý bude obsahovať funkciu main.
add_executable(mylib-unit-tests test_main.cpp)
A pridávam súbory, v ktorých sú neskôr popísané samotné testy. Ale nemusíte to robiť.
Spájame závislosti. Upozorňujeme, že sme prepojili iba ciele CMake, ktoré sme potrebovali, s naším binárnym súborom a nezavolali sme príkaz target_include_directories. Nadpisy z testovacieho rámca a z nášho Mylib::mylib, ako aj parametre zostavy (v našom prípade ide o jazykový štandard C++) spolu s týmito cieľmi dosiahli.
Nakoniec vytvoríme fiktívny cieľ, ktorého „zostavenie“ je ekvivalentné spusteniu testov a pridáme tento cieľ do predvoleného zostavenia (za to zodpovedá atribút ALL). To znamená, že predvolená zostava spúšťa testy, čo znamená, že ich nikdy nezabudneme spustiť.
add_custom_target(check ALL COMMAND mylib-unit-tests)
Ďalej povolíme meranie pokrytia kódom, ak je zadaná vhodná možnosť. Nebudem zachádzať do podrobností, pretože sa týkajú skôr nástroja na meranie pokrytia ako CMake. Dôležité je len poznamenať, že na základe výsledkov sa vytvorí cieľ coverage, s ktorým je vhodné začať merať pokrytie.
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()
Ďalej skontrolujeme, či používateľ nastavil premennú jazyka. Ak áno, nedotkneme sa ho, ak nie, berieme ruštinu. Potom nakonfigurujeme systémové súbory Doxygen. Všetky potrebné premenné vrátane jazyka sa tam nachádzajú počas procesu konfigurácie (pozri. команду configure_file).
Potom vytvoríme cieľ doc, ktorý začne generovať dokumentáciu. Keďže generovanie dokumentácie nie je tou najväčšou potrebou v procese vývoja, cieľ nebude štandardne povolený, bude musieť byť spustený explicitne.
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 ()
Tu nájdeme tretí Python a vytvoríme cieľ wandbox, ktorý vygeneruje požiadavku zodpovedajúcu servisnému API Box na prútika pošle ho preč. Odpoveď prichádza s odkazom na hotový 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()
Poskytuje možnosť zakázať zostavovanie a zacielenie testovania jednotiek check. V dôsledku toho sa vypne meranie pokrytia kódu testami (pozri. MYLIB_COVERAGE).
Testovanie je tiež automaticky vypnuté, ak je projekt pripojený k inému projektu ako podprojekt pomocou príkazu add_subdirectory.
V skutočnosti je CMake verzia 3.13 potrebná len na spustenie niektorých príkazov konzoly opísaných v tomto pomocníkovi. Z pohľadu syntaxe skriptov CMake je verzia 3.8 dostatočná, ak sa generovanie volá inými spôsobmi.
CMake je veľmi výkonný a flexibilný systém, ktorý vám umožňuje implementovať funkčnosť pre každý vkus a farbu. A hoci syntax niekedy ponecháva veľa na želanie, diabol stále nie je taký strašný, ako je namaľovaný. Využite zostavovací systém CMake v prospech spoločnosti a zdravia.