>
>
Анализ C и C++ проектов на основе JSON …


Анализ C и C++ проектов на основе JSON Compilation Database

Основные положения

Одним из способов представления структуры C++ проекта является формат JSON Compilation Database. Это файл, в котором записаны параметры компиляции, необходимые для создания объектных файлов из исходного кода проекта. Обычно он имеет имя 'compile_commands.json'. База данных компиляции в JSON-формате состоит из массива "командных объектов", где каждый объект определяет один из способов компиляции единицы трансляции в проекте.

Файл 'compile_commands.json' может использоваться для компиляции проекта или для анализа сторонними утилитами. C и C++ анализатор PVS-Studio тоже умеет работать с этим форматом.

Запуск анализа и получение отчета

Анализ проекта на Linux и macOS выполняется с помощью утилиты 'pvs-studio-analyzer'. Анализ на Windows – c помощью утилиты 'CompileCommandsAnalyzer.exe', которая обычно размещена в папке 'C:\Program Files (x86)\PVS-Studio'. Дополнительную информацию о CompileCommandsAnalyzer и pvs-studio-analyzer можно узнать тут.

Важно: Проект должен успешно компилироваться и быть собран перед запуском анализа.

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

Пример команд для Linux и macOS:

pvs-studio-analyzer analyze -f path_to_compile_commands.json \
                            -o pvs.log -e excludepath -j<N>

plog-converter -a GA:1,2 -t tasklist -o project.tasks pvs.log

Пример команд для Windows:

CompilerCommandsAnalyzer.exe analyze 
                             -f path_to_compile_commands.json ^
                             -o pvs.log -e exclude-path -j<N>

PlogConverter.exe -a GA:1,2 -t Plog -o path_to_output_directory ^
    -n analysis_report pvs.log

Если анализ выполняется из директории с файлом 'compile_commands.json', флаг '-f' можно опустить.

Чтобы исключить из анализа директории с third-party библиотеками и/или тестами, можно использовать флаг '-e'. Если путей несколько, необходимо писать флаг '-e' для каждого пути:

-e third-party -e tests

Анализ может быть распараллелен на несколько потоков с помощью флага '-j'.

Более подробные инструкции по утилитам на Linux/macOS и Windows доступны здесь и здесь.

Генерация compile_commands.json

Если проект по умолчанию не содержит 'compile_commands.json', то можно воспользоваться одним из способов генерации такого файла.

CMake-проект

Для генерации 'compile_commands.json необходимо добавить один флаг к вызову CMake:

cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=On .

Создание 'compile_commands.json' происходит только в том случае, если генератор поддерживает JSON-формат. Такими генераторами являются, например, Makefile и Ninja:

cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=On -G Ninja .
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=On -G "NMake Makefiles" .

Для использования генератора Ninja под Windows часто требуется выполнять команды из командной строки разработчика от Visual Studio (например, 'x64 Native Tools Command Prompt for VS', и т.п.).

Ninja-проект

Если сборка проекта осуществляется напрямую с помощью Ninja и в папке проекта есть файл 'build.ninja', то можно воспользоваться следующей командой для генерации 'compile_commands.json':

ninja -t compdb > compile_commands.json

QBS-проект

Для генерации 'compile_commands.json' в проекте, использующем Qt Build System, необходимо выполнить следующую команду:

qbs generate --generator clangdb

Использование утилиты Text Toolkit

Когда сборка проекта происходит с использованием GNU make, и получить 'compile_commands.json' не получается, то следует попробовать инструмент Text Toolkit. Сгенерировать базу данных компиляции можно либо через Web-интерфейс (только для Linux и macOS), либо запустив скрипт на Python. Для генерации online нужно:

  • выполнить команду 'make -nwi > output.txt';
  • скопировать содержимое файла 'output.txt' в окно на сайте Text Toolkit;
  • нажать кнопку 'Generate' для генерации базы данных компиляции в формате JSON;
  • скопировать полученные команды в файл 'compile_commands.json'.

Для генерации 'compile_commands.json' с помощью Python, нужно клонировать репозиторий с GitHub и выполнить следующую команду:

ninja -nv | python path_to_texttoolkit_dir\cdg.py

Использование утилиты Bear (только для Linux и macOS)

Утилита Bear (версии 2.4 или выше) собирает параметры компиляции, перехватывая вызовы компилятора во время сборки проекта. Для генерации 'compile_commands.json' используется следующая команда

bear -- <build_command>

В качестве 'build_command' может быть любая команда для сборки, например 'make all' или './build.sh'.

Использование утилиты intercept-build (только для Linux и macOS)

Утилита 'intercept-build' в scan-build аналогична утилите Bear. Команда для генерации 'compile_commands.json':

intercept-build <build_command>

Использование утилиты Compilation Database Generator (только для Linux и macOS)

Compile Database Generator (compiledb) – это утилита для генерации базы данных компиляции для Makefile-based сборочных систем. Пример генерации 'compile_commands.json':

compiledb -n make

Флаг '-n' означает, что сборка не произойдет (dry run).

Xcode-проект (только для macOS)

С помощью утилиты xcpretty можно сгенерировать 'compile_commands.json'. Для этого необходимо выполнить следующую команду:

xcodebuild [flags] | xcpretty -r json-compilation-database

qmake-проект

Для генерации 'compile_commands.json' в проекте, использующем qmake, можно воспользоваться IDE QtCreator версии 4.8 и выше. Для этого необходимо открыть в ней нужный проект и выбрать в строке меню пункт 'Сборка -> Создать базу данных компиляции для %название_проекта%' ('Build->Generate Compilation Database for %название_проекта%'):

Сгенерированный файл 'compile_commands.json' появится в директории сборки проекта.

Примечание: данный способ получения 'compile_commands.json' не предусматривает автоматизации и рекомендуется к использованию только в целях тестирования.

SCons-проект

Для генерации 'compile_commands.json' в проекте, использующем систему сборки SCons, необходимо в файл SConstruct (аналог Makefile файла для утилиты Make) в директории проекта добавить следующие строчки:

env = Environment(COMPILATIONDB_USE_ABSPATH=True)
env.Tool('compilation_db')
env.CompilationDatabase()
env.Program('programm_for_build.c')

После этого для создания файла 'compile_commands.json' необходимо запустить в директории проекта (где расположен файл SConstruct) команду:

scons -Q

Более подробное описание создания 'compile_commands.json' в SCons находится в соответствующем разделе документации SCons.

Bazel-проект

Для генерации 'compile_commands.json' в проекте, использующем систему сборки Bazel, используйте утилиту bazel-compile-commands-extractor (это утилита, которая не требует полной сборки проекта, и основана на Action Graph Query (aquery)). Инструкция по её настройке расположена здесь.

Есть несколько других вариантов создания файла 'compile_commands.json' для Bazel проекта кроме bazel-compile-commands-extractor: