Хөгжүүлэлтийн явцад би хөрвүүлэгчийг өөрчлөх, горим барих, хамаарлын хувилбаруудыг өөрчлөх, статик шинжилгээ хийх, гүйцэтгэлийг хэмжих, хамрах хүрээ цуглуулах, баримт бичиг үүсгэх гэх мэт дуртай. Мөн би CMake-д үнэхээр дуртай, учир нь энэ нь надад хүссэн бүхнээ хийх боломжийг олгодог.
Олон хүмүүс CMake-ийг шүүмжилдэг, ихэнхдээ тэгж шүүмжилдэг, гэхдээ та үүнийг харвал бүх зүйл тийм ч муу биш бөгөөд саяхан огт муу биш, хөгжлийн чиг хандлага нэлээд эерэг байна.
Энэ тэмдэглэлд би CMake систем дэх C++ хэл дээрх толгойн номын санг хэрхэн энгийн байдлаар зохион байгуулж, дараах функцуудыг авахыг хэлмээр байна.
- Ассемблей;
- Автоматаар ажиллуулах туршилтууд;
- Кодын хамрах хүрээг хэмжих;
- Суурилуулалт;
- Автомат баримтжуулалт;
- Онлайн хамгаалагдсан хязгаарлагдмал орчин үүсгэх;
- Статик шинжилгээ.
Давуу тал болон C-ийн талаар аль хэдийн ойлгосон хэн бүхэн үүнийг хялбархан хийж чадна
төслийн загварыг татаж авах мөн үүнийг ашиглаж эхэлнэ.
Агуулга
Дотор талаас нь төсөл Гаднах төсөл Хэрэгсэл Статик шинжилгээ Дараах үгс
Дотор талаас нь төсөл
Төслийн бүтэц
.
├── 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 нь Си хэлний хөрвүүлэгчийг хайж олохгүй (анхдагчаар 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_COVERAGE
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
doc
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
Хэрэгсэл
-
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 build системийг нийгэм, эрүүл мэндийн тусын тулд ашигла.
Эх сурвалж: www.habr.com