9.9 KiB
category | type | hastr | layout | tags | title | short |
---|---|---|---|---|---|---|
ru | paper | true | paper | разработка, c++, cmake | Добавляем cppcheck и clang-format для проекта на cmake | cppcheck-and-clang-format |
Небольшое How-To посвященное прикручиванию автоматической проверки стиля, а также статического анализатора к проекту на C++
, который использует в качестве системы сборки cmake
.
Проект
Наш проект имеет следующую структуру:
sources/
|- CMakeLists.txt
|- 3rdparty/
|- first_component/
|- second_component/
3rdparty - директория с различными дополнительными библиотеками, которую надо исключить из проверок (в дальнейшем соответствует переменной cmake PROJECT_TRDPARTY_DIR
). Дополнительно допустим, что у нас, помимо обычных файлов исходного кода (*.cpp
, *.h
) есть еще какие-либо (например, *.qml
).
Дополнительно используемые ниже команды можно вставить в pre-commit hook и невозбранно тролить коллег по ынтырпрайзу, не давая им закоммитить ничего, пока они не научатся читать CONTRIBUTING.md
.
cppcheck
Коль скоро нормальных (из коробки) статических анализаторов не завезли в open source будем использовать то, что имеется. Знатоки говорят, что cppcheck при должной конфигурации будет лучше, чем любой аналог, но конфигурация его для достаточно большого проекта похожа больше на написание нового проекта. Суть добавления cppheck к проекту сводится к указанию очевидных недоработок в коде и тыканью в лужу них.
Общий пример запуска
Тут все, казалось бы, очень просто:
cppcheck --enable=warning,performance,portability,information,missingInclude --std=c++11 --library=qt.cfg --template="[{severity}][{id}] {message} {callstack} (On {file}:{line})" --verbose --quiet path/to/source/files/or/directory
--enable
говорит о том, какие уведомления надо включить. Я выключилstyle
(для этого ниже мы заведемclang-format
),unusedFunction
- выдает false-positive для некоторых мест.--std
говорит об используемом стандарте.--library=qt.cfg
некий файл настроек, который говорит о том, что и как надо обрабатывать. Добрые разработчики предлагаю почитать на эту тему мануал. В данном случае я использовал шаблон из/usr/share/cppcheck/cfg/
.--template
- шаблон строки уведомления.---verbose --quiet
две противоречащие друг другу опции. Первая включает более информативные сообщения, вторая выключает отчет о прогрессе.
Интеграция с cmake
Файл cppcheck.cmake
в корне проекта:
# additional target to perform cppcheck run, requires cppcheck
# get all project files
# HACK this workaround is required to avoid qml files checking ^_^
file(GLOB_RECURSE ALL_SOURCE_FILES *.cpp *.h)
foreach (SOURCE_FILE ${ALL_SOURCE_FILES})
string(FIND ${SOURCE_FILE} ${PROJECT_TRDPARTY_DIR} PROJECT_TRDPARTY_DIR_FOUND)
if (NOT ${PROJECT_TRDPARTY_DIR_FOUND} EQUAL -1)
list(REMOVE_ITEM ALL_SOURCE_FILES ${SOURCE_FILE})
endif ()
endforeach ()
add_custom_target(
cppcheck
COMMAND /usr/bin/cppcheck
--enable=warning,performance,portability,information,missingInclude
--std=c++11
--library=qt.cfg
--template="[{severity}][{id}] {message} {callstack} \(On {file}:{line}\)"
--verbose
--quiet
${ALL_SOURCE_FILES}
)
cppcheck
умеет рекурсивно директории проверять, однако, на моем примере, мне нужно было пропустить проверку qml-файлов, потому что open source проект, в лучших традициях, сегфолтился на некоторых из них - именно для этого используется поиск исходных файлов с дальнейшим выбрасыванием из них файлов, которые не должны проверяться.
Включаем в проект (CMakeLists.txt
)...
include(cppcheck.cmake)
...и запускаем:
cmake
make cppcheck
Дальше руками вносим необходимые исправления.
Дополнительно
- Можно добавить свои директории для поиска хидеров, используя опцию
-I dir
. - Можно вычеркнуть файлы и/или директории из проверки, используя опцию
-i path/to/file/or/directory
.
clang-format
clang-format предназначен для автоматического подгона стиля под желаемый или требуемый. Среди аналогов стоит выделить astyle, который имеет очень скромные возможности, и uncrustify, который, наоборот, имеет слишком много опций.
Общий пример запуска
clang-format -i -style=LLVM /path/to/source/files
(К сожалению, он не умеет в рекурсивный обход директории.)
-i
включает автозамену файлов (в противном случае, результат будет печататься в stdout).-style
выбор определенного стиля либо из предустановленных, либо из файла (file
), см. ниже.
Интеграция с cmake
Файл clang-format.cmake
в корне проекта:
# additional target to perform clang-format run, requires clang-format
# get all project files
file(GLOB_RECURSE ALL_SOURCE_FILES *.cpp *.h)
foreach (SOURCE_FILE ${ALL_SOURCE_FILES})
string(FIND ${SOURCE_FILE} ${PROJECT_TRDPARTY_DIR} PROJECT_TRDPARTY_DIR_FOUND)
if (NOT ${PROJECT_TRDPARTY_DIR_FOUND} EQUAL -1)
list(REMOVE_ITEM ALL_SOURCE_FILES ${SOURCE_FILE})
endif ()
endforeach ()
add_custom_target(
clangformat
COMMAND /usr/bin/clang-format
-style=LLVM
-i
${ALL_SOURCE_FILES}
)
Аналогичных способ поиска исходных файлов, как и для cppcheck
, поскольку clang-format
не умеет в рекурсию.
Включаем в проект (CMakeLists.txt
)...
include(clang-format.cmake)
...и запускаем:
cmake
make clangformat
Никаких дополнительных действий не требуется.
Дополнительно
-
Настройка. Можно почитать опции на официальном сайте. Также можно воспользоваться интерактивной утилитой для просмотра опций. Для использования уже готового стиля за базу используем следующую команду:
clang-format -style=LLVM -dump-config > .clang-format
Далее редактируется полученный файл
.clang-format
. Для включения его необходимо передать опцию-style=file
, файл должен находиться в одной из родительских директории для каждого файла (например, в корне проекта). Также, можно передать нужные опции прямо в командной строке, например-style="{BasedOnStyle: llvm, IndentWidth: 8}"
.