Gjatë zhvillimit, më pëlqen të ndryshoj përpiluesit, të ndërtoj mënyrat, versionet e varësisë, të kryej analiza statike, të masë performancën, të mbledh mbulimin, të gjeneroj dokumentacion, etj. Dhe unë me të vërtetë e dua CMake sepse më lejon të bëj gjithçka që dua.
Shumë njerëz e kritikojnë CMake, dhe shpesh kështu meritojnë, por nëse e shikoni, jo gjithçka është aq e keqe, dhe kohët e fundit aspak keq, dhe drejtimi i zhvillimit është mjaft pozitiv.
Në këtë shënim, unë dua t'ju tregoj se si thjesht të organizoni një bibliotekë me kokë në C++ në sistemin CMake për të marrë funksionalitetin e mëposhtëm:
Ne do të flasim kryesisht për mënyrën e organizimit të skripteve CMake, kështu që ato do të diskutohen në detaje. Çdokush mund të shikojë drejtpërdrejt pjesën tjetër të skedarëve në faqen e projektit shabllon.
Para së gjithash, duhet të kërkoni versionin e kërkuar të sistemit CMake. CMake po evoluon, nënshkrimet e komandës dhe sjellja në kushte të ndryshme po ndryshojnë. Në mënyrë që CMake të kuptojë menjëherë se çfarë duam prej tij, ne duhet të regjistrojmë menjëherë kërkesat tona për të.
cmake_minimum_required(VERSION 3.13)
Pastaj ne do të caktojmë projektin tonë, emrin e tij, versionin, gjuhët e përdorura, etj. (shih. команду project).
Në këtë rast ne tregojmë gjuhën CXX (dhe kjo do të thotë C++) në mënyrë që CMake të mos sforcohet dhe të kërkojë një përpilues të gjuhës C (si parazgjedhje, CMake përfshin dy gjuhë: C dhe C++).
project(Mylib VERSION 1.0 LANGUAGES CXX)
Këtu mund të kontrolloni menjëherë nëse projekti ynë është përfshirë në një projekt tjetër si nënprojekt. Kjo do të ndihmojë shumë në të ardhmen.
Opsioni i parë është MYLIB_TESTING — për të çaktivizuar testet e njësisë. Kjo mund të jetë e nevojshme nëse jemi të sigurt se gjithçka është në rregull me testet, por ne duam vetëm, për shembull, të instalojmë ose paketojmë projektin tonë. Ose projekti ynë përfshihet si nënprojekt - në këtë rast, përdoruesi i projektit tonë nuk është i interesuar të ekzekutojë testet tona. Ju nuk i testoni varësitë që përdorni, apo jo?
Përveç kësaj, ne do të bëjmë një opsion të veçantë MYLIB_COVERAGE për matjen e mbulimit të kodit me teste, por do të kërkojë mjete shtesë, kështu që do të duhet të aktivizohet në mënyrë eksplicite.
Natyrisht, ne jemi programues të lezetshëm plus, kështu që duam nivelin maksimal të diagnostikimit në kohën e përpilimit nga përpiluesi. Asnjë mi i vetëm nuk do të rrëshqasë.
Ne do të çaktivizojmë gjithashtu shtesat në mënyrë që të përputhen plotësisht me standardin e gjuhës C++. Ato janë aktivizuar si parazgjedhje në CMake.
Biblioteka jonë përbëhet vetëm nga skedarë kokë, që do të thotë se nuk kemi asnjë shkarkim në formën e bibliotekave statike ose dinamike. Nga ana tjetër, për të përdorur bibliotekën tonë nga jashtë, ajo duhet të instalohet, duhet të jetë e zbulueshme në sistem dhe e lidhur me projektin tuaj, dhe në të njëjtën kohë të njëjtat tituj, si dhe mundësisht disa të tjerë shtesë. i janë bashkangjitur vetitë.
Për këtë qëllim, ne krijojmë një bibliotekë ndërfaqe.
add_library(mylib INTERFACE)
Ne lidhim titujt me bibliotekën tonë të ndërfaqes.
Përdorimi modern, në modë, rinor i CMake nënkupton që titujt, vetitë, etj. transmetohet përmes një objektivi të vetëm. Pra, mjafton të thuhet target_link_libraries(target PRIVATE dependency), dhe të gjithë titujt që janë të lidhur me objektivin dependency, do të jetë në dispozicion për burimet që i përkasin objektivit target. Dhe jo [target_]include_directories. Kjo do të tregohet më poshtë në analizë CMake skript për testet e njësisë.
Kjo komandë lidh titujt që na duhen me bibliotekën tonë të ndërfaqes dhe nëse biblioteka jonë është e lidhur me ndonjë objektiv brenda së njëjtës hierarki CMake, atëherë titujt nga drejtoria do të shoqërohen me të. ${CMAKE_CURRENT_SOURCE_DIR}/include, dhe nëse biblioteka jonë është e instaluar në sistem dhe e lidhur me një projekt tjetër duke përdorur komandën find_package, atëherë titujt nga drejtoria do të shoqërohen me të include në lidhje me direktorinë e instalimit.
Le të vendosim një standard gjuhësor. Sigurisht, kjo e fundit. Në të njëjtën kohë, ne jo vetëm e përfshijmë standardin, por edhe e shtrijmë atë tek ata që do të përdorin bibliotekën tonë. Kjo arrihet për faktin se vetia e vendosur ka një kategori INTERFACE (Cm. komanda target_compile_features).
Le të krijojmë një pseudonim për bibliotekën tonë. Për më tepër, për bukurinë, do të jetë në një "hapësirë emrash" të veçantë. Kjo do të jetë e dobishme kur module të ndryshme shfaqen në bibliotekën tonë dhe ne shkojmë t'i lidhim ato në mënyrë të pavarur nga njëri-tjetri. Si në Busta, për shembull.
Instalimi i titujve tanë në sistem. Gjithçka është e thjeshtë këtu. Ne themi që dosja me të gjitha titujt duhet të hyjë në direktori include në lidhje me vendin e instalimit.
Më pas, informojmë sistemin e ndërtimit që duam të jemi në gjendje të thërrasim komandën në projektet e palëve të treta find_package(Mylib) dhe merrni një gol Mylib::mylib.
Magjia tjetër duhet kuptuar në këtë mënyrë. Kur në një projekt të palës së tretë ne thërrasim komandën find_package(Mylib 1.2.3 REQUIRED), dhe versioni real i bibliotekës së instaluar do të jetë i papajtueshëm me versionin 1.2.3CMake do të gjenerojë automatikisht një gabim. Kjo do të thotë, nuk do t'ju duhet të gjurmoni versionet manualisht.
Nëse testet çaktivizohen duke përdorur në mënyrë të qartë opsionin përkatës ose projekti ynë është një nënprojekt, domethënë është i lidhur me një projekt tjetër CMake duke përdorur komandën add_subdirectory, ne nuk lëvizim më tej përgjatë hierarkisë dhe skripti, i cili përshkruan komandat për gjenerimin dhe ekzekutimin e testeve, thjesht nuk funksionon.
if(NOT MYLIB_TESTING)
message(STATUS "Тестирование проекта Mylib выключено")
elseif(IS_SUBPROJECT)
message(STATUS "Mylib не тестируется в режиме подмодуля")
else()
add_subdirectory(test)
endif()
Para së gjithash, ne gjejmë një paketë me kornizën e kërkuar të testit (zëvendësojeni me atë të preferuarin tuaj).
find_package(doctest 2.3.3 REQUIRED)
Le të krijojmë skedarin tonë të ekzekutueshëm me teste. Zakonisht shtoj direkt në binarin e ekzekutueshëm vetëm skedarin që do të përmbajë funksionin main.
add_executable(mylib-unit-tests test_main.cpp)
Dhe unë shtoj skedarë në të cilët vetë testet përshkruhen më vonë. Por ju nuk duhet ta bëni këtë.
Ne lidhim varësitë. Ju lutemi vini re se ne lidhëm vetëm objektivat CMake që na duheshin me binarin tonë dhe nuk e thirrëm komandën target_include_directories. Titujt nga korniza e testit dhe nga e jona Mylib::mylib, si dhe parametrat e ndërtimit (në rastin tonë, ky është standardi i gjuhës C++) u arritën së bashku me këto qëllime.
Së fundi, ne krijojmë një objektiv të rremë, "ndërtimi" i të cilit është ekuivalent me testet e ekzekutimit dhe e shtojmë këtë objektiv në ndërtimin e paracaktuar (atributi është përgjegjës për këtë ALL). Kjo do të thotë që ndërtimi i parazgjedhur shkakton ekzekutimin e testeve, që do të thotë se nuk do të harrojmë kurrë t'i ekzekutojmë ato.
add_custom_target(check ALL COMMAND mylib-unit-tests)
Më pas, ne aktivizojmë matjen e mbulimit të kodit nëse specifikohet opsioni i duhur. Nuk do të hyj në detaje, sepse ato lidhen më shumë me një mjet për matjen e mbulimit sesa me CMake. Është e rëndësishme vetëm të theksohet se në bazë të rezultateve do të krijohet një qëllim coverage, me të cilin është i përshtatshëm për të filluar matjen e mbulimit.
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()
Më pas, kontrollojmë nëse përdoruesi ka vendosur variablin e gjuhës. Nëse po, atëherë nuk e prekim, nëse jo, atëherë marrim rusisht. Pastaj ne konfigurojmë skedarët e sistemit Doxygen. Të gjitha variablat e nevojshme, duke përfshirë gjuhën, shkojnë atje gjatë procesit të konfigurimit (shih. команду configure_file).
Pastaj krijojmë një qëllim doc, i cili do të nisë gjenerimin e dokumentacionit. Meqenëse gjenerimi i dokumentacionit nuk është nevoja më e madhe në procesin e zhvillimit, objektivi nuk do të aktivizohet si parazgjedhje; ai do të duhet të lançohet në mënyrë eksplicite.
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 ()
Këtu gjejmë Python-in e tretë dhe krijojmë një objektiv wandbox, e cila gjeneron një kërkesë që korrespondon me shërbimin API Kuti me shkop, dhe e largon atë. Përgjigja vjen me një lidhje me sandboxin e përfunduar.
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()
Ofron aftësinë për të çaktivizuar ndërtimin dhe objektivin e testit të njësisë check. Si rezultat, matja e mbulimit të kodit nga testet është çaktivizuar (shih. MYLIB_COVERAGE).
Testimi gjithashtu çaktivizohet automatikisht nëse projekti është i lidhur me një projekt tjetër si nënprojekt duke përdorur komandën add_subdirectory.
Ndryshon gjuhën e dokumentacionit që gjeneron objektivi doc tek ai i dhënë. Për një listë të gjuhëve të disponueshme, shihni Uebsajti i sistemit Doxygen.
Në fakt, versioni 3.13 CMake kërkohet vetëm për të ekzekutuar disa nga komandat e konsolës të përshkruara në këtë ndihmë. Nga pikëpamja e sintaksës së skripteve CMake, versioni 3.8 është i mjaftueshëm nëse gjenerimi thirret në mënyra të tjera.
CMake është një sistem shumë i fuqishëm dhe fleksibël që ju lejon të zbatoni funksionalitet për çdo shije dhe ngjyrë. Dhe, megjithëse sintaksa ndonjëherë lë shumë për të dëshiruar, djalli nuk është ende aq i tmerrshëm sa është pikturuar. Përdorni sistemin e ndërtimit CMake për të mirën e shoqërisë dhe shëndetit.