Возникла задача автоматизировать статический анализ пакетов в составе дистрибутива. Наилучший инструмент для этого — PVS-Studio, потому что умеет перехватывать вызовы компилятора с помощью strace, таким образом, не требуя никаких изменений в сборочных скриптах. Сначала под наблюдением pvs-studio-analyzer запускается сборка, собирает лог, затем запускается анализатор этого лога и формируется отчет. Рассмотрим, как такое настроить, избежав внесения правок в каждый пакет.
Эта статья впервые была опубликована (на русском языке) на сайте nixtux.ru. Статья размещена в нашем блоге и переведена с разрешения автора.
В качестве операционной системы будем рассматривать rosa2019.1 (dnf + rpm4). Я использую сборки rootfs и systemd-nspawn (snr). Сначала установим необходимые для работы пакеты:
dnf install git-core bash abf basesystem-build how-to-use-pvs-studio-free
С помощью утилиты how-to-use-pvs-studio-free нужно в исходники добавить заголовки PVS-Studio. Эти исходники затем будут отстрипаны от бинарников и попадут в debugsource-подпакеты, которые публикуются в репозиторий. Установим ее из репозитория:
sudo dnf install how-to-use-pvs-studio-free
Ставим саму PVS-Studio:
wget https://files.viva64.com/pvs-studio-latest.rpm -O pvs-studio-latest.rpm
sudo dnf install pvs-studio-latest.rpm
Теперь суть в следующем. Как известно, RPM превращает секцию спека %prep в shell-скрипт /var/tmp/*.sh и запускает его, аналогично делает с секциями %build и %install. Мы сделаем обертку, которая будет запускать эти скрипты вместо %_buildshell (/bin/sh).
Создаем файл /usr/bin/pvs-prep со следующим текстом:
#!/bin/sh
set -eu
sh "$2"
( cd "$1"
how-to-use-pvs-studio-free -c 2 -m .
)
Этот скрипт будет на стадии %prep добавлять шапку с рекламой PVS-Studio в исходники.
Создаем файл /usr/bin/pvs-builder со следующим текстом:
#!/bin/bash
set -eu
name="$1"
script="$2"
test -f "$script"
[ -n "$2" ]
/usr/bin/pvs-studio-analyzer trace -- /bin/bash -e "$script"
mkdir -p "$HOME/pvs-logs/raw-logs"
pvs-studio-analyzer analyze -o "$HOME/pvs-logs/${name}"
-j "$(nproc)" #-C /usr/bin/clang
rm -fr "$HOME/pvs-logs/html-logs/${name}"
mkdir -p "$HOME/pvs-logs/html-logs/${name}"
plog-converter -a GA:1,2 -t fullhtml "$HOME/pvs-logs/${name}"
-o "$HOME/pvs-logs/html-logs/${name}"
mv -v "$HOME/pvs-logs/html-logs/${name}/fullhtml"/*
"$HOME/pvs-logs/html-logs/${name}/"
rm -fr "$HOME/pvs-logs/html-logs/${name}/fullhtml"
Этот скрипт будет запускать скрипт %build под трассировщиком PVS-Studio, а затем создавать отчет.
Делаем их исполняемыми:
chmod +x /usr/bin/pvs-builder /usr/bin/pvs-prep
Не используем /usr/local/bin, поскольку он не входит в $PATH в RPM.
Теперь в файл /etc/rpm/macros дописываем:
%__spec_prep_cmd /usr/bin/pvs-prep "%{_sourcedir}"
%__spec_build_cmd /usr/bin/pvs-builder %{name}
(см. https://github.com/rpm-software-management/rpm/issues/1399)
И всё. Каждая сборка проекта на C/C++ будет создавать HTML-отчет в папке $HOME/pvs-logs/html-logs/имя_пакета.
Чтобы не мучиться с mock, можно собирать список пакетов так:
cat list_sec_sorted.txt | while read -r line; do pushd $line
&& dnf builddep --allowerasing -y *.spec
&& abf rpmbuild ; popd; done
т. е. ставить сборочные зависимости в ту же систему, но разрешать удалять лишние пакеты, если устанавливаемые зависимости текущего пакета конфликтуют с зависимостями одного из предыдущих пакетов.