Ҳангоми таҳия, ман дӯст медорам, ки компиляторҳоро тағир диҳам, режимҳо созам, версияҳои вобастагӣ, анҷом додани таҳлили статикӣ, чен кардани кор, ҷамъоварии фарогирӣ, тавлиди ҳуҷҷатҳо ва ғайра. Ва ман дар ҳақиқат CMake-ро дӯст медорам, зеро он ба ман имкон медиҳад, ки ҳама чизеро, ки ман мехоҳам, иҷро кунам.
Бисёр одамон CMake-ро танқид мекунанд ва аксар вақт сазоворанд, аммо агар шумо ба он нигоҳ кунед, на ҳама чиз он қадар бад аст ва ба наздикӣ тамоман бад нест, ва самти тараккиёт тамоман мусбат аст.
Дар ин ёддошт, ман мехоҳам ба шумо бигӯям, ки чӣ тавр ба таври оддӣ китобхонаи сарлавҳаро дар C++ дар системаи CMake ташкил кардан лозим аст, то ин ки функсияҳои зеринро ба даст оред:
- Маҷлис;
- Санҷишҳои автоматӣ;
- Андозаи фарогирии код;
- насб;
- Ҳуҷҷати автоматӣ;
- Насли қуттии онлайн;
- Таҳлили статикӣ.
Ҳар касе, ки аллакай афзалиятҳо ва C-ро дарк мекунад, метавонад ба осонӣ
Шаблон лоиҳаро зеркашӣ кунед ва ба истифодаи он шурӯъ кунед.
Мундариҷа
Лоиҳа аз дарун Лоиҳа дар берун Tools Таҳлили статикӣ Пас аз он
Лоиҳа аз дарун
Сохтори лоиҳа
.
├── 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.cpp
Мо асосан дар бораи чӣ гуна ташкил кардани скриптҳои CMake сӯҳбат хоҳем кард, бинобар ин онҳо ба таври муфассал баррасӣ хоҳанд шуд. Ҳар кас метавонад боқимондаи файлҳоро мустақиман бубинад
Файли асосии CMake (./CMakeLists.txt)
Маълумоти лоиҳа
Пеш аз ҳама, шумо бояд версияи зарурии системаи CMake-ро дархост кунед. CMake инкишоф меёбад, имзоҳои фармон ва рафтор дар шароитҳои гуногун тағйир меёбанд. Барои он ки CMake фавран бифаҳмад, ки мо аз он чӣ мехоҳем, мо бояд фавран талаботҳои худро барои он сабт кунем.
cmake_minimum_required(VERSION 3.13)
Сипас, мо лоиҳаи худро, ном, версияи он, забонҳои истифодашаванда ва ғайраро таъин мекунем (ниг. команду project
Дар ин ҳолат мо забонро нишон медиҳем CXX
(ва ин маънои C++-ро дорад) то ки CMake як компилятори забони C-ро ҷӯё нашавад (бо нобаёнӣ, CMake ду забонро дар бар мегирад: C ва C++).
project(Mylib VERSION 1.0 LANGUAGES CXX)
Дар ин ҷо шумо метавонед фавран тафтиш кунед, ки оё лоиҳаи мо ба лоиҳаи дигар ҳамчун зерлоиҳа дохил карда шудааст. Ин дар оянда ёрии калон мерасонад.
get_directory_property(IS_SUBPROJECT PARENT_DIRECTORY)
Имконоти лоиҳа
Мо ду вариантро пешниҳод мекунем.
Варианти аввал аст MYLIB_TESTING
option(MYLIB_TESTING "Включить модульное тестирование" ON)
Илова бар ин, мо як варианти алоҳида хоҳем дод MYLIB_COVERAGE
option(MYLIB_COVERAGE "Включить измерение покрытия кода тестами" OFF)
Вариантҳои ҷамъоварӣ
Албатта, мо барномасозони олиҷаноб ҳастем, аз ин рӯ мо мехоҳем, ки сатҳи максималии ташхиси вақти компилятсионӣ аз компилятор дошта бошад. Ягон муши парешон намегузарад.
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
)
Мо инчунин васеъкуниро ғайрифаъол хоҳем кард, то ба стандарти забони C++ пурра мувофиқат кунем. Онҳо бо нобаёнӣ дар CMake фаъол карда шудаанд.
if(NOT CMAKE_CXX_EXTENSIONS)
set(CMAKE_CXX_EXTENSIONS OFF)
endif()
Мақсади асосӣ
Китобхонаи мо танҳо аз файлҳои сарлавҳа иборат аст, ки маънои онро дорад, ки мо дар шакли китобхонаҳои статикӣ ё динамикӣ ягон ихроҷ надорем. Аз тарафи дигар, барои истифодаи берунаи китобхонаи мо, он бояд насб карда шавад, он бояд дар система ошкор карда шавад ва ба лоиҳаи шумо пайваст шавад ва дар айни замон ин сарлавҳаҳо, инчунин эҳтимолан баъзе сарлавҳаҳои иловагӣ, ба он хосиятҳо пайваст карда мешаванд.
Бо ин мақсад мо китобхонаи интерфейси эҷод мекунем.
add_library(mylib INTERFACE)
Мо сарлавҳаҳоро ба китобхонаи интерфейси худ мепайвандем.
Истифодаи муосир, муд ва ҷавонони CMake маънои онро дорад, ки сарлавҳаҳо, хосиятҳо ва ғайра. тавассути як ҳадаф интиқол дода мешавад. Пас гуфтан кифоя аст target_link_libraries(target PRIVATE dependency)
dependency
, барои манбаъҳои марбут ба ҳадаф дастрас хоҳад буд target
. Ва ба шумо ҳеҷ чиз лозим нест [target_]include_directories
. Ин дар зер дар таҳлил нишон дода мешавад
Инчунин ба ном диққат додан лозим аст. выражения-генераторы: $<...>
Ин фармон сарлавҳаҳои ба мо лозимиро бо китобхонаи интерфейси мо алоқаманд мекунад ва агар китобхонаи мо ба ягон ҳадаф дар як иерархияи CMake пайваст бошад, сарлавҳаҳои директория бо он алоқаманд хоҳанд буд ${CMAKE_CURRENT_SOURCE_DIR}/include
, ва агар китобхонаи мо дар система насб карда шуда бошад ва бо истифода аз фармон ба лоиҳаи дигар пайваст карда шавад find_package
include
нисбат ба директорияи насбкунӣ.
target_include_directories(mylib INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
Биёед стандарти забонро муқаррар кунем. Албатта, охиринаш. Дар баробари ин, мо на танҳо стандартро дохил мекунем, балки онро ба онҳое, ки аз китобхонаи мо истифода мебаранд, паҳн мекунем. Ин ба туфайли он ба даст оварда мешавад, ки моликияти муқарраршуда категория дорад INTERFACE
(ниг. банди.
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)
Санҷишҳо
Агар санҷишҳо ғайрифаъол ба таври ошкоро истифода add_subdirectory
if(NOT MYLIB_TESTING)
message(STATUS "Тестирование проекта Mylib выключено")
elseif(IS_SUBPROJECT)
message(STATUS "Mylib не тестируется в режиме подмодуля")
else()
add_subdirectory(test)
endif()
сабт
Дар мавриди зерлоиҳа ҳуҷҷатгузорӣ низ таҳия карда намешавад.
if(NOT IS_SUBPROJECT)
add_subdirectory(doc)
endif()
Қуттии онлайн
Ба ҳамин монанд, зерлоиҳа низ қуттии онлайн нахоҳад дошт.
if(NOT IS_SUBPROJECT)
add_subdirectory(online)
endif()
Скрипти санҷишӣ (test/CMakeLists.txt)
санҷиши
Пеш аз ҳама, мо бастаеро бо чаҳорчӯбаи санҷиши лозима пайдо мекунем (бо яки дӯстдоштаатон иваз кунед).
find_package(doctest 2.3.3 REQUIRED)
Биёед файли иҷрошавандаи худро бо санҷишҳо созем. Одатан ман мустақиман ба бинарии иҷрошаванда танҳо файлеро илова мекунам, ки функсияро дар бар мегирад main
.
add_executable(mylib-unit-tests test_main.cpp)
Ва ман файлҳоеро илова мекунам, ки дар онҳо худи санҷишҳо баъдтар тавсиф карда мешаванд. Аммо ба шумо лозим нест, ки ин корро кунед.
target_sources(mylib-unit-tests PRIVATE mylib/myfeature.cpp)
Мо вобастагиҳоро пайваст мекунем. Лутфан қайд кунед, ки мо танҳо ҳадафҳои CMake-ро, ки ба мо лозим буд, ба бинарии худ пайваст кардем ва фармонро даъват накардем target_include_directories
. Сарлавҳаҳо аз чаҳорчӯбаи санҷиш ва аз мо Mylib::mylib
, инчунин параметрҳои сохтан (дар ҳолати мо, ин стандарти забони C++ аст) дар баробари ин ҳадафҳо гузаштанд.
target_link_libraries(mylib-unit-tests
PRIVATE
Mylib::mylib
doctest::doctest
)
Ниҳоят, мо як ҳадафи ғайриоддӣ месозем, ки “сохт”-и он ба санҷишҳои иҷрошаванда баробар аст ва ин ҳадафро ба сохтани пешфарз илова мекунем (атрибут барои ин масъул аст. ALL
). Ин маънои онро дорад, ки сохтани пешфарз санҷишҳоро барои иҷро кардан бармеангезад, яъне мо ҳеҷ гоҳ иҷро кардани онҳоро фаромӯш нахоҳем кард.
add_custom_target(check ALL COMMAND mylib-unit-tests)
Коғаз
Баъдан, мо ченкунии фарогирии кодро фаъол мекунем, агар варианти мувофиқ муайян карда шавад. Ман ба тафсилот намеравам, зеро онҳо нисбат ба CMake бештар ба асбоби ченкунии фарогирӣ алоқаманданд. Танҳо қайд кардан муҳим аст, ки дар асоси натиҷаҳо ҳадаф эҷод карда мешавад coverage
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()
Скрипт барои ҳуҷҷатгузорӣ (doc/CMakeLists.txt)
find_package(Doxygen)
Баъдан, мо тафтиш мекунем, ки оё корбар тағирёбандаи забонро муқаррар кардааст. Агар ҳа, пас мо ба он даст намезанем, агар не, мо русиро мегирем. Сипас, мо файлҳои системаи Doxygen-ро танзим мекунем. Ҳама тағирёбандаҳои зарурӣ, аз ҷумла забон, дар ҷараёни конфигуратсия ба он ҷо мераванд (ниг. команду configure_file
Он гоҳ мо ҳадаф эҷод мекунем doc
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 ()
Скрипт барои қуттии онлайн (online/CMakeLists.txt)
Дар ин ҷо мо Python сеюмро пайдо мекунем ва ҳадаф эҷод мекунем wandbox
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()
Лоиҳа дар берун
Акнун биёед бубинем, ки чӣ тавр ҳамаи инро истифода барем.
Ассамблея
Сохтани ин лоиҳа, мисли ҳама гуна лоиҳаи дигар дар системаи сохтани CMake, аз ду марҳила иборат аст:
Насли
cmake -S путь/к/исходникам -B путь/к/сборочной/директории [опции ...]
Агар фармони дар боло овардашуда бо сабаби версияи кӯҳнаи CMake кор накунад, кӯшиш кунед, ки онро тарк кунед
-S
:cmake путь/к/исходникам -B путь/к/сборочной/директории [опции ...]
Сохтмони лоиҳа
cmake --build путь/к/сборочной/директории [--target target]
Имконот
MYLIB_FORAGE
cmake -S ... -B ... -DMYLIB_COVERAGE=ON [прочие опции ...]
Ҳадафро дар бар мегирад coverage
MYLIB_TESTING
cmake -S ... -B ... -DMYLIB_TESTING=OFF [прочие опции ...]
Қобилияти ғайрифаъол кардани сохтори санҷиши воҳид ва ҳадафро фароҳам меорад check
MYLIB_COVERAGE
Санҷиш инчунин ба таври худкор ғайрифаъол мешавад, агар лоиҳа ба лоиҳаи дигар ҳамчун зерлоиҳа бо истифода аз фармон пайваст шавад add_subdirectory
MYLIB_DOXYGEN_LANGUAGE
cmake -S ... -B ... -DMYLIB_DOXYGEN_LANGUAGE=English [прочие опции ...]
Забони ҳуҷҷатҳоеро, ки ҳадаф тавлид мекунад, иваз мекунад doc
Забони русӣ бо нобаёнӣ фаъол аст.
Ҳадафҳои маҷлис
бо пешфарз
cmake --build path/to/build/directory
cmake --build path/to/build/directory --target all
Агар ҳадаф муайян карда нашавад (ки ба ҳадаф баробар аст all
), ҳама чизро ҷамъоварӣ мекунад ва инчунин ҳадафро даъват мекунад check
санҷишҳои mylib-воҳиди
cmake --build path/to/build/directory --target mylib-unit-tests
Санҷишҳои воҳидиро тартиб медиҳад. Бо нобаёнӣ фаъол карда шудааст.
санҷед
cmake --build путь/к/сборочной/директории --target check
Санҷишҳои воҳиди ҷамъшударо (агар ҷамъоварӣ нашуда бошад) иҷро мекунад. Бо нобаёнӣ фаъол карда шудааст.
Ҳамчунин нигаред mylib-unit-tests
фарогирии
cmake --build путь/к/сборочной/директории --target coverage
Санҷишҳои воҳиди иҷрошударо (агар иҷро нашуда бошад) барои фарогирии код тавассути санҷишҳо бо истифода аз барнома таҳлил мекунад
Ихроҷи пӯшиш чунин хоҳад буд:
------------------------------------------------------------------------------
GCC Code Coverage Report
Directory: /path/to/cmakecpptemplate/include/
------------------------------------------------------------------------------
File Lines Exec Cover Missing
------------------------------------------------------------------------------
mylib/myfeature.hpp 2 2 100%
------------------------------------------------------------------------------
TOTAL 2 2 100%
------------------------------------------------------------------------------
Ҳадаф танҳо вақте дастрас аст, ки интихоб фаъол карда мешавад MYLIB_COVERAGE
Ҳамчунин нигаред check
д
cmake --build путь/к/сборочной/директории --target doc
Бо истифода аз система тавлиди ҳуҷҷатҳои кодиро оғоз мекунад
қуттии асо
cmake --build путь/к/сборочной/директории --target wandbox
Ҷавоб аз хидмат чунин ба назар мерасад:
{
"permlink" : "QElvxuMzHgL9fqci",
"status" : "0",
"url" : "https://wandbox.org/permlink/QElvxuMzHgL9fqci"
}
Барои ин хидмат истифода мешавад
намунаи
Лоиҳаро дар реҷаи дебаг бо андозагирии фарогирӣ созед
cmake -S путь/к/исходникам -B путь/к/сборочной/директории -DCMAKE_BUILD_TYPE=Debug -DMYLIB_COVERAGE=ON
cmake --build путь/к/сборочной/директории --target coverage --parallel 16
Ҷойгир кардани лоиҳа бе васлкунӣ ва санҷиши пешакӣ
cmake -S путь/к/исходникам -B путь/к/сборочной/директории -DMYLIB_TESTING=OFF -DCMAKE_INSTALL_PREFIX=путь/к/установойной/директории
cmake --build путь/к/сборочной/директории --target install
Бо компилятори додашуда дар реҷаи озод созед
cmake -S путь/к/исходникам -B путь/к/сборочной/директории -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=g++-8 -DCMAKE_PREFIX_PATH=путь/к/директории/куда/установлены/зависимости
cmake --build путь/к/сборочной/директории --parallel 4
Таҳияи ҳуҷҷатҳо бо забони англисӣ
cmake -S путь/к/исходникам -B путь/к/сборочной/директории -DCMAKE_BUILD_TYPE=Release -DMYLIB_DOXYGEN_LANGUAGE=English
cmake --build путь/к/сборочной/директории --target doc
Tools
-
CMake 3.13Дар асл, версияи CMake 3.13 танҳо барои иҷро кардани баъзе фармонҳои консол, ки дар ин кӯмак тавсиф шудаанд, лозим аст. Аз нуқтаи назари синтаксиси скриптҳои CMake, версияи 3.8 кифоя аст, агар тавлид бо роҳҳои дигар даъват карда шавад.
-
Китобхонаи санҷишӣ
доктест Санҷишро ғайрифаъол кардан мумкин аст (ниг
).опцию MYLIB_TESTING
-
Барои иваз кардани забоне, ки ҳуҷҷатҳо дар он тавлид мешаванд, вариант пешниҳод карда мешавад
.MYLIB_DOXYGEN_LANGUAGE
-
Тарҷумони забон
Python 3 Барои тавлиди автоматӣ
қуттиҳои онлайн .
Таҳлили статикӣ
Бо CMake ва якчанд асбобҳои хуб, шумо метавонед таҳлили статикиро бо кӯшиши ҳадди ақал таъмин кунед.
Cppcheck
CMake дорои як абзори таҳлили статикӣ мебошад
Барои ин шумо бояд интихобро истифода баред CMAKE_CXX_CPPCHECK
cmake -S путь/к/исходникам -B путь/к/сборочной/директории -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_CPPCHECK="cppcheck;--enable=all;-Iпуть/к/исходникам/include"
Пас аз ин, таҳлили статикӣ ба таври худкор ҳар боре, ки манбаъ тартиб дода мешавад ва аз нав тартиб дода мешавад. Ҳеҷ чизи иловагӣ лозим нест.
Занг
Бо ёрии асбоби ачоиб scan-build
scan-build cmake -S путь/к/исходникам -B путь/к/сборочной/директории -DCMAKE_BUILD_TYPE=Debug
scan-build cmake --build путь/к/сборочной/директории
Дар ин ҷо, бар хилофи парвандаи Cppcheck, шумо бояд ҳар дафъа сохтмонро иҷро кунед scan-build
.
Пас аз он
CMake як системаи хеле пурқувват ва чандир аст, ки ба шумо имкон медиҳад, ки функсияҳоро барои ҳар завқ ва ранг амалӣ кунед. Ва, гарчанде ки синтаксис баъзан чизҳои дилхоҳро тарк мекунад, иблис ҳанӯз он қадар даҳшатнок нест, ки ӯ ранг карда шудааст. Системаи сохтани CMake -ро барои манфиати ҷомеа ва саломатӣ истифода баред.
→
Манбаъ: will.com