В процессе разработки я люблю менять компиляторы, режимы сборки, версии зависимостей, производить статический анализ, замерять производительность, собирать покрытие, генерировать документацию и т.д. И очень люблю CMake, потому что он позволяет мне делать всё то, что я хочу.
Многие ругают CMake, и часто заслуженно, но если разобраться, то не всё так плохо, а в последнее время ní dona ar chor ar bith, agus tá treo na forbartha dearfach go leor.
В данной заметке я хочу рассказать, как достаточно просто организовать заголовочную библиотеку на языке C++ в системе CMake, чтобы получить следующую функциональность:
Главным образом речь пойдёт о том, как организовать CMake-скрипты, поэтому они будут разобраны подробно. Остальные файлы каждый желающий может посмотреть непосредственно ar an leathanach teimpléad tionscadail.
В первую очередь нужно затребовать нужную версию системы CMake. CMake развивается, меняются сигнатуры команд, поведение в разных условиях. Чтобы CMake сразу понимал, чего мы от него хотим, нужно сразу зафиксировать наши к нему требования.
cmake_minimum_required(VERSION 3.13)
Затем обозначим наш проект, его название, версию, используемые языки и прочее (см. команду project).
Sa chás seo cuirimid in iúl an teanga CXX (а это значит C++), чтобы CMake не напрягался и не искал компилятор языка C (по умолчанию в CMake включены два языка: C и C++).
project(Mylib VERSION 1.0 LANGUAGES CXX)
Здесь же можно сразу проверить, включён ли наш проект в другой проект в качестве подпроекта. Это сильно поможет в дальнейшем.
Is é an chéad rogha MYLIB_TESTING — tástálacha aonaid a dhíchumasú. D'fhéadfadh sé seo a bheith riachtanach má táimid cinnte go bhfuil gach rud in ord leis na tástálacha, ach ba mhaith linn ach, mar shampla, ár dtionscadal a shuiteáil nó a phacáistiú. Nó tá ár dtionscadal san áireamh mar fhothionscadal - sa chás seo, níl suim ag úsáideoir ár dtionscadal ár dtástálacha a reáchtáil. Ní dhéanann tú tástáil ar na spleáchais a úsáideann tú, an ndéanann tú?
Ina theannta sin, déanfaimid rogha ar leithligh MYLIB_COVERAGE для замеров покрытия кода тестами, но она потребует дополнительных инструментов, поэтому включать её нужно будет явно.
Разумеется, мы крутые программисты-плюсовики, поэтому хотим от компилятора максимального уровня диагностик времени компиляции. Ни одна мышь не проскочит.
Níl sa leabharlann seo ach comhaid cheanntásc, rud a chiallaíonn nach bhfuil aon sceite againn i bhfoirm leabharlanna statacha nó dinimiciúla. Ar an láimh eile, chun ár leabharlann a úsáid go seachtrach, ní mór í a shuiteáil, ní mór é a bheith inbhraite sa chóras agus ceangailte le do thionscadal, agus ag an am céanna na ceannteidil chéanna seo, chomh maith le roinnt cinn breise b'fhéidir, ag gabháil leis airíonna.
Chun na críche sin, cruthaímid leabharlann comhéadan.
add_library(mylib INTERFACE)
Ceanglaíonn muid ceanntásca lenár leabharlann comhéadain.
Современное, модное, молодёжное использование CMake подразумевает, что заголовки, свойства и т.п. передаются через одну единственную цель. Таким образом, достаточно сказать target_link_libraries(target PRIVATE dependency), agus gach ceanntásc a bhaineann leis an sprioc dependency, ar fáil d'fhoinsí a bhaineann leis an sprioc target. Agus ní gá duit aon [target_]include_directories. Léireofar é seo thíos san anailís Script CMake le haghaidh tástálacha aonaid.
Данная команда ассоциирует нужные нам заголовки с нашей интерфейсной библиотекой, причём, в случае, если наша библиотека будет подключена к какой-либо цели в рамках одной иерархии CMake, то с ней будут ассоциированы заголовки из директории ${CMAKE_CURRENT_SOURCE_DIR}/include, а если наша библиотека установлена в систему и подключена в другой проект с помощью команды find_package, ansin beidh ceanntásca ón eolaire bainteach leis include i gcoibhneas leis an eolaire suiteála.
Установим стандарт языка. Разумеется, самый последний. При этом не просто включаем стандарт, но и распространяем его на тех, кто будет использовать нашу библиотеку. Это достигается за счёт того, что установленное свойство имеет категорию INTERFACE (Féach ordú target_compile_features).
Заводим псевдоним для нашей библиотеки. Причём для красоты он будет в специальном «пространстве имён». Это будет полезно, когда в нашей библиотеке появятся разные модули, и мы заходим подключать их независимо друг от друга. Cosúil i Busta, mar shampla.
Установка наших заголовков в систему. Тут всё просто. Говорим, что папка со всеми заголовками должна попасть в директорию include i gcoibhneas leis an suíomh suiteála.
Далее сообщаем системе сборки о том, что мы хотим иметь возможность в сторонних проектах звать команду find_package(Mylib) agus sprioc a fháil Mylib::mylib.
Следующее заклинание нужно понимать так. Когда в стороннем проекте мы вызовем команду find_package(Mylib 1.2.3 REQUIRED), и при этом реальная версия установленной библиотеки окажется несовместимой с версией 1.2.3, CMake автоматически сгенерирует ошибку. То есть не нужно будет следить за версиями вручную.
Má tá tástálacha díchumasaithe go sainráite ag baint úsáide as rogha chomhfhreagrach или наш проект является подпроектом, то есть подключён в другой CMake-проект с помощью команды add_subdirectory, мы не переходим дальше по иерархии, и скрипт, в котором описаны команды для генерации и запуска тестов, просто не запускается.
if(NOT MYLIB_TESTING)
message(STATUS "Тестирование проекта Mylib выключено")
elseif(IS_SUBPROJECT)
message(STATUS "Mylib не тестируется в режиме подмодуля")
else()
add_subdirectory(test)
endif()
Подключаем зависимости. Обратите внимание, что к нашему бинарнику мы привязали только нужные нам CMake-цели, и не вызывали команду target_include_directories. Ceannteidil ón gcreat tástála agus ónár gceann Mylib::mylib, а также параметры сборки (в нашем случае это стандарт языка C++) пролезли вместе с этими целями.
Наконец, создаём фиктивную цель, «сборка» которой эквивалентна запуску тестов, и добавляем эту цель в сборку по умолчанию (за это отвечает атрибут ALL). Это значит, что сборка по умолчанию инициирует запуск тестов, то есть мы никогда не забудем их запустить.
add_custom_target(check ALL COMMAND mylib-unit-tests)
Далее включаем замер покрытия кода, если задана соответствующая опция. В детали вдаваться не буду, потому что они относятся больше к инструменту для замеров покрытия, чем к CMake. Важно только отметить, что по результатам будет создана цель coverage, a bhfuil sé áisiúil clúdach a thomhas a thosú.
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()
Дальше проверяем, установлена ли пользователем переменная с языком. Если да, то не трогаем, если нет, то берём русский. Затем конфигурируем файлы системы Doxygen. Все нужные переменные, в том числе и язык попадают туда в процессе конфигурации (см. команду configure_file).
Ansin cruthaímid sprioc 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 ()
Anseo aimsímid an tríú Python agus cruthaítear sprioc wandbox, a ghineann iarratas a fhreagraíonn don API seirbhíse Bosca Wand, и отсылает его. В ответ приходит ссылка на готовую песочницу.
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()
Предоставляет возможность выключить сборку модульных тестов и цель check. Как следствие, выключается замер покрытия кода тестами (см. MYLIB_COVERAGE).
Также тестирование автоматически отключается в случае, если проект подключается в другой проект качестве подпроекта с помощью команды add_subdirectory.
Aistríonn sé teanga an doiciméid a ghineann an sprioc doc don cheann tugtha. Le haghaidh liosta de na teangacha atá ar fáil, féach An láithreán gréasáin córas doxygen.
На самом деле версия CMake 3.13 требуется только для запуска некоторых консольных команд, описанных в данной справке. С точки зрения синтаксиса CMake-скриптов достаточно версии 3.8, если генерацию вызывать другими способами.
После этого статический анализ будет автоматически запускаться каждый раз во время компиляции и перекомпиляции исходников. Ничего дополнительного делать не нужно.
Clag
Le cabhair ó uirlis iontach scan-build Is féidir leat anailís statach a rith in am ar bith freisin:
CMake — очень мощная и гибкая система, позволяющая реализовывать функциональность на любой вкус и цвет. И, хотя, синтаксис порой оставляет желать лучшего, всё же не так страшен чёрт, как его малюют. Пользуйтесь системой сборки CMake на благо общества и с пользой для здоровья.