
Gjatë procesit të zhvillimit, më pëlqen të ndryshoj kompajlerët, modet e ndërtimit, versionet e varësive, të bëj një analizë statike, të mas përformancën, të mbledh mbulimin, të krijoj dokumentacion dhe kështu me radhë. Dhe më pëlqen shumë CMake, sepse më lejon të bëj gjithçka që dua.
Shumë njerëz kritikojnë CMake, dhe shpesh me të drejtë, por nëse e shqyrton, nuk është aq keq, dhe në kohët e fundit në fakt shumë mirë, dhe drejtimi i zhvillimit është mjaft pozitiv.
Në këtë shënim, dëshiroj të tregoj se si është mjaft e thjeshtë të organizosh një bibliotekë header në gjuhën C++ në sistemin CMake, për të arritur funksionalitetin e mëposhtëm:
- Ndërtimi;
- Autod запŃŃĐșа ŃĐ”ŃŃĐŸĐČ;
- Matja e mbulimit të kodit;
- Instalimi;
- Autodokumentimi;
- Krijimi i një sandbox-i online;
- Analiza statike.
Ata që e dinë mirë C++ dhe CMake mund të thjesht dhe të fillojnë ta përdorin atë.
Përmbajtja
.
âââ 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.cppKryesisht do tĂ« flasim pĂ«r mĂ«nyrĂ«n e organizimit tĂ« skripteve CMake, prandaj ato do tĂ« shqyrtohen nĂ« detaje. TĂ« tjerĂ«t mund tĂ« shikojnĂ« dosjet e mbetura .
Së pari, duhet të kërkojmë versionin e nevojshëm të CMake. CMake zhviillohet dhe nisin të ndryshojnë sintaksat e komandave, sjellja në kushte të ndryshme. Për të bërë që CMake të kuptojë menjëherë se çfarë duam prej tij, duhet të konfirmojmë kërkesat tona.
cmake_minimum_required(VERSION 3.13)Pastaj, do të përcaktojmë projektin tonë, emrin e tij, versionin, gjuhët e përdorura dhe më shumë (shihni ).
Në këtë rast, përcaktojmë gjuhën CXX (dhe kjo do të thotë C++), për të shmangur që CMake të shqetësohet dhe të kërkojë kompajlerin e gjuhës C (në bazë të parazgjedhjes, CMake ka dy gjuhë: C dhe C++).
project(Mylib VERSION 1.0 LANGUAGES CXX)Këtu mund të kontrolloni nëse projekti ynë është përfshirë si nënprojekt në një projekt tjetër. Kjo do të ndihmojë shumë në të ardhmen.
get_directory_property(IS_SUBPROJECT PARENT_DIRECTORY)
Do të parashikojmë dy opsione.
Opsioni i parĂ« â â pĂ«r tĂ« çaktivizuar testet modulare. Kjo mund tĂ« nevojitet nĂ«se jemi tĂ« sigurt se testet janĂ« nĂ« rregull, dhe ne duam, pĂ«r shembull, vetĂ«m tĂ« instalojmĂ« ose paketojmĂ« projektin tonĂ«. Ose projekti ynĂ« Ă«shtĂ« pĂ«rfshirĂ« si nĂ«nprojekt â nĂ« kĂ«tĂ« rast, pĂ«rdoruesit e projektit tonĂ« nuk kanĂ« interes tĂ« ekzekutojnĂ« testet tona. A nuk e testoni varĂ«sitĂ« qĂ« pĂ«rdorni?
option(MYLIB_TESTING "Aktivizo testimin modular" ON)Për më tepër, do të krijojmë një opsion të veçantë për matjen e mbulimit të kodit nga testet, por kjo do të kërkojë mjete shtesë, kështu që do të duhet ta aktivizoni atë në mënyrë të qartë.
option(MYLIB_COVERAGE "Aktivizo matjen e mbulimit të kodit nga testet" OFF)
Sigurisht, ne jemi programues të shkëlqyer në C++, prandaj duam maksimumin e nivelit të diagnostikave nga kompileri gjatë kohës së kompilimit. Asnjë mi nuk do të kalojë pa u vënë re.
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
)Do të çaktivizojmë gjithashtu zgjerimet, për të përputhur plotësisht standardin e gjuhës C++. Në CMake, ato janë të aktivizuara si standart.
if(NOT CMAKE_CXX_EXTENSIONS)
set(CMAKE_CXX_EXTENSIONS OFF)
endif()
Biblioteka jonë përbëhet vetëm nga skedarë të titullit, kështu që nuk kemi asnjë dalje në formën e librarive statike ose dinamike. Nga ana tjetër, për ta përdorur bibliotekën tonë nga jashtë, duhen instaluar, duhen bërë të pakapshme në sistem dhe të lidhen me projektin tuaj, dhe po ashtu me titujt e lidhur dhe ndoshta disa pronësi shtesë.
Për këtë qëllim krijojmë një bibliotekë ndërfaqësore.
add_library(mylib INTERFACE)Lidhim titujt me bibliotekën tonë ndërfaqësore.
Përdorimi modern, trendi dhe rinor i CMake-t sugjeron që titujt, pronësitë etj., kalohen përmes një qëllimi të vetëm. Prandaj, mjafton të thuhet , dhe të gjitha titujt që janë të asociuar me këtë qëllim dependency, do të jenë të disponueshëm për burimet e përkatëse për qëllimin target. Dhe nuk nevojiten ndonjëherë [target_]include_directories. Kjo do të demonstrohet më poshtë gjatë analizës .
Gjithashtu, vlen të përmendet e ashtuquajtura .
Ky komandë asocion titujt e nevojshëm me bibliotekën tonë ndërfaqësore, duke pasur parasysh se, nëse bibliotekë tona lidhet me një qëllim brenda një hierarkie CMake, do të asocohen titujt nga direktoria ${CMAKE_CURRENT_SOURCE_DIR}/include, dhe nëse biblioteca jonë instalohet në sistem dhe lidhet në një projekt tjetër përmes komandës , do të asocohen titujt nga direktoria include në marrëdhënie me drejtorinë e instalimit.
target_include_directories(mylib INTERFACE
$
$
)Do të caktosh standardin e gjuhës. Sigurisht, atë më të fundit. Ndërsa nuk mjafton thjesht të përfshihet standardi, por dhe ta përhapim atë tek ata që do ta përdorin bibliotekën tonë. Kjo arrihet përmes faktit se prona e caktuar ka kategorinë INTERFACE (shih ).
target_compile_features(mylib INTERFACE cxx_std_17)Do krijojmë një pseudonim për bibliotekën tonë. Gjithashtu, për estetikë do jetë në një «hapësirë emri» speciale. Kjo do të jetë e dobishme kur në bibliotekën tonë shfaqen module të ndryshme, të cilat lidhim ndaras. .
add_library(Mylib::mylib ALIAS mylib)
Instalimi i titujve tanë në sistem. Këtu është e thjeshtë. Thjesht themi se dosja me të gjitha titujt duhet të futet në drejtorinë include në marrëdhënie me vendin e instalimit.
install(DIRECTORY include/mylib DESTINATION include)Pastaj informojmë sistemin e ndërtimit që duam të kemi mundësinë që në projektet e jashtme të thërrasim komandën find_package(Mylib) dhe të marrim qëllimin Mylib::mylib.
install(TARGETS mylib EXPORT MylibConfig)
install(EXPORT MylibConfig NAMESPACE Mylib:: DESTINATION share/Mylib/cmake)Shpirti i ardhshëm duhet të kuptohet kështu. Kur në një projekt të jashtëm të thërrasim komandën find_package(Mylib 1.2.3 REQUIRED), dhe në të njëjtën kohë versioni actual i bibliotekës instaluar është i papërputhshëm me versionin 1.2.3, CMake automatikisht do të generejë një gabim. Do të thotë se nuk ka nevojë të keni vëmendje për versionet manualisht.
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)
Nëse testet janë çaktivizuar qartë përmes ose projekti ynë është një nënprojekt, domethënë i lidhur në një projekt tjetër CMake përmes komandës , ne nuk kalojmë më tej në hierarki, dhe skripti në të cilin përshkruhen komandat për gjenerimin dhe ekzekutimin e testeve, thjesht nuk ekzekutohet.
if(NOT MYLIB_TESTING)
message(STATUS "Testimi i projektit Mylib është i çaktivizuar")
elseif(IS_SUBPROJECT)
message(STATUS "Mylib nuk testohen në modalitetin nënmodul")
else()
add_subdirectory(test)
endif()
Dokumentacioni gjithashtu nuk do të gjenerohet në rastin e nënprojektit.
if(NOT IS_SUBPROJECT)
add_subdirectory(doc)
endif()
Në të njëjtën mënyrë, nuk do të ketë gjithashtu sandboxes online për nënprojektin.
if(NOT IS_SUBPROJECT)
add_subdirectory(online)
endif()
Së pari, gjejmë paketën me kornizën e testit të nevojshme (zëvendësoni me preferencën tuaj).
find_package(doctest 2.3.3 REQUIRED)Krijojmë skedarin tonë ekzekutiv me testet. Zakonisht drejtpërdrejt në binarin ekzekutiv unë shtoj vetëm skedarin, në të cilin do të jetë funksioni main.
add_executable(mylib-unit-tests test_main.cpp)Dhe skedarët në të cilat përshkruhen testet, i shtoj më vonë. Por nuk është e domosdoshme ta bësh kështu.
target_sources(mylib-unit-tests PRIVATE mylib/myfeature.cpp)Lidhim varësitë. Vini re se për binarin tonë ne kemi lidhur vetëm objektivat CMake të nevojshëm, dhe nuk kemi thirrur urdhërin target_include_directories. Titujt nga korniza e testit dhe nga tonë Mylib::mylib, si dhe parametrat e ndërtimit (në rastin tonë, kjo është standardi i gjuhës C++) kaluan së bashku me këto objekte.
target_link_libraries(mylib-unit-tests
PRIVATE
Mylib::mylib
doctest::doctest
)Së fundi, krijojmë një qëllim fals, "ndërtimi" i të cilit është ekuivalent me ekzekutimin e testeve dhe e shtojmë këtë qëllim në ndërtimin e parazgjedhur (kjo është përgjegjësia e atributit Tà GJITHA). Kjo do të thotë se ndërtimi i parazgjedhur nxisin ekzekutimin e testeve, domethënë kurrë nuk do ta harrojmë t'i ekzekutojmë ato.
add_custom_target(check ALL COMMAND mylib-unit-tests)
Më pas aktivizojmë matjen e përmbajtjes së kodit, nëse është dhënë opsioni përkatës. Nuk do të futem në detaje, sepse ato lidhen më shumë me mjetin për matjen e përmbajtjes se sa me CMake. E rëndësishme është të theksohet se në përfundim do të krijohet një qëllim , me ndihmën e të cilit është e lehtë të ekzekutohet matja e përmbajtjes.
find_program(GCOVR_EXECUTABLE gcovr)
if(MYLIB_COVERAGE AND GCOVR_EXECUTABLE)
message(STATUS "Matja e mbulimit të kodit me teste është e aktivizuar")
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 "Programi gcovr është i nevojshëm për matjen e mbulimit të kodit me teste")
endif()
.
find_package(Doxygen)Pastaj kontrollojmë nëse përdoruesi ka vendosur variablën për gjuhën. Nëse po, atëherë nuk e prekim, nëse jo, marrim gjuhën shqipe. Më pas konfiguroni skedarët e sistemit Doxygen. Të gjitha variablat e nevojshme, përfshirë gjuhën, do të kalojnë aty gjatë procesit të konfigurimit (shih. ).
Më pas krijojmë një objektiv , i cili do të ekzekutojë gjenerimin e dokumentacionit. Duke qenë se gjenerimi i dokumentacionit nuk është një nevojë e madhe gjatë zhvillimit, objekti në parazgjedhje nuk do të aktivizohet, do të duhet ta ekzekutoni në mënyrë të qartë.
if (Doxygen_FOUND)
if (NOT MYLIB_DOXYGEN_LANGUAGE)
set(MYLIB_DOXYGEN_LANGUAGE Albanian)
endif()
message(STATUS "Dokumentacioni Doxygen do të gjenerohet në ${MYLIB_DOXYGEN_LANGUAGE}")
configure_file(Doxyfile.in Doxyfile)
add_custom_target(doc COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}\/Doxyfile)
endif ()
Këtu gjejmë Python-in e tretë dhe krijojmë një objektiv , që gjeneron kërkesën përkatëse për API-në e shërbimit , dhe e dërgon atë. Në përgjigje, kthehet një lidhje për sandbox-in e gatshëm.
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 "Për krijimin e një sandbox-i online, kërkohet interpretuese e gjuhës programimit python version 3")
endif()
Tani le të shohim se si të përdorim të gjitha këto.
Ndërtimi i këtij projekti, si çdo projekt tjetër në sistemin e ndërtimit CMake, përbëhet nga dy faza:
cmake -S rruga\/në\/burime -B rruga\/në\/direktorinë\/ndërtuese [opsionet ...]Nëse komandën e mësipërme nuk funksionon për shkak të një versioni të vjetër të CMake, provoni të hiqni
-S:cmake rruga\/në\/burime -B rruga\/në\/direktorinë\/ndërtuese [opsionet ...]
.
cmake --build rruga\/në\/direktorinë\/ndërtuese [--target target].
cmake -S ... -B ... -DMYLIB_COVERAGE=ON [opsione të tjera ...]Aktivizon objektivin , e cila mund të aktivizojë matjen e mbulimit të kodit përmes testeve.
cmake -S ... -B ... -DMYLIB_TESTING=OFF [opsione të tjera ...]Ofron mundësinë për të çaktivizuar ndërtimin e testeve modulare dhe qëllimin . Si rezultat, çaktivizohet matja e mbulimit të kodit me teste (shih. ).
Po ashtu, testingu automatikisht çaktivizohet në rast se projekti lidhet në një projekt tjetër si nënpunës përmes komandës .
cmake -S ... -B ... -DMYLIB_DOXYGEN_LANGUAGE=English [opsione të tjera ...]Ndërron gjuhën e dokumentacionit që gjeneron qëllimi në atë të caktuar. Lista e gjuhëve të disponueshme shihet në .
Nga default, është aktivizuar gjuha ruse.
cmake --build path/to/build/directory
cmake --build path/to/build/directory --target allNëse qëllimi nuk përcaktohet (e cila është ekuivalente me qëllimin të gjitha), ndërtimi i gjithçkaje që mundet, si dhe thirrja e qëllimit .
cmake --build path/to/build/directory --target mylib-unit-testsKompilon testet modulare. Aktivizuar nga default.
cmake --build path/te/sherbimeve --target checkEkzekuton testet e ndërtuara (ndërtimin nëse akoma nuk është bërë). Aktivizuar nga default.
Shih gjithashtu .
cmake --build path/te/sherbimeve --target coverageAnalizon testet e ndërtuara (thirrjen nëse akoma nuk është bërë) për mbulimin e kodit me testet duke përdorur programin .
Aktiviteti i mbulimit do të duket afërsisht kështu:
------------------------------------------------------------------------------
Raporti i Mbulesës së Kodit GCC
Directory: /path/to/cmakecpptemplate/include/
------------------------------------------------------------------------------
File Lines Exec Cover Missing
------------------------------------------------------------------------------
mylib/myfeature.hpp 2 2 100%
------------------------------------------------------------------------------
TOTAL 2 2 100%
------------------------------------------------------------------------------Qëllimi është i disponueshëm vetëm kur është aktivizuar opsioni .
Shih gjithashtu .
cmake --build path/te/sherbimeve --target docAktivizon gjenerimin e dokumentacionit për kodin përmes sistemit .
cmake --build path/te/sherbimeve --target wandboxPërgjigjja nga shërbimi duket afërsisht kështu:
{
"permlink" : "QElvxuMzHgL9fqci",
"status" : "0",
"url" : "https://wandbox.org/permlink/QElvxuMzHgL9fqci"
}Për këtë përdoret shërbimi . Nuk e di sa elastike janë serverët e tyre, por mendoj se nuk duhet abuzuar me këtë mundësi.
Ndërtimi i projektit në modin e depurimit me matjen e mbulimit
cmake -S path/te/burimeve -B path/te/sherbimeve -DCMAKE_BUILD_TYPE=Debug -DMYLIB_COVERAGE=ON
cmake --build path/te/sherbimeve --target coverage --parallel 16Instalimi i projektit pa përgatitje të mëparshme dhe testim
cmake -S rruga/këto/burime -B rruga/këto/directorinë/bashkues -DMYLIB_TESTING=OFF -DCMAKE_INSTALL_PREFIX=rruga/këto/directorinë/e/instalimit
cmake --build rruga/këto/directorinë/bashkues --target installNdërtimi në modalitetin e prodhimit me kompiluesin e caktuar
cmake -S rruga/këto/burime -B rruga/këto/directorinë/bashkues -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=g++-8 -DCMAKE_PREFIX_PATH=rruga/këto/directorinë/ku/kanë/instaluar/depozitat
cmake --build rruga/këto/directorinë/bashkues --parallel 4Gjene dokumentacionin në anglisht
cmake -S rruga/këto/burime -B rruga/këto/directorinë/bashkues -DCMAKE_BUILD_TYPE=Release -DMYLIB_DOXYGEN_LANGUAGE=English
cmake --build rruga/këto/directorinë/bashkues --target doc
3.13
Në të vërtetë, versioni CMake 3.13 kërkohet vetëm për të ekzekutuar disa komanda konsolë të përshkruara në këtë manual. Nga këndvështrimi i sintaksës së skripteve CMake, versioni 3.8 është i mjaftueshëm nëse gjenerimi thirret në mënyra të tjera.
Biblioteka e testimit
Testimi mund të fiket (shih ).
Për të ndryshuar gjuhën në të cilën do të gjenerohet dokumentacioni, është parashikuar një opsion .
Interpretues i gjuhës së programimit
Për gjenerimin automatik .
Me ndihmën e CMake dhe disa mjeteve të mira, mund të sigurohet analiza statike me minimal përpjekje.
Cppcheck
CMake mbështet në mënyrë të integruar mjetin për analizën statike .
Për këtë, duhet të përdorni opsionin :
cmake -S rruga/këto/burime -B rruga/këto/directorinë/bashkues -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_CPPCHECK="cppcheck;--enable=all;-Irruga/këto/burime/include"Pas kësaj, analiza statike do të ekzekutohet automatikisht çdo herë gjatë kompilimit dhe riparimit të burimeve. Nuk është nevojitur asgjë tjetër.
Clang
Me ndihmën e një mjeti të mrekullueshëm mund të ekzekutoni gjithashtu analizën statike me lehtësi:
scan-build cmake -S rruga/këto/burime -B rruga/këto/directorinë/bashkues -DCMAKE_BUILD_TYPE=Debug
scan-build cmake --build rruga/këto/directorinë/bashkuesKëtu, ndryshe nga rasti me Cppcheck, kërkohet që çdo herë të niset ndërtimi përmes scan-build.
CMake është një sistem shumë i fuqishëm dhe fleksibël, i cili lejon realizimin e funksionaliteteve sipas shijes dhe preferencave. Edhe pse, sintaksa ndonjëherë lë për të dëshiruar, e vërteta është se nuk është aq e frikshme sa e piktaron njëri. Përdorni sistemin e ndërtimit CMake për mirë të komunitetit dhe me përfitim për shëndetin.
â
Burimi: habr.com
