Durante u sviluppu, mi piace à cambià i compilatori, i modi di custruisce, e versioni di dependenza, eseguisce analisi statiche, misurà u rendiment, cullà a cobertura, generà documentazione, etc. È mi piace veramente CMake perchè mi permette di fà ciò chì vogliu.
Parechji scold CMake, è spessu meritatamente, ma s'è vo circate, ùn hè micca cusì male, ma ultimamente micca male in tuttu, è a direzzione di u sviluppu hè abbastanza pusitiva.
In questa nota, vogliu dicu quantu hè faciule d'urganizà una biblioteca di header C++ in un sistema CMake per uttene e seguenti funziunalità:
Questu principarmenti fucalizza nantu à cumu urganizà script CMake, cusì seranu analizati in detail. U restu di i schedari ponu esse vistu direttamente da qualcunu. nantu à a pagina di u prughjettu di u mudellu.
Prima di tuttu, avete bisognu di dumandà a versione desiderata di u sistema CMake. CMake si sviluppa, i cumandamenti di signatura cambianu, u cumpurtamentu in diverse cundizioni. Per chì CMake capisce immediatamente ciò chì vulemu da ellu, avemu bisognu di riparà immediatamente i nostri bisogni per questu.
cmake_minimum_required(VERSION 3.13)
Allora denotemu u nostru prughjettu, u so nome, a versione, e lingue usate, etc. команду project).
In questu casu, specificate a lingua CXX (chì significa C++) per chì CMake ùn si preoccupa micca di circà un compilatore C (per difettu, duie lingue sò incluse in CMake: C è C++).
project(Mylib VERSION 1.0 LANGUAGES CXX)
Quì pudete verificà immediatamente se u nostru prughjettu hè inclusu in un altru prughjettu cum'è sottuprogettu. Questu aiuterà assai in u futuru.
A prima opzione hè MYLIB_TESTING - per disattivà e teste di unità. Questu pò esse necessariu se simu sicuri chì tuttu hè in ordine cù e teste, è vulemu, per esempiu, solu per installà o pacchettu u nostru prughjettu. O u nostru prughjettu hè inclusu cum'è un subprogettu - in questu casu, l'utilizatori di u nostru prughjettu ùn hè micca interessatu à eseguisce i nostri testi. Ùn pruvate micca e dipendenze chì utilizate, nò?
Inoltre, faremu una opzione separata MYLIB_COVERAGE per a misurazione di a cobertura di codice cù testi, ma hà bisognu di strumenti supplementari, cusì vi tuccherà à attivà esplicitamente.
Di sicuru, simu programatori positivi belli, cusì vulemu u livellu massimu di diagnostichi in tempu di compilazione da u compilatore. Ùn passa micca un solu mouse.
A nostra biblioteca hè custituita solu da i fugliali di l'intestazione, chì significa chì ùn avemu micca alcuna pruduzzioni in forma di biblioteche statiche o dinamiche. Per d 'altra banda, per aduprà a nostra biblioteca da l'esternu, avete bisognu à stallà, avete bisognu di pudè truvà lu in u sistema è cunnette à u vostru prughjettu, è à u stessu tempu sti stessi intestazioni, ancu. cum'è, possibbilmente, alcune proprietà supplementari.
Per questu scopu, creemu una biblioteca di l'interfaccia.
add_library(mylib INTERFACE)
Lighemu l'intestazione à a nostra biblioteca di l'interfaccia.
L'usu mudernu, mudernu, ghjovanu di CMake significa chì l'intestazione, proprietà, etc. trasmesse à traversu una sola mira. Allora basta à dì target_link_libraries(target PRIVATE dependency), è tutti l'intestazione chì sò assuciati cù u target dependency, serà dispunibule per e fonti chì appartenenu à u mira target. È ùn avete micca bisognu [target_]include_directories. Questu serà dimustratu quì sottu quandu analizà CMake script per teste unità.
Stu cumandimu associa l'intestazione chì avemu bisognu cù a nostra biblioteca di l'interfaccia, è se a nostra biblioteca hè cunnessa à qualsiasi destinazione in a listessa ghjerarchia CMake, allora l'intestazione da u cartulare seranu assuciati cun ella. ${CMAKE_CURRENT_SOURCE_DIR}/include, è se a nostra biblioteca hè stallata nantu à u sistema è cunnessu à un altru prughjettu cù u cumandimu find_package, allura l'intestazione da u cartulare seranu assuciati cun ellu include relative à u cartulare di stallazione.
Stabbilisce u standard di lingua. Di sicuru, l'ultime. À u listessu tempu, ùn avemu micca solu include u standard, ma ancu distribuisce à quelli chì anu da aduprà a nostra biblioteca. Questu hè ottenutu da avè a pruprietà stabilita avè una categuria INTERFACE (vede para. cumanda di target_compile_features).
Avemu un alias per a nostra biblioteca. È per a bellezza, serà in un "namespace" speciale. Questu serà utile quandu diversi moduli appariscenu in a nostra biblioteca, è andemu à cunnette indipindentamente l'un l'altru. Cum'è in Busta, per esempiu.
Stallà i nostri headers in u sistema. Tuttu hè simplice quì. Dicemu chì u cartulare cù tutti l'intestazione deve falà in u cartulare include riguardu à u locu di stallazione.
Dopu, dicemu à u sistema di custruzzione chì vulemu esse capace di chjamà u cumandamentu in i prughjetti di terzu find_package(Mylib) è uttene un scopu Mylib::mylib.
L'incantazione seguente deve esse cumpresa cusì. Quandu in un prughjettu laterale chjamemu u cumandamentu find_package(Mylib 1.2.3 REQUIRED), è à u stessu tempu a versione vera di a biblioteca installata serà incompatibile cù a versione 1.2.3, CMake generà automaticamente un errore. Questu hè, ùn avete micca bisognu di mantene a traccia di e versioni manualmente.
Se i testi sò esplicitamente disattivati cù opzione corrispondente o u nostru prughjettu hè un sottuprogettu, vale à dì, hè cunnessu à un altru prughjettu CMake cù u cumandimu add_subdirectory, Ùn andemu più in a ghjerarchia, è u script, chì descrive i cumandamenti per generà è eseguisce testi, simpricimenti ùn principia micca.
if(NOT MYLIB_TESTING)
message(STATUS "Тестирование проекта Mylib выключено")
elseif(IS_SUBPROJECT)
message(STATUS "Mylib не тестируется в режиме подмодуля")
else()
add_subdirectory(test)
endif()
Prima di tuttu, truvamu un pacchettu cù u quadru di prova desideratu (sustituitu cù u vostru preferitu).
find_package(doctest 2.3.3 REQUIRED)
Creemu u nostru schedariu eseguibile cù testi. Di solitu, direttamente à u binariu eseguibile, aghju aghjunghje solu u schedariu in quale a funzione serà main.
add_executable(mylib-unit-tests test_main.cpp)
È i schedarii in quale i testi stessi sò descritti, aghju aghjustatu dopu. Ma ùn hè micca necessariu di fà cusì.
Cunnettemu dipendenze. Per piacè nutate chì avemu attaccatu solu i miri CMake chì avemu bisognu à u nostru binariu, è ùn hà micca chjamatu u cumandamentu target_include_directories. Intestazioni da u quadru di prova è da u nostru Mylib::mylib, è ancu l'opzioni di custruzzione (in u nostru casu, u standard di lingua C ++) rastreu cù questi miri.
Infine, creamu un target fittiziu chì "custruisce" hè equivalente à l'esecuzione di teste, è aghjunghje stu mira à a custruzione predeterminata (questu hè a rispunsabilità di l'attributu). ALL). Questu significa chì a custruzione predeterminata attivarà e teste per eseguisce, vale à dì chì ùn ci scurderemu mai di eseguisce.
add_custom_target(check ALL COMMAND mylib-unit-tests)
Dopu, attivate a misura di a cobertura di codice, se l'opzione currispondente hè stabilita. Ùn andaraghju micca in i dettagli, perchè sò più ligati à l'uttellu di misurazione di a cobertura cà à CMake. Hè impurtante solu di nutà chì i risultati creanu un scopu coverage, cù quale hè cunvenutu per inizià a misurazione di a cobertura.
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()
Dopu, avemu verificatu se a variàbile cù a lingua hè stabilita da l'utilizatore. Sì iè, allora ùn avemu micca toccu, se no, allora pigliamu u russu. Allora cunfiguremu i schedarii di u sistema Doxygen. Tutte e variàbili necessarii, cumprese a lingua, ghjunghjenu quì durante u prucessu di cunfigurazione (vede. команду configure_file).
Allora criemu un scopu doc, chì cumincià à generà documentazione. Siccomu a generazione di documentazione ùn hè micca u più grande bisognu in u prucessu di sviluppu, u mira ùn serà micca inclusu per automaticamente, duverà esse eseguitu esplicitamente.
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 ()
Quì truvamu u terzu Python è creanu un mira wandbox, chì genera una dumanda currispondente à l'API di serviziu bacchetta, è u manda. In risposta, vene un ligame à u sandbox finitu.
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()
Fornisce l'opzione per disattivà a creazione è a destinazione di test di unità check. In u risultatu, a misurazione di a cobertura di codice per teste hè disattivata (vede MYLIB_COVERAGE).
Inoltre, a prova hè automaticamente disattivata se u prughjettu hè cunnessu à un altru prughjettu cum'è sottuprogettu cù u cumandimu add_subdirectory.
In fattu, a versione CMake 3.13 hè necessaria solu per eseguisce alcuni di i cumandamenti di cunsola descritti in questu aiutu. Da u puntu di vista di a sintassi di i script CMake, a versione 3.8 hè abbastanza se a generazione hè chjamata in altri modi.
Dopu questu, l'analisi statica serà automaticamente lanciata ogni volta durante a compilazione è a ricumpilazione di e fonti. Ùn ci hè nunda di più da fà.
chjappà
Cù un strumentu maravigliu scan-build Pudete ancu eseguisce l'analisi statica in pocu tempu:
CMake hè un sistema assai putente è flessibile chì vi permette di implementà funziunalità per ogni gustu è culore. E, ancu s'è a sintassi qualchì volta lascià assai per esse desideratu, u diavulu ùn hè micca cusì terribili quant'ellu hè dipintu. Aduprate u sistema di creazione CMake per u benefiziu di a sucità è a salute.