Tijekom razvoja volim mijenjati prevoditelje, načine izrade, verzije ovisnosti, izvoditi statičku analizu, mjeriti performanse, prikupljati pokrivenost, generirati dokumentaciju itd. I stvarno volim CMake jer mi omogućuje da radim sve što želim.
Mnogi ljudi kritiziraju CMake, i to često zasluženo, ali ako pogledate, nije sve tako loše, a nedavno uopće nije loše, a smjer razvoja je dosta pozitivan.
U ovoj bilješci želim vam reći kako jednostavno organizirati biblioteku zaglavlja u C++ u sustavu CMake da dobijete sljedeću funkcionalnost:
Uglavnom ćemo govoriti o tome kako organizirati CMake skripte, pa će se o njima detaljnije raspravljati. Svatko može izravno vidjeti ostale datoteke na stranici predloška projekta.
Prije svega, potrebno je zatražiti potrebnu verziju CMake sustava. CMake se razvija, mijenjaju se potpisi naredbi i ponašanje u različitim uvjetima. Kako bi CMake odmah shvatio što želimo od njega, moramo odmah zabilježiti svoje zahtjeve za njim.
cmake_minimum_required(VERSION 3.13)
Zatim ćemo označiti naš projekt, njegov naziv, verziju, korištene jezike itd. (vidi. команду project).
U ovom slučaju označavamo jezik CXX (a to znači C++) tako da se CMake ne napreže i traži kompilator za C jezik (prema zadanim postavkama CMake uključuje dva jezika: C i C++).
project(Mylib VERSION 1.0 LANGUAGES CXX)
Ovdje možete odmah provjeriti je li naš projekt uključen u neki drugi projekt kao potprojekt. Ovo će vam puno pomoći u budućnosti.
Prva opcija je MYLIB_TESTING — za onemogućavanje jediničnih testova. To može biti potrebno ako smo sigurni da je sve u redu s testovima, ali želimo samo npr. instalirati ili pakirati naš projekt. Ili je naš projekt uključen kao podprojekt - u ovom slučaju korisnik našeg projekta nije zainteresiran za izvođenje naših testova. Ne testirate ovisnosti koje koristite, zar ne?
Osim toga, napravit ćemo zasebnu opciju MYLIB_COVERAGE za mjerenje pokrivenosti koda testovima, ali će zahtijevati dodatne alate, pa će se morati izričito omogućiti.
Također ćemo onemogućiti proširenja kako bismo bili u potpunosti usklađeni sa standardom jezika C++. Oni su prema zadanim postavkama omogućeni u CMakeu.
Naša biblioteka sastoji se samo od datoteka zaglavlja, što znači da nemamo ispuha u obliku statičkih ili dinamičkih biblioteka. S druge strane, da bi eksterno koristili našu biblioteku, ona mora biti instalirana, mora biti detektabilna u sustavu i povezana s vašim projektom, a istovremeno ta ista zaglavlja, kao i eventualno neka dodatna, pridaju mu svojstva.
U tu svrhu stvaramo biblioteku sučelja.
add_library(mylib INTERFACE)
Zaglavlja povezujemo s bibliotekom sučelja.
Moderna, moderna, mladalačka upotreba CMakea podrazumijeva da zaglavlja, svojstva itd. prenosi kroz jednu metu. Dakle, dovoljno je reći target_link_libraries(target PRIVATE dependency)i sva zaglavlja koja su povezana s ciljem dependency, bit će dostupni za izvore koji pripadaju cilju target. I ne treba ti ništa [target_]include_directories. To će biti prikazano u nastavku analize CMake skripta za jedinične testove.
Ova naredba pridružuje zaglavlja koja su nam potrebna s našom bibliotekom sučelja, a ako je naša biblioteka povezana s bilo kojim ciljem unutar iste CMake hijerarhije, tada će zaglavlja iz direktorija biti povezana s njom ${CMAKE_CURRENT_SOURCE_DIR}/include, a ako je naša knjižnica instalirana na sustav i povezana s drugim projektom pomoću naredbe find_package, tada će zaglavlja iz imenika biti povezana s njim include u odnosu na instalacijski direktorij.
Postavimo jezični standard. Naravno, posljednji. U isto vrijeme, ne samo da uključujemo standard, već ga i proširujemo na one koji će koristiti našu knjižnicu. To se postiže činjenicom da svojstvo skupa ima kategoriju INTERFACE (Vidi. naredba target_compile_features).
Stvorimo alias za našu knjižnicu. Štoviše, zbog ljepote, bit će u posebnom "prostoru imena". Ovo će biti korisno kada se u našoj biblioteci pojave različiti moduli, a mi ih povezujemo neovisno jedan o drugom. Kao na primjer u Busti.
Instaliranje naših zaglavlja u sustav. Ovdje je sve jednostavno. Kažemo da mapa sa svim zaglavljima treba ići u direktorij include u odnosu na mjesto instalacije.
Zatim obavještavamo sustav za izgradnju da želimo imati mogućnost pozivanja naredbe u projektima trećih strana find_package(Mylib) i postići gol Mylib::mylib.
Sljedeću čaroliju treba shvatiti na ovaj način. Kada u projektu treće strane pozivamo naredbu find_package(Mylib 1.2.3 REQUIRED), a prava verzija instalirane biblioteke bit će nekompatibilna s verzijom 1.2.3CMake će automatski generirati pogrešku. To jest, nećete morati ručno pratiti verzije.
Ako su testovi izričito onemogućeni korištenjem odgovarajuća opcija ili je naš projekt podprojekt, odnosno naredbom je povezan s drugim CMake projektom add_subdirectory, ne idemo dalje po hijerarhiji, a skripta koja opisuje naredbe za generiranje i izvođenje testova jednostavno se ne pokreće.
if(NOT MYLIB_TESTING)
message(STATUS "Тестирование проекта Mylib выключено")
elseif(IS_SUBPROJECT)
message(STATUS "Mylib не тестируется в режиме подмодуля")
else()
add_subdirectory(test)
endif()
Povezujemo ovisnosti. Imajte na umu da smo s našim binarnim datotekama povezali samo CMake ciljeve koji su nam bili potrebni i nismo pozvali naredbu target_include_directories. Naslovi iz okvira testa i iz našeg Mylib::mylib, kao i parametri izgradnje (u našem slučaju, ovo je standard jezika C++) došli su zajedno s ovim ciljevima.
Konačno, stvaramo lažni cilj, čija je "izgradnja" ekvivalentna izvođenju testova, i dodajemo ovaj cilj u zadanu verziju (atribut je odgovoran za ovo ALL). To znači da zadana verzija pokreće testove, što znači da ih nikada nećemo zaboraviti pokrenuti.
add_custom_target(check ALL COMMAND mylib-unit-tests)
Zatim omogućujemo mjerenje pokrivenosti koda ako je navedena odgovarajuća opcija. Neću ulaziti u detalje jer se oni više odnose na alat za mjerenje pokrivenosti nego na CMake. Važno je samo napomenuti da će se na temelju rezultata kreirati gol coverage, s kojim je zgodno započeti mjerenje pokrivenosti.
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()
Zatim provjeravamo je li korisnik postavio jezičnu varijablu. Ako da, onda ga ne diramo, ako ne, onda uzimamo ruski. Zatim konfiguriramo datoteke sustava Doxygen. Sve potrebne varijable, uključujući jezik, idu tamo tijekom procesa konfiguracije (pogledajte. команду configure_file).
Zatim stvaramo cilj doc, čime će započeti generiranje dokumentacije. Budući da generiranje dokumentacije nije najveća potreba u procesu razvoja, cilj neće biti omogućen prema zadanim postavkama; morat će se eksplicitno pokrenuti.
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 ()
Ovdje nalazimo treći Python i stvaramo cilj wandbox, koji generira zahtjev koji odgovara API-ju usluge Kutija za štapiće, i šalje ga. Odgovor dolazi s vezom na gotov 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()
Pruža mogućnost onemogućavanja izrade i cilja jediničnog testa check. Kao rezultat toga, mjerenje pokrivenosti koda testovima je isključeno (vidi. MYLIB_COVERAGE).
Testiranje je također automatski onemogućeno ako je projekt pomoću naredbe povezan s drugim projektom kao podprojekt add_subdirectory.
Zapravo, CMake verzija 3.13 potrebna je samo za pokretanje nekih konzolnih naredbi opisanih u ovoj pomoći. Sa stajališta sintakse CMake skripti, verzija 3.8 je dovoljna ako se generacija poziva na druge načine.
CMake je vrlo moćan i fleksibilan sustav koji vam omogućuje implementaciju funkcionalnosti za svaki ukus i boju. I, iako sintaksa ponekad ostavlja mnogo da se poželi, vrag ipak nije tako strašan kao što je naslikan. Koristite CMake sustav izgradnje za dobrobit društva i zdravlja.