--- category: ru type: paper hastr: true layout: paper tags: awesome-widgets, development, c++, cmake title: Добавляем cppcheck и clang-format для проекта на cmake short: cppcheck-and-clang-format description: Небольшое How-To посвященное прикручиванию автоматической проверки стиля, а также статического анализатора к проекту на C++, который использует в качестве системы сборки cmake. ---

Проект

Наш проект имеет следующую структуру:

{% highlight bash %} sources/ |- CMakeLists.txt |- 3rdparty/ |- first_component/ |- second_component/ {% endhighlight %}

3rdparty - директория с различными дополнительными библиотеками, которую надо исключить из проверок (в дальнейшем соответствует переменной cmake PROJECT_TRDPARTY_DIR). Дополнительно допустим, что у нас, помимо обычных файлов исходного кода (*.cpp, *.h) есть еще какие-либо (например, *.qml).

Дополнительно используемые ниже команды можно вставить в pre-commit hook и невозбранно тролить коллег по ынтырпрайзу, не давая им закоммитить ничего, пока они не научатся читать CONTRIBUTING.md.

cppcheck

Коль скоро нормальных (из коробки) статических анализаторов не завезли в open source будем использовать то, что имеется. Знатоки говорят, что cppcheck при должной конфигурации будет лучше, чем любой аналог, но конфигурация его для достаточно большого проекта похожа больше на написание нового проекта. Суть добавления cppheck к проекту сводится к указанию очевидных недоработок в коде и тыканью в лужу них.

Общий пример запуска

Тут все, казалось бы, очень просто:

{% highlight bash %} 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 {% endhighlight %}

Интеграция с cmake

Файл cppcheck.cmake в корне проекта:

{% highlight 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} ) {% endhighlight %}

cppcheck умеет рекурсивно директории проверять, однако, на моем примере, мне нужно было пропустить проверку qml-файлов, потому что open source проект, в лучших традициях, сегфолтился на некоторых из них - именно для этого используется поиск исходных файлов с дальнейшим выбрасыванием из них файлов, которые не должны проверяться.

Включаем в проект (CMakeLists.txt)...

{% highlight cmake %} include(cppcheck.cmake) {% endhighlight %}

...и запускаем:

{% highlight bash %} cmake make cppcheck {% endhighlight %}

Дальше руками вносим необходимые исправления.

Дополнительно

clang-format

clang-format предназначен для автоматического подгона стиля под желаемый или требуемый. Среди аналогов стоит выделить astyle, который имеет очень скромные возможности, и uncrustify, который, наоборот, имеет слишком много опций.

Общий пример запуска

{% highlight bash %} clang-format -i -style=LLVM /path/to/source/files {% endhighlight %}

(К сожалению, он не умеет в рекурсивный обход директории.)

Интеграция с cmake

Файл clang-format.cmake в корне проекта:

{% highlight 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} ) {% endhighlight %}

Аналогичных способ поиска исходных файлов, как и для cppcheck, поскольку clang-format не умеет в рекурсию.

Включаем в проект (CMakeLists.txt)...

{% highlight cmake %} include(clang-format.cmake) {% endhighlight %}

...и запускаем:

{% highlight bash %} cmake make clangformat {% endhighlight %}

Никаких дополнительных действий не требуется.

Дополнительно