﻿# Меньше багов — больше FPS: как статический анализ помогает проектам на Unreal Engine

Всё больше проектов появляется на Unreal Engine — от великого "Ведьмака" до не менее великой "The Day Before"\. И чем больше проект, тем выше цена одной незамеченной ошибки\. Когда число строк кода переваливает за несколько тысяч, даже самый внимательный разработчик может не заметить неочевидный баг\. И тут на помощь приходит он — PVS\-Studio, который помогает снизить риск попадания багов в ваши UE\-проекты\.

![1273_ArticleUE_ru/image1.png](https://import.viva64.com/docx/blog/1273_ArticleUE_ru/image1.png)

## Введение

В gamedev происходит постоянная борьба разработчиков с багами и, к сожалению, полностью избавиться от ошибок остаётся недостижимой мечтой\. Но программисты не сдаются и продолжают искать эффективные способы выявления уязвимостей в коде, опираясь на разнообразные инструменты\. В этой статье пойдёт речь об одном из мощных помощников для поиска багов, в том числе и при работе с Unreal Engine\.

У статического анализатора PVS\-Studio богатый опыт сотрудничества с Epic Games и Unreal Engine\. И с каждым релизом в PVS\-Studio появляется всё больше механизмов и специализированных для Unreal Engine диагностических правил\. Давайте же посмотрим, к каким результатам привели годы развития интеграции PVS\-Studio с одним из самых популярных игровых движков\.


> \*\*Примечание\\\.\*\* Подробнее о необходимости статического анализа в GameDev мы рассказывали \[в статье ранее\]\(https://pvs\-studio\.ru/ru/blog/posts/csharp/1269/\) на примере движка Unity\\\.

## Установка PVS\-Studio и плагинов

Подключить [PVS\-Studio](https://pvs-studio.ru/ru/) к [Unreal Engine](https://www.unrealengine.com/en-US) несложно\. Скачиваем инсталлятор по [ссылке](https://pvs-studio.ru/ru/pvs-studio/download/) и следуем инструкции — устанавливаем сам PVS\-Studio и плагин для Visual Studio 2022\. Понадобится Enterprise\-лицензия, если её нет, можно получить триальную по этой [ссылке](https://pvs-studio.ru/ru/pvs-studio/try-free/)\.

Быстрый старт на Windows описан в [документации](https://pvs-studio.ru/ru/pvs-studio-quickstart-cppwindows/?ysclid=mdcuy6die9533359180)\.

## Способы запуска анализа

Попытка проанализировать проект на Unreal Engine привычным способом — через плагин в Visual Studio — приведёт к сообщению о невозможности запуска анализа\. Unreal Engine использует собственную систему сборки [UnrealBuildTool \(UBT\)](https://dev.epicgames.com/documentation/en-us/unreal-engine/unreal-build-tool-in-unreal-engine), и именно через неё должен запускаться анализ\. Поэтому давайте рассмотрим первый способ запуска анализа — через флаги UBT\.

### Флаги UnrealBuildTool

Как я уже ранее упоминал, Unreal Engine компилирует проекты через UBT\. Чтобы проанализировать проект, нужно добавить в UBT следующий флаг:

```cpp
-StaticAnalyzer=PVSStudio
```

Этот флаг нужно прописать в поле `NMake Command Line` в настройках проекта\. В этом случае вместо сборки проекта будет производиться анализ\. При первом запуске будет произведён полный анализ проекта, при последующих — только изменённых файлов \(инкрементальный анализ\)\. Если указать флаг в команде `Rebuild`, анализ будет запускаться каждый раз для всего проекта\.

Подробности о сценариях запуска сборки и анализа можно найти в [документации](https://pvs-studio.ru/ru/docs/manual/0043/#ID5219D77B4B)\.

### Задание параметров в \.target\.cs файлах

Если вы часто пересоздаёте `.sln` или регулярно пересобираете проект, удобнее всего зашить параметры анализа прямо в `.target.cs`\.

Для этого просто добавьте одну строку в конструктор `Target`, в зависимости от версии Unreal Engine\.

<details>
   <summary>Unreal Engine 5\\\.0 и ниже:</summary>

```cpp
public MyProjectTarget(TargetInfo Target) : base(Target)
{
    ....
    WindowsPlatform.StaticAnalyzer = WindowsStaticAnalyzer.PVSStudio;
    ....
}
```


</details>


<details>
   <summary>Unreal Engine 5\\\.1 и выше:</summary>

```cpp
public MyProjectTarget(TargetInfo Target) : base(Target)
{
    ....
    StaticAnalyzer = StaticAnalyzer.PVSStudio;
    ....
}
```


</details>


### Через файл BuildConfiguration\.xml

Если нет возможности менять `.target.cs` файлы, то можно задать параметры анализа через отдельный конфигурационный файл — `BuildConfiguration.xml`\.

Пример минимальной конфигурации:

```cpp
<?xml version="1.0" encoding="utf-8" ?>
<Configuration xmlns="https://www.unrealengine.com/BuildConfiguration">
    <BuildConfiguration>
        <StaticAnalyzer>
            PVSStudio
        </StaticAnalyzer>
    </BuildConfiguration>
</Configuration>
```

## Исключение автогенерируемых файлов и файлов ядра Unreal Engine из анализа проекта

Файлы `*.gen.cpp` генерируются экосистемой Unreal Engine\. Их анализ бесполезен и замедляет процесс\. Также важно исключить из анализа исходники самого Unreal Engine, но это лучше делать, если вы не модифицируете движок\.

Для исключения из анализа автогенерируемых файлов добавьте маску `*.gen.cpp` в настройку плагина [`PathMasks`](https://pvs-studio.ru/ru/docs/manual/6653/#IDE8E5A6ECF6)\. Тут важно сказать, что начиная с Unreal Engine 5\.4, анализ автогенерируемых файлов по умолчанию отключён, но если вдруг вы решили всё же проанализировать эти файлы, то можете использовать флаг `-StaticAnalyzerIncludeGenerated` в UBT\.

Исключить из анализа модуль ядра Unreal Engine можно двумя способами:

1\. Добавлением в `UnrealBuildTool` флага:

```cpp
-StaticAnalyzerProjectOnly
```

2\. Добавлением в файл `target.cs`:

```cpp
bStaticAnalyzerProjectOnly = true;
```

Эти настройки очень важны для ускорения процесса анализа вашего проекта\. Конечно, есть ещё куча других параметров, и если вам интересно про них узнать, то наливайте чаёк и открывайте эту [страницу](https://pvs-studio.ru/ru/docs/manual/0043/)\.

## Что нового в анализе проектов на основе Unreal Engine

### Новый формат отчёта и навигация

Мы переработали формат вывода предупреждений, выдаваемых при запуске анализа через `UnrealBuildTool`\. Наш анализатор уже давно генерирует отчёты в новом формате, и его главная фишка — поддержка многофайловой навигации\. Раньше, если вы запускали анализ через `UnrealBuildTool`, она была недоступна, но сейчас всё работает как надо\.

### Распределённая сборка и анализ через Horde \+ UBA

В Unreal Engine 5\.5 появилась удобная связка — [Horde и UBA \(Unreal Build Accelerator\)](https://dev.epicgames.com/documentation/en-us/unreal-engine/horde-unreal-build-accelerator-and-remote-compilation-tutorial-for-unreal-engine)\. Она умеет распределять сборку \(а теперь ещё и анализ\) по нескольким машинам в сети, серьёзно ускоряя весь процесс\.

* Horde — это кластерная система сборки от Epic Games, использующая MongoDB и Redis\. Ставится либо через MSI, либо через Docker\.
* UBA — специальный executor, который можно включить в конфиге, чтобы задачи сборки и анализа шли параллельно на агентах\.

Как подключить анализ:

1. Разворачиваем [Horde](https://dev.epicgames.com/documentation/en-us/unreal-engine/horde-server-for-unreal-engine#docker-linux): на сервере поднимаем MongoDB и Redis, настраиваем Horde, [привязываем](https://www.epicgames.com/help/ru/c-Category_EpicAccount/c-ConnectedAccounts/kak-privyazat-uchyotnuyu-zapis-unreal-engine-k-uchyotnoj-zapisi-github-a000084938) свою учётную запись Epic Games к GitHub и принимаем инвайт в организацию\.
1. Агенты: ставим HordeAgent на нужные машины, задаём `ServerUrl`, `Enroll` и готово\.
1. Включаем анализ: в `.target.cs` добавляем: `StaticAnalyzer = StaticAnalyzer.PVSStudio;`\.
1. Настраиваем конфиг: в `BuildConfiguration.xml` включаем `bAllowUBAExecutor`, указываем нужный `Server` и `WindowsPool`\.

После этого и сборка, и статический анализ будут распределяться по агентам\. Это уже действительно быстрая разработка, особенно на крупных проектах\. По [ссылке](https://pvs-studio.ru/ru/blog/posts/1220/) вы узнаете все тонкости функционала и настроек, рекомендую ознакомиться\.

### Оптимизация памяти

При анализе проектов на основе Unreal Engine можно заметить, что PVS\-Studio потребляет больше памяти, чем хотелось бы\. Есть две основные причины:

* **Unity build \(Single Compilation Unit\)**\. Unreal Engine по умолчанию объединяет кучу `.cpp` файлов в один большой\. Это позволяет неплохо ускорить сборку, но также требует больше ресурсов для анализа\. 
* **Шаблоны**\. Unreal Engine активно использует шаблоны, а для качественного анализа нужно проводить анализ каждого инстанцирования\. Это тоже даёт нагрузку\.

Мы провели работу над оптимизацией ядра C и C\+\+ анализатора, уменьшив потребление памяти и время анализа\. Однако если проект большой, лучше временно отключить Unity build\. Как это сделать — рассказано [здесь](https://pvs-studio.ru/ru/docs/manual/0043/#IDF173D50339)\.

## Диагностические правила, специфичные для проектов на основе Unreal Engine

Ещё хочется напомнить, что в PVS\-Studio доступны диагностические правила, специфичные для проектов на основе Unreal Engine:

[V1100](https://pvs-studio.ru/ru/docs/warnings/v1100/): Объявление нестатического поля класса в виде указателя на тип, унаследованный от `UObject`, внутри класса/структуры, которые не унаследованы от типа `UObject`\. Сборщик мусора Unreal Engine может уничтожить объект, адресуемый этим указателем\.

[V1102](https://pvs-studio.ru/ru/docs/warnings/v1102/): Объявление сущности, несоответствующей соглашениям о наименованиях для проектов на основе Unreal Engine\. Соответствие этому соглашению требуется для корректной работы Unreal Header Tool\.

Если у вас есть идеи по новым диагностическим правилам, мы будем рады предложениям\. Более подробно об этом можно почитать [здесь](https://pvs-studio.ru/ru/blog/posts/cpp/1069/)\.

## Учёт сторонних библиотек

Была занятная история: у проектов на основе Unreal Engine иногда "исчезали" срабатывания диагностических правил, включая даже наши специфичные и описанные ранее\. Разобравшись, мы выяснили, что в кодовой базе движка есть файл [`MicrosoftPlatformCodeAnalysis.h`](https://github.com/EpicGames/UnrealEngine/blob/release/Engine/Source/Runtime/Core/Public/Microsoft/MicrosoftPlatformCodeAnalysis.h), в котором прописаны комментарии вида [`//-V:: (number)`](https://pvs-studio.ru/ru/docs/manual/0017/#ID699C61E7E6)\. Они отключают диагностические правила по всей кодовой базе, включая ваш код\.

Чтобы решить проблему, мы добавили флаг `--analysis-paths mode=path`, который позволяет игнорировать подавления из стороннего кода\. У него есть режимы:

1\.`mode` — это набор из следующих значений:

* `skip-analysis` — исключает из анализа указанные файлы и директории;
* `skip-settings` — игнорирует чтение настроек из указанных файлов и директорий;
* `skip` — объединяет функционал режимов `skip-analysis` и `skip-settings`;

2\. `path` — это файлы и каталоги, к которым будут применяться настройки\.

Если вы собираете проект с флагом [`-StaticAnalyzerProjectOnly`](https://pvs-studio.ru/ru/docs/manual/0043/#analyze_project_only), `UnrealBuildTool` сам передаёт анализатору флаг `--analysis-paths` с нужными параметрами\. Это позволяет запустить анализ только пользовательского проекта, игнорируя модуль ядра Unreal Engine и вместе с этим все нежелательные подавления диагностических правил\.

Подробнее про проблему и её устранение можно прочитать [тут](https://pvs-studio.ru/ru/blog/posts/cpp/1201/)\.

## Заключение

PVS\-Studio легко интегрируется в существующую сборочную систему\. Чем раньше вы включите его в процесс разработки, тем меньше будет сюрпризов на релизе\. А бесплатно попробовать проверить свой проект на основе Unreal Engine с помощью PVS\-Studio можно по этой [ссылке](https://pvs-studio.ru/ru/pvs-studio/try-free/)\.

Благодарю за внимание\!