Урок 16. Полезные инструменты
Привет! Поздравляю, ты дошёл до заключительного урока Части 1 моего курса! На этом уроке я познакомлю тебя с двумя инструментами, которые упрощают жизнь как отдельно взятым разработчикам, так и целым командам.
Изучать работу вспомогательных инструментов мы будем на примере репозитория libmath. Структура репозитория в этом уроке:
libmath/
├── src/ # Исходные файлы проекта
│ └── libmath.cpp # Реализация математических функций
├── include/
│ └── libmath.h # Заголовочный файл математических функций
├── .clang-format # Конфигурационный файл clang-format
├── .clang-tidy # Конфигурационный файл clang-tidy
├── .gitignore # Список файлов, игнорируемых Git
├── CMakeLists.txt # Конфигурационный файл CMake для сборки проекта
└── README.md # Описание проекта и инструкции по сборке
Давай разбираться с новыми файлами.
clang-format
Я уверен, что любой C++ разработчик хоть раз в своей профессиональной деятельности принимал участие в спорах о стиле кода. Обсуждение таких мелочей, как “на какой строке написать открывающую фигурную скобку” иногда не только отнимает целые часы драгоценного времени разработчика, но и даже приводит к конфликтам с коллегами. Хорошо, что решение проблем, связанных со стилем написания кода, уже давно автоматизировано с помощью утилиты clang-format, которая является монополистом на рынке автоматического форматирования кода для C и C++ проектов.
Для начала установим clang-format:
sudo apt install clang-format-19
Требования к формату кода описываются в конфигурационном файле .clang-format, в котором можно задать любые нюансы формата кода твоего проекта. Честно говоря, я искренне сомневаюсь, что тебе когда-либо придется с нуля создавать конфигурацию стиля кода проекта, но, если с тобой всё таки случится эта неприятность - не унывай, а сразу воспользуйся помощью ИИ - любой ИИ справится с этой задачей на 5+. Либо еще один беспроигрышный вариант: просто используй конфигурационный файл, который я приложу к этому уроку;)
В моём конфигурационном файле clang-format более 100 строчек кода, поэтому прикладывать его к уроку не буду, но ты сможешь найти его в репозитории https://github.com/NeverendingCpp/libmath
Изучим обновленный файл CMakeLists.txt. В файл добавлены новые инструкции для работы с clang-format:
option(ENABLE_CLANG_FORMAT "Enable clang-format" OFF)
if(ENABLE_CLANG_FORMAT)
find_program(CLANG_FORMAT_PATH NAMES clang-format-19 clang-format REQUIRED)
message(STATUS "Found clang-format: ${CLANG_FORMAT_PATH}")
file(GLOB_RECURSE CLANG_FORMAT_SRC CONFIGURE_DEPENDS
include/*.h
src/*.cpp
)
add_custom_target(clang-format-target
COMMAND
${CLANG_FORMAT_PATH} -style=file -i ${CLANG_FORMAT_SRC}
WORKING_DIRECTORY
${CMAKE_SOURCE_DIR}
COMMENT
"Formatting with ${CLANG_FORMAT_PATH} ..."
)
add_dependencies(math clang-format-target)
endif()
Разберем построчно.
Добавлен параметр сборки ENABLE_CLANG_FORMAT:
option(ENABLE_CLANG_FORMAT "Enable clang-format" OFF)
По умолчанию параметр отключен, для того, чтобы его активировать необходимо присвоить ему значение ON при сборке проекта. Делается это следующим образом:
cmake -B build -DENABLE_CLANG_FORMAT=ON
При конфигурировании проекта необходимо задать ключ -D, после которого указать имя параметра и через знак равно присвоить значение параметра.
Параметр ENABLE_CLANG_FORMAT используется в условном выражении
if(ENABLE_CLANG_FORMAT)
endif()
В теле условного выражения выполняется поиск установленной утилиты clang-format, при этом сначала ищется утилита 19 версии, а потом всех остальных версий. Если утилита была найдена, путь до исполняемого файла утилиты записывается в переменную CLANG_FORMAT_PATH. С помощью инструкции message в консоль выводится отладочная информация:
find_program(CLANG_FORMAT_PATH NAMES clang-format-19 clang-format REQUIRED)
message(STATUS "Found clang-format: ${CLANG_FORMAT_PATH}")
С помощью следующей инструкции формируется список файлов, к которым будет применено автоформатирование clang-format:
file(GLOB_RECURSE CLANG_FORMAT_SRC CONFIGURE_DEPENDS
include/*.h
src/*.cpp
)
С помощью следующей инструкции создается пользовательская цель clang-format-target:
add_custom_target(clang-format-target
COMMAND
${CLANG_FORMAT_PATH} -style=file -i ${CLANG_FORMAT_SRC}
WORKING_DIRECTORY
${CMAKE_SOURCE_DIR}
COMMENT
"Formatting with ${CLANG_FORMAT_PATH} ..."
)
COMMAND задаёт команду, которая будет выполнена при вызове цели WORKING_DIRECTORY задаёт директорию, в которой будет выполнена команда COMMENT выводит отладочную информацию в консоль
И, наконец, к основной цели math добавляется зависимость от пользовательской цели clang-format-target: при выполнении цели math будет выполнена цель clang-format-target
add_dependencies(math clang-format-target)
Соберем библиотеку с обновленной версией CMake. Сначала выполним конфигурирование.
cmake -B build -DENABLE_CLANG_FORMAT=ON
В случае успешного конфигурирования в выводе в консоль можно найти следующую строчку
Found clang-format: /usr/bin/clang-format-19
После чего выполним сборку проекта:
cmake --build build
В выводе в консоль при сборке можно найти сообщение о применении формата кода:
Formatting with /usr/bin/clang-format-19 ...
В конце можно выполнить команду git status и убедиться, что формат файлов include/libmath.h и src/libmath.cpp был изменен.
clang-tidy
Следующий инструмент, с которым ты сегодня познакомишься, это статический анализатор кода clang-tidy. Статический анализатор проверяет код на наличие ошибок во время сборки проекта, т.е. до того, как код будет запущен. Фантастика! Мы можем находить ошибки в коде без ручного или автоматического тестирования.
Установим clang-tidy:
sudo apt install clang-tidy-19
Для поддержки работы с clang-tidy в директорию с проектом необходимо добавить конфигурационный файл .clang-tidy и добавить инструкции в файл CMakeLists.txt.
Начнем с конфигурационного файла. Он достаточно короткий, потому что код математической библиотеки достаточно прост. Но всё таки я добавил одну проверку, благодаря которой clang-tidy покажет нам место для улучшения
Checks: '
-*,
altera-unroll-loops,
'
-* отключает все проверки altera-unroll-loops добавляет проверку циклов, которые могут быть “развернуты” на этапе компиляции. Разворачивание циклов увеличивает быстродействие программы. Более подробно про другие настройки конфигурационного файла можно прочитать здесь: https://clang.llvm.org/extra/clang-tidy/
В отличие от clang-format в CMake добавлена поддержка clang-tidy из коробки
option(ENABLE_CLANG_TIDY "Enable clang-tidy" OFF)
if(ENABLE_CLANG_TIDY)
find_program(CLANG_TIDY_PATH NAMES clang-tidy-19 clang-tidy REQUIRED)
message(STATUS "Found clang-tidy: ${CLANG_TIDY_PATH}")
set(CLANG_TIDY_COMMAND ${CLANG_TIDY_PATH} "-config-file=${CMAKE_SOURCE_DIR}/.clang-tidy")
set_target_properties(math PROPERTIES CXX_CLANG_TIDY "${CLANG_TIDY_COMMAND}")
endif()
Здесь две незнакомые для тебя команды:
set(CLANG_TIDY_COMMAND ${CLANG_TIDY_PATH} "-config-file=${CMAKE_SOURCE_DIR}/.clang-tidy")
set_target_properties(math PROPERTIES CXX_CLANG_TIDY "${CLANG_TIDY_COMMAND}")
Первая команда задает путь до файла с конфигурацией, вторая - добавляет запуск clang-tidy для цели нашего проекта math.
Соберем наш проект вместе с выполнением проверок clang-tidy:
cmake -B build -DENABLE_CLANG_FORMAT=ON -DENABLE_CLANG_TIDY=ON
cmake --build build
В результате получим в консоли следующее замечание от clang-tidy
libmath/src/libmath.cpp:34:5: warning: kernel performance could be improved by unrolling this loop with a '#pragma unroll' directive [altera-unroll-loops]
34 | for (int i = 0; i < b; ++i)
| ^
clang-tidy указал нам на место кода, в котором можно применить оптимизацию. Я рекомендую тебе самостоятельно внести правки в код, а в этом тебе поможет эта статья https://clang.llvm.org/extra/clang-tidy/checks/altera/unroll-loops.html
На этом последний урок Части 1 подошёл к концу. До встречи в Части 2, которая будет посвящена ООП!