
Arendusprotsessis meeldib mulle vahetada kompilaatorite, kogumise režiimide, sõltuvuste versioonide vahel, teha staatilist analüüsi, mõõta jõudlust, koguda katvust, genereerida dokumentatsiooni jne. Ja mulle meeldib väga CMake, sest see võimaldab mul teha kõike, mida ma tahan.
Paljud inimesed kritiseerivad CMake'i ning tihti on see õigustatud, kuid kui asja lähemalt uurida, pole asi üldse nii halb, ja viimase ajal on see isegi päris hästi edenenud, ning areng suund on täiesti positiivne.
Selles märkuses soovin rääkida sellest, kuidas on üsna lihtne organiseerida C++ peaaguplokki CMake süsteemis, et saavutada järgmine funktsionaalsus:
- Kogumine;
- Automaatne testide käivitamine;
- Koodikatvuse mõõtmine;
- Paigaldamine;
- Automaatne dokumenteerimine;
- Online-keskkonna genereerimine;
- Staatiline analüüs.
Kes juba teab Plusidest ja CMake'ist, võib lihtsalt ja hakkata seda kasutama.
Sisukord
.
├── CMakeLists.txt
├── README.en.md
├── README.md
├── doc
│ ├── CMakeLists.txt
│ └── Doxyfile.in
├── include
│ └── mylib
│ └── myfeature.hpp
├── online
│ ├── CMakeLists.txt
│ ├── mylib-example.cpp
│ └── wandbox.py
└── test
├── CMakeLists.txt
├── mylib
│ └── myfeature.cpp
└── test_main.cppPõhiliselt räägime sellest, kuidas organiseerida CMake skripte, seetõttu käsitletakse neid põhjalikult. Ülejäänud faile saab iga soovija vaadata otse .
Esiteks tuleb küsida vajalikku versiooni CMake süsteemist. CMake areneb, käskude allkirjad ja käitumine erinevates tingimustes muutuvad. Et CMake kohe mõistaks, mida me temalt ootame, tuleb kohe fikseerida meie ehk nõudmised.
cmake_minimum_required(VERSION 3.13)Seejärel tähistame oma projekti, selle nime, versiooni, kasutatavad keeled ja muud (vt. ).
Sel juhul määrame keele CXX (see tähendab C++), et CMake ei pingutaks ja ei otsiks C keele kompilaatorit (CMake'is on vaikimisi sisse lülitatud kaks keelt: C ja C++).
project(Mylib VERSION 1.0 LANGUAGES CXX)Siin on võimalik kohe kontrollida, kas meie projekt on teises projektis alaprojektina kaasatud. See aitab meid tulevikus oluliselt.
get_directory_property(IS_SUBPROJECT PARENT_DIRECTORY)
Kaalume kahte valikut.
Esimene valik — — modulaarsete testide väljalülitamine. See võib olla vajalik, kui oleme kindlad, et testidega on kõik korras, kuid soovime näiteks oma projekti ainult installida või pakkida. Või on meie projekt kaasatud alaprojektina — sellisel juhul pole meie projekti kasutajale huvi meie teste käivitada. Kas te testite sõltuvusi, mida kasutate?
option(MYLIB_TESTING "Luba modulaarne testimine" ON)Lisaks teeme eraldi valiku kattuvuse mõõtmiseks testidega, kuid see vajab täiendavaid tööriistu, seega tuleb see selgelt lubada.
option(MYLIB_COVERAGE "Luba testidega kattuvuse mõõtmine" OFF)
Muidugi oleme me ägedad C++ programmeerijad ja seetõttu tahame kompilaatori poolt maksimaalset kompileerimise aja diagnostikat. Ükski hiir ei lipsa läbi.
add_compile_options(
-Werror
-Wall
-Wextra
-Wpedantic
-Wcast-align
-Wcast-qual
-Wconversion
-Wctor-dtor-privacy
-Wenum-compare
-Wfloat-equal
-Wnon-virtual-dtor
-Wold-style-cast
-Woverloaded-virtual
-Wredundant-decls
-Wsign-conversion
-Wsign-promo
)Samuti keelame laiendused, et täielikult vastata C++ keele standardile. CMake'is on need vaikimisi lubatud.
if(NOT CMAKE_CXX_EXTENSIONS)
set(CMAKE_CXX_EXTENSIONS OFF)
endif()
Meie teek koosneb ainult pealkirjafailidest, mistõttu meil ei ole mingit väljundit staatiliste või dünaamiliste teekide näol. Teisest küljest, et meie teeki väljastpoolt kasutada, tuleb see installida, et seda saaks süsteemis avastada ja oma projekti lisada, ning sellega peavad olema koos need sama pealkirjad, samuti võimalikud täiendavad omadused.
Selle eesmärgi saavutamiseks loome liidese teegi.
add_library(mylib INTERFACE)Seome pealkirjad meie liidese teegiga.
Kaasaegne, trendikas ja nooruslik CMake'i kasutamine eeldab, et pealkirjad, omadused jne edastatakse läbi üheainsa sihtmärk. , ja kõik pealkirjad, mis on seotud sihtmärgiga dependency, on saadaval sihtmärgi kuuluvatele lähtekoodidele target. Ja ei ole vaja mingit [target_]include_directories. Это будет продемонстрировано ниже при разборе .
Также стоит обратить внимание на т.н. .
Данная команда ассоциирует нужные нам заголовки с нашей интерфейсной библиотекой, причём, в случае, если наша библиотека будет подключена к какой-либо цели в рамках одной иерархии CMake, то с ней будут ассоциированы заголовки из директории ${CMAKE_CURRENT_SOURCE_DIR}/include, а если наша библиотека установлена в систему и подключена в другой проект с помощью команды , то с ней будут ассоциированы заголовки из директории include относительно директории установки.
target_include_directories(mylib INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)Установим стандарт языка. Разумеется, самый последний. При этом не просто включаем стандарт, но и распространяем его на тех, кто будет использовать нашу библиотеку. Это достигается за счёт того, что установленное свойство имеет категорию INTERFACE (vt. ).
target_compile_features(mylib INTERFACE cxx_std_17)Заводим псевдоним для нашей библиотеки. Причём для красоты он будет в специальном «пространстве имён». Это будет полезно, когда в нашей библиотеке появятся разные модули, и мы заходим подключать их независимо друг от друга. .
add_library(Mylib::mylib ALIAS mylib)
Установка наших заголовков в систему. Тут всё просто. Говорим, что папка со всеми заголовками должна попасть в директорию include относительно места установки.
install(DIRECTORY include/mylib DESTINATION include)Далее сообщаем системе сборки о том, что мы хотим иметь возможность в сторонних проектах звать команду find_package(Mylib) и получать цель Mylib::mylib.
install(TARGETS mylib EXPORT MylibConfig)
install(EXPORT MylibConfig NAMESPACE Mylib:: DESTINATION share/Mylib/cmake)Следующее заклинание нужно понимать так. Когда в стороннем проекте мы вызовем команду find_package(Mylib 1.2.3 REQUIRED), и при этом реальная версия установленной библиотеки окажется несовместимой с версией 1.2.3, CMake автоматически сгенерирует ошибку. То есть не нужно будет следить за версиями вручную.
include(CMakePackageConfigHelpers)
write_basic_package_version_file("${PROJECT_BINARY_DIR}/MylibConfigVersion.cmake"
VERSION
${PROJECT_VERSION}
COMPATIBILITY
AnyNewerVersion
)
install(FILES "${PROJECT_BINARY_DIR}/MylibConfigVersion.cmake" DESTINATION share/Mylib/cmake)
Если тесты выключены явно с помощью või meie projekt on alamprojekt, see tähendab, et see on ühendatud teise CMake projekti kaudu käsu , me ei liigu hierarhias edasi ja skript, milles on kirjeldatud käsud testide genereerimiseks ja käivitamiseks, lihtsalt ei käivitu.
if(NOT MYLIB_TESTING)
message(STATUS "Mylibi projekti testimine on keelatud")
elseif(IS_SUBPROJECT)
message(STATUS "Mylibi ei testita alammodulina")
else()
add_subdirectory(test)
endif()
Dokumentatsiooni ei genereerita ka alamprojekti puhul.
if(NOT IS_SUBPROJECT)
add_subdirectory(doc)
endif()
Sarnaselt ei ole alamprojekti juhul ka veebiliivakaste.
if(NOT IS_SUBPROJECT)
add_subdirectory(online)
endif()
Esiteks otsime paketti vajaliku testimisraamistiku jaoks (asendage oma lemmikuga).
find_package(doctest 2.3.3 REQUIRED)Loome oma käivitatava faili testide jaoks. Tavaline on, et käivitatavasse binaari lisan ainult faili, kus on funktsioon main.
add_executable(mylib-unit-tests test_main.cpp)Ja failid, kus on kirja pandud testid, lisan hiljem. Kuid nii teha ei ole vajalik.
target_sources(mylib-unit-tests PRIVATE mylib/myfeature.cpp)Seome sõltuvused. Pange tähele, et meie binaariga seostasime ainult vajalikud CMake eesmärgid ega kutsunud üles käsku target_include_directories. Testimisraamistiku pealkirjad ja meie Mylib::mylib, samuti kogumise parameetrid (meie juhul on see C++ keele standard) läksid koos nende eesmärkidega läbi.
target_link_libraries(mylib-unit-tests
PRIVATE
Mylib::mylib
doctest::doctest
)Lõpuks loome vale eesmärgi, mille "kogumine" on võrdne testide käitamisega, ja lisame selle doelame standardkogumisse (seda juhib atribuut , või). See tähendab, et vaikimisi kogumine käivitab testide käitamist, seega me kunagi ei unusta neid käivitada.
add_custom_target(check ALL COMMAND mylib-unit-tests)
Seejärel aktiveerime koodikatvuse mõõtmise, kui vastav valik on määratud. Sügavale detailidesse ei lähe, kuna need kuuluvad rohkem katvuse mõõtamisseadmesse kui CMake'ile. Oluline on märkida ainult, et tulemuste põhjal luuakse eesmärk , millega on mugav käivitada katvuse mõõtmine.
find_program(GCOVR_EXECUTABLE gcovr)
if(MYLIB_COVERAGE AND GCOVR_EXECUTABLE)
message(STATUS "Koodikatse katvuse mõõtmine on sisse lülitatud")
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 "Koodikatse katvuse mõõtmiseks on vajalik programm gcovr")
endif()
.
find_package(Doxygen)Edasi kontrollime, kas kasutaja on määranud keelemuutuja. Kui jah, siis ei puutu sellesse, kui ei, siis võtame vene. Seejärel konfigureerime Doxygen süsteemi failid. Kõik vajalikud muutujad, sealhulgas keel, saadakse konfiguratsiooni käigus (vt. ).
Peale seda loome sihiks , mis käivitab dokumentatsiooni genereerimise. Kuna dokumentatsiooni genereerimine ei ole arenduse käigus kõige tähtsam vajadus, siis ei ole siht vaikimisi sisse lülitatud, see tuleb käivitada selgelt.
if (Doxygen_FOUND)
if (NOT MYLIB_DOXYGEN_LANGUAGE)
set(MYLIB_DOXYGEN_LANGUAGE Vene)
endif()
message(STATUS "Doxygeni dokumentatsioon genereeritakse keeles ${MYLIB_DOXYGEN_LANGUAGE}")
configure_file(Doxyfile.in Doxyfile)
add_custom_target(doc COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}\/Doxyfile)
endif ()
Siin leiame kolmanda Python'i ja loome sihiks , mis genereerib päringu, mis vastab teenuse API-le , ja saadab selle. Vastuseks tulevad valmis liivakasti link.
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 "Veebiliivakasti loomiseks on vajalik Python 3 interpreteur")
endif()
Nüüd vaatame, kuidas seda kõike kasutada.
Selle projekti koostamine, nagu ka iga teise CMake süsteemi projekti puhul, koosneb kahest etapist:
cmake -S tee\/kallid -B tee\/kogumiskohta [valikud ...]Kui ülemine käsk ei toiminud vanema CMake versiooni tõttu, proovige jätta välja
-S:cmake tee\/kallid -B tee\/kogumiskohta [valikud ...]
.
cmake --build tee\/kogumiskohta [--target siht].
cmake -S ... -B ... -DMYLIB_COVERAGE=ON [teised valikud ...]Lülitab sihi sisse , mille on võimalik käivitada koodikatvuse mõõtmine testide kaudu.
cmake -S ... -B ... -DMYLIB_TESTING=OFF [muud seaded ...]Pakub võimalusi moodulite testimise ja eesmärgi väljalülitamiseks. . Selle tulemusena lülitatakse koodikatvuse mõõtmine testide kaudu välja (vt. ).
Samuti lülitatakse testimine automaatselt välja, kui projekt lisatakse teise projekti alaprojektina käsu abil .
cmake -S ... -B ... -DMYLIB_DOXYGEN_LANGUAGE=English [muud seaded ...]Vahetab dokumentatsiooni keele, mille genereerib eesmärk mugandatuks. Saadaval olevate keelte loetelu leiate .
Vaikimisi on keel vene.
cmake --build path/to/build/directory
cmake --build path/to/build/directory --target allKui eesmärki ei ole määratud (mis on samaväärne eesmärgiga all), kogub kõik, mis on võimalik, ning kutsub üles eesmärki. .
cmake --build path/to/build/directory --target mylib-unit-testsKompileerib moodulitestide. Vaikimisi on see sisse lülitatud.
cmake --build tee/ehituskausta --target checkKäivitab koostatud (kogub, kui veel mitte) moodulitestid. Vaikimisi on see sisse lülitatud.
Vaata ka .
cmake --build tee/ehituskausta --target coverageAnalüüsib käivitatud (käivitab, kui veel mitte) moodulitestid koodikatvuse osas testimise ajal programmi .
Katvuse väljund näeb välja selline:
------------------------------------------------------------------------------
GCC Koodikatvuse Aruanne
Kaust: /path/to/cmakecpptemplate/include/
------------------------------------------------------------------------------
Fail Read Täitmine Katvus Puuduvad
------------------------------------------------------------------------------
mylib/myfeature.hpp 2 2 100%
------------------------------------------------------------------------------
TOTAL 2 2 100%
------------------------------------------------------------------------------Eesmärk on saadaval ainult, kui valik on sisse lülitatud. .
Vaata ka .
cmake --build tee/ehituskausta --target docKäivitab dokumentatsiooni genereerimise koodi jaoks Doxygen süsteemi abil. .
cmake --build tee/ehituskausta --target wandboxTeenuse vastus näeb välja selline:
{
"permlink" : "QElvxuMzHgL9fqci",
"status" : "0",
"url" : "https://wandbox.org/permlink/QElvxuMzHgL9fqci"
}Selleks kasutatakse teenust . Ma ei tea, kui paindlikud nende serverid on, kuid ma arvan, et seda võimalust ei tasu kuritarvitada.
Projekti ülesehitus tõrkeotsingu režiimis koodikatvuse mõõtmisega.
cmake -S tee/komplekt/dokumendid -B tee/ehituskausta -DCMAKE_BUILD_TYPE=Debug -DMYLIB_COVERAGE=ON
cmake --build tee/ehituskausta --target coverage --parallel 16Projekti paearendust ja testimist
cmake -S tee/koodifailid -B tee/ehituskaust -DMYLIB_TESTING=OFF -DCMAKE_INSTALL_PREFIX=tee/paigalduskaust
cmake --build tee/ehituskaust --target installEhitus vabastamisrežiimis määratud kompilaatoriga
cmake -S tee/koodifailid -B tee/ehituskaust -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=g++-8 -DCMAKE_PREFIX_PATH=tee/kaust/kuhu/paigaldatud/sõltuvused
cmake --build tee/ehituskaust --parallel 4Dokumentatsiooni genereerimine inglise keeles
cmake -S tee/koodifailid -B tee/ehituskaust -DCMAKE_BUILD_TYPE=Release -DMYLIB_DOXYGEN_LANGUAGE=English
cmake --build tee/ehituskaust --target doc
3.13
Tegelikult vajatakse CMake versiooni 3.13 ainult teatud konsolikomandide käivitamiseks, mis on kirjeldatud antud juhendis. CMake-skriptide süntaksiks piisab versioonist 3.8, kui genereerimist kutsuda välja muude viiside kaudu.
Testimise raamatukogu
Testimist saab keelduda (vt. ).
Dokumentatsioonikeele vahetamiseks on olemas valik .
Tõlkija YP
Automaatseks genereerimiseks .
CMake ja paar head tööriista võivad hõlpsasti tagada staatilise analüüsi minimaalse vaevaga.
Cppcheck
CMake'is on sisseehitatud tugi staatilise analüüsi tööriistale .
Selleks tuleb kasutada valikut :
cmake -S tee/koodifailid -B tee/ehituskaust -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_CPPCHECK="cppcheck;--enable=all;-Itee/koodifailid/include"Pärast seda käivitatakse staatiline analüüs automaatselt iga kord, kui lähtefaile kompileeritakse ja uuesti kompileeritakse. Ei ole vaja midagi lisada.
Clang
Imekauni tööriista abil saab samuti staatilist analüüsi kiiresti käivitada:
scan-build cmake -S tee/koodifailid -B tee/ehituskaust -DCMAKE_BUILD_TYPE=Debug
scan-build cmake --build tee/ehituskaustSiin on vastupidiselt Cppcheck'ile vajalik igakordselt käivitada ehitus scan-build.
CMake on väga võimas ja paindlik süsteem, mis võimaldab realiseerida igasugust funktsionaalsust. Ja kuigi süntaks jätab vahel soovida, ei ole see nii hirmus, kui teda maalitakse. Kasutage CMake ehitussüsteemi ühiskonna hüvanguks ja enda terviseks.
→
Allikas: habr.com
