Résoudre l'erreur Unreal Engine UBA Executor UBT dans les builds de source UE 5.8
En bref
Ce guide explique comment résoudre le plantage de compilation dans Unreal Engine 5.8 provoqué par l'erreur `UBAExecutor.cs` lors des appels récursifs d'UBT. Nous détaillons la cause racine liée à la sélection de l'exécuteur par la factory ainsi que les limites de l'ancienne configuration XML. Enfin, nous présentons des solutions concrètes, notamment l'application d'un patch C# dans `ExecutorFactory.cs` ou l'utilisation de configurations XML et de flags mis à jour.
Peu de choses freinent autant l'élan d'un studio qu'un build de moteur planté, surtout lorsque vous compilez Unreal Engine 5.8.0 à partir des sources et que Visual Studio s'arrête avec une exception cryptique. Le build échoue avec une exception non gérée pointant directement vers UBAExecutor.cs. Ce bloqueur spécifique, connu sous le nom de unreal engine uba executor ubt error, interrompt complètement la compilation. Il empêche le build graph de terminer la génération de programmes d'aide critiques comme UnrealHeaderTool. Dans ce guide, nous analyserons pourquoi Unreal Build Accelerator (UBA) rencontre des difficultés avec les appels imbriqués, comment la configuration par défaut échoue, et comment patcher le code source de votre moteur pour restaurer un build pipeline fonctionnel.
Comprendre l'architecture du build system
Pour comprendre pourquoi cette erreur se produit, nous devons examiner comment Unreal Build Tool (UBT) orchestre la compilation. Les codebases de Unreal Engine sont massives, contenant souvent des dizaines de milliers de fichiers sources. Pour les compiler efficacement, UBT agit comme un méta-build system, générant des graphes de dépendance et distribuant les actions de compilation.
Qu'est-ce que Unreal Build Accelerator ?
Epic Games a introduit Unreal Build Accelerator (UBA) comme exécuteur de compilation par défaut pour remplacer les anciens systèmes de distribution. UBA est conçu pour accélérer la compilation en utilisant un système de fichiers virtualisé (VFS) léger pour intercepter les opérations d'I/O de fichiers. Il route les tâches du compilateur sur plusieurs cœurs locaux ou les distribue sur des nœuds de build Horde.
Sur une machine de build standard de 64 cœurs, UBA peut réduire le temps de compilation complète du moteur de ~90 minutes à moins de ~25 minutes. Cependant, comme UBA repose sur un agent local centralisé pour intercepter les I/O, il nécessite un contrôle strict sur la façon dont les processus du compilateur sont lancés.
Le mécanisme des appels UBT récursifs
Lors d'une exécution de compilation, UBT rencontre fréquemment des cibles qui doivent être générées avant que les binaires du moteur principal ne puissent être compilés. Par exemple, avant de compiler l'exécutable UnrealEditor, UBT must compile UnrealHeaderTool (UHT) afin de parser les fichiers d'en-tête et générer les métadonnées de réflexion.
Pour ce faire, le processus UBT principal lance un processus UBT secondaire imbriqué pour compiler la cible prérequise. Cette invocation imbriquée est appelée un appel UBT récursif. Lorsqu'un appel UBT récursif est actif, UBT définit un flag interne (UnrealBuildTool.IsRecursive = true) et propage des variables d'environnement pour marquer le processus comme imbriqué.
Pourquoi l'exécuteur UBA crashe lors d'invocations récursives
Le crash se produit car l'exécuteur UBA n'est pas conçu pour prendre en charge les boucles de compilation imbriquées. Examinons la call stack classique retournée par UBT lorsque cette défaillance survient dans Visual Studio :
Unhandled exception: Exception: UBA executor is not expected to be invoked from a recursive UBT call.
at UnrealBuildTool.UBAExecutor.Init(IEnumerable`1 targetDescriptors, ILogger logger) in UnrealEngine\Engine\Source\Programs\UnrealBuildTool\Executors\UnrealBuildAccelerator\UBAExecutor.cs:line 315
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
at UnrealBuildTool.UBAExecutor.ExecuteActionsAsync(IEnumerable`1 inputActions, ILogger logger) in UnrealEngine\Engine\Source\Programs\UnrealBuildTool\Executors\UnrealBuildAccelerator\UBAExecutor.cs:line 617
at UnrealBuildTool.ActionGraph.InternalExecuteActions(ActionExecutor Executor, List`1 ActionsToExecute, ILogger Logger) in UnrealEngine\Engine\Source\Programs\UnrealBuildTool\Actions\ActionGraph.cs:line 435
La vérification de sécurité dans UBAExecutor.cs
Dans la méthode UBAExecutor.Init (autour de la ligne 315 de UBAExecutor.cs), le moteur applique explicitement une vérification de sécurité liée à la récursion :
// Engine/Source/Programs/UnrealBuildTool/Executors/UnrealBuildAccelerator/UBAExecutor.cs
public void Init(IEnumerable<TargetDescriptor> TargetDescriptors, ILogger Logger)
{
if (UnrealBuildTool.IsRecursive)
{
throw new Exception("UBA executor is not expected to be invoked from a recursive UBT call.");
}
// Virtualized file system and network initialization follow...
}
Cette vérification de sécurité existe pour une raison cruciale. L'agent UBA local se lie à des ports TCP spécifiques pour communiquer avec les processus d'assistance du compilateur virtualisé.
Si une invocation UBT récursive tentait d'initialiser une seconde instance de l'exécuteur UBA, les deux instances essaieraient de se lier aux mêmes sockets réseau et entreraient en conflit pour les hooks du système de fichiers virtualisé. Cela entraînerait des erreurs d'allocation de sockets, une corruption du système de fichiers ou des deadlocks de build indéfinis. L'exception sert de barrière de protection.
La cause racine : l'échec de la sélection de l'exécuteur
Le véritable bug dans les builds de source d'Unreal Engine 5.8.0 n'est pas cette vérification de sécurité. Il s'agit plutôt de l'échec de la logique de la factory d'exécuteurs à gérer correctement les appels récursifs.
Lorsque UBT détermine quel exécuteur utiliser, il interroge la classe ExecutorFactory.cs. Le factory vérifie si UBA est activé et disponible sur la machine hôte.
Cependant, elle ne vérifie pas si le processus UBT actuel est une exécution récursive. Par conséquent, lorsque le processus UBT secondaire se lance pour compiler UnrealHeaderTool, la factory tente d'assigner le UBAExecutor au build imbriqué, déclenchant le crash dans la méthode Init.
Le piège de la configuration XML
De nombreux développeurs tentent de contourner ce problème en modifiant le fichier global BuildConfiguration.xml. Le conseil classique dans les anciens posts de forums est de désactiver UBA en désactivant la balise suivante :
<?xml version="1.0" encoding="utf-8" ?>
<Configuration xmlns="https://www.unrealengine.com/BuildConfiguration">
<BuildConfiguration>
<bAllowUBA>false</bAllowUBA>
</BuildConfiguration>
</Configuration>
Pourquoi bAllowUBA est ignoré dans UE 5.8
Si vous appliquez la configuration XML ci-dessus à un build de source d'Unreal Engine 5.8.0, le compilateur tentera toujours de lancer UBA et lèvera l'exception. C'est parce que le système de configuration de build du moteur a été refactorisé.
L'ancien flag bAllowUBA est déprécié et n'est plus mappé à la logique de sélection de l'exécuteur. À la place, le comportement de UBA est contrôlé par deux propriétés distinctes : bAllowUBAExecutor et bAllowUBALocalExecutor.
Comme UBT ne trouve pas bAllowUBAExecutor dans votre XML, sa valeur par défaut est true. Cela annule silencieusement votre tentative de désactiver UBA.
Structure XML correcte pour la configuration de UBA
Pour désactiver avec succès UBA via les fichiers de configuration, vous devez utiliser les noms de propriétés XML mis à jour. Voici la structure correcte pour forcer UBT à basculer sur les exécuteurs locaux standards :
<?xml version="1.0" encoding="utf-8" ?>
<Configuration xmlns="https://www.unrealengine.com/BuildConfiguration">
<BuildConfiguration>
<bAllowUBAExecutor>false</bAllowUBAExecutor>
<bAllowUBALocalExecutor>false</bAllowUBALocalExecutor>
</BuildConfiguration>
</Configuration>
Cette configuration contourne avec succès UBA. Cependant, désactiver complètement UBA signifie que vous perdez les avantages significatifs de vitesse de compilation qu'il offre pour vos actions de build principales.
Guide étape par étape pour résoudre l'erreur
Selon votre workflow, vous pouvez choisir de résoudre ce problème globalement en modifiant votre configuration XML, ou en patchant directement le code source d'UBT pour préserver l'accélération de build pour les compilations non récursives.
Méthode 1 : La surcharge via BuildConfiguration.xml
Si vous ne souhaitez pas modifier le code source du moteur, vous pouvez désactiver UBA globalement. C'est le moyen le plus rapide de compiler votre projet, bien que cela augmente les temps de compilation pour les clean builds de ~40 % à ~60 % selon votre matériel.
- Localisez ou créez votre fichier global
BuildConfiguration.xml. Sur Windows, il se trouve généralement à l'adresse%AppData%\Roaming\Unreal Engine\UnrealBuildTool\BuildConfiguration.xml. Sur Linux, il se trouve à l'adresse~/.config/Unreal Engine/UnrealBuildTool/BuildConfiguration.xml. - Ouvrez le fichier XML dans un éditeur de texte.
- Remplacez le contenu par le schéma XML mis à jour présenté ci-dessous.
- Enregistrez le fichier et relancez votre build Visual Studio.
<?xml version="1.0" encoding="utf-8" ?>
<Configuration xmlns="https://www.unrealengine.com/BuildConfiguration">
<BuildConfiguration>
<bAllowUBAExecutor>false</bAllowUBAExecutor>
<bAllowUBALocalExecutor>false</bAllowUBALocalExecutor>
</BuildConfiguration>
</Configuration>
Méthode 2 : Patcher le code source d'UBT (Recommandé)
Comme vous compilez Unreal Engine 5.8 à partir des sources, la solution recommandée consiste à patcher le code source C# d'UBT. Cela permet à UBA de s'exécuter sur votre cible de compilation principale tout en forçant un fallback vers le ParallelExecutor standard lors des appels récursifs.
- Accédez au répertoire source d'UBT :
Engine/Source/Programs/UnrealBuildTool/Executors/. - Ouvrez le fichier
ExecutorFactory.csdans Visual Studio ou un éditeur de texte. - Localisez la méthode
Create. Cette méthode est responsable de l'évaluation de votre configuration et du retour de l'exécuteurActionExecutorapproprié. - Modifiez la condition de sélection de UBA pour inclure une vérification des exécutions UBT récursives.
// Engine/Source/Programs/UnrealBuildTool/Executors/ExecutorFactory.cs
public static ActionExecutor Create(BuildConfiguration BuildConfiguration, List<TargetDescriptor> TargetDescriptors, ILogger Logger)
{
// Check if UBA is allowed, available, and NOT running recursively
- if (BuildConfiguration.bAllowUBAExecutor && UBAExecutor.IsAvailable())
+ if (BuildConfiguration.bAllowUBAExecutor && UBAExecutor.IsAvailable() && !UnrealBuildTool.IsRecursive)
{
return new UBAExecutor(BuildConfiguration, Logger);
}
// Fall back to IncrediBuild if configured
if (BuildConfiguration.bAllowXGE)
{
return new XGEExecutor(BuildConfiguration, Logger);
}
// Fall back to standard ParallelExecutor
return new ParallelExecutor(BuildConfiguration, Logger);
}
Ce patch empêche l'instance UBT imbriquée de sélectionner l'exécuteur UBA. À la place, le build récursif (comme la compilation de UnrealHeaderTool) s'exécutera en toute sécurité à l'aide du ParallelExecutor local, tandis que la compilation principale de votre moteur continuera à utiliser toute la puissance de UBA.
Méthode 3 : Flags en ligne de commande
Si vous exécutez votre processus de build via des scripts en ligne de commande personnalisés ou des pipelines de CI/CD, vous pouvez désactiver UBA par invocation. Cela est particulièrement utile si vous souhaitez garder UBA activé pour les développeurs locaux mais le désactiver sur les serveurs de build distants.
Pour ce faire, ajoutez le flag -NoUBA à votre commande de build UBT :
# Example command to build the editor without UBA
Engine\Build\BatchFiles\Build.bat UnrealEditor Win64 Development -NoUBA
Alternativement, vous pouvez forcer UBT à utiliser le parallel executor standard en le spécifiant explicitement avec le flag -Executor :
Engine\Build\BatchFiles\Build.bat UnrealEditor Win64 Development -Executor=Parallel
Nettoyage et régénération de l'environnement de build
Après avoir appliqué l'un des correctifs ci-dessus, UBT peut échouer à compiler en raison de fichiers d'assembly en cache ou de métadonnées intermédiaires obsolètes. Pour garantir que le correctif s'applique proprement, vous devez effacer les binaires générés pour les outils de build et régénérer les fichiers de projet.
Pour les environnements Windows
Exécutez les commandes suivantes dans une invite de commandes ou une instance PowerShell pointant vers le répertoire source de votre Unreal Engine :
:: Delete the cached UBT assembly and build binaries
rd /s /q Engine\Intermediate\Build\UnrealBuildTool
rd /s /q Engine\Binaries\DotNET\UnrealBuildTool
:: Regenerate the project files
GenerateProjectFiles.bat
Pour les environnements Linux et macOS
Exécutez ces commandes dans votre terminal :
# Remove cached build tool data
rm -rf Engine/Intermediate/Build/UnrealBuildTool
rm -rf Engine/Binaries/DotNET/UnrealBuildTool
# Regenerate project files
./GenerateProjectFiles.sh
Une fois l'environnement propre, ouvrez le fichier de solution généré (UE5.sln) dans Visual Studio et recompilez la cible. Le build devrait maintenant passer la phase de compilation récursive sans lever d'exception d'exécuteur.
Best practices concrètes pour les builds de source d'Unreal Engine
Compiler un fork personnalisé du moteur à partir des sources introduit divers défis de compilation, d'optimisation et de packaging. L'application des best practices suivantes vous aidera à maintenir un pipeline de développement stable et hautement optimisé.
1. Optimiser la concurrence pour éviter la saturation de la mémoire
Les compilateurs C++ modernes nécessitent une quantité importante de RAM par thread de compilation. Lors de la compilation de grands modules du moteur, UBT peut lancer plus de tâches parallèles que la RAM de votre système ne peut en supporter, ce qui entraîne du page-file thrashing ou des plantages du compilateur.
Vous pouvez limiter le nombre maximal de processeurs en configurant les paramètres de ParallelExecutor dans votre fichier BuildConfiguration.xml :
<Configuration xmlns="https://www.unrealengine.com/BuildConfiguration">
<ParallelExecutor>
<MaxProcessorCount>16</MaxProcessorCount>
<ProcessorCountMultiplier>1.0</ProcessorCountMultiplier>
</ParallelExecutor>
</Configuration>
Limitez le nombre à environ 2 Go de RAM par thread. Exemple : une machine disposant de 32 Go de RAM devrait limiter le MaxProcessorCount à 16.
2. Maîtriser l'asset stripping pour Dedicated Server
Lors du déploiement de votre jeu dans le cloud, vous devriez éviter de compiler des assets clients inutiles (tels que les textures d'interface utilisateur, l'audio et les meshes) dans votre binaire de Dedicated Server. Cela réduit le temps de démarrage de votre serveur et son empreinte mémoire, ce qui est crucial pour le scaling efficace des flottes.
Pour apprendre à configurer vos scripts de build afin d'exclure ces assets, suivez notre guide détaillé sur Unreal Engine Dedicated Server Asset Stripping.
3. Vérifier tôt l'intégrité des Blueprints et des packages
Un build réussi du moteur ne garantit pas que votre projet se packagera sans erreur. Des blueprints obsolètes ou des erreurs de sérialisation provoquent souvent des crashs lors de la phase finale de packaging.
Pour éviter que ces problèmes ne bloquent votre release pipeline, lisez notre guide sur la Résolution du crash Unreal Package HasValidBlueprint Ensure afin de mettre en place des vérifications de validation automatisées.
4. Configurer correctement le cache VFS de UBA
Si vous décidez de garder UBA activé en utilisant le patch C#, configurez le cache du système de fichiers virtuel pour stocker localement les fichiers objets compilés. Cela vous évite de recompiler les fichiers sources non modifiés lors du changement de branche.
Ajoutez le bloc de configuration UnrealBuildAccelerator à votre fichier XML pour activer le cache :
<Configuration xmlns="https://www.unrealengine.com/BuildConfiguration">
<UnrealBuildAccelerator>
<WriteCache>true</WriteCache>
<Cache>127.0.0.1</Cache>
</UnrealBuildAccelerator>
</Configuration>
Assurez-vous que votre pare-feu ne bloque pas les ports de communication réseau locaux d'UBA, qui sont utilisés pour gérer la boucle de synchronisation du cache.
Élever votre architecture Backend
Résoudre des problèmes de build comme le unreal engine uba executor ubt error est crucial pour maintenir un workflow de développement sain. Cependant, la configuration d'un environnement de compilation local n'est que la première étape de la création d'un jeu Multiplayer moderne.
Une fois votre moteur personnalisé compilé et vos Dedicated Servers prêts, vous devez faire face aux défis complexes de l'infrastructure Backend. Écrire de zéro votre propre orchestration de serveurs, vos algorithmes de Matchmaking et vos bases de données de persistance demande des semaines de temps de développement.
La configuration des Load Balancers, du sharding de base de données et de la gestion des certificats SSL peut facilement prendre 4 à 6 semaines de travail dédié. Avec horizOn, ces services Backend sont préconfigurés et prêts à être scalés.
Au lieu d'écrire du code d'infrastructure, vous pouvez intégrer les données des joueurs, les salons en temps réel et le scaling de serveurs à l'aide de quelques appels API simples. Cela vous permet de déployer des builds de Dedicated Server et de gérer l'état des joueurs sans surcharge de maintenance. Votre équipe peut se concentrer sur les mécaniques de gameplay et les fonctionnalités du moteur pendant que horizOn gère l'infrastructure cloud.
Prochaines étapes
Pour résoudre cette erreur de build, choisissez soit la surcharge XML rapide, soit appliquez le patch source C# dans ExecutorFactory.cs. Une fois votre build pipeline opérationnel, recherchez des moyens d'optimiser votre workflow de déploiement. Si vous souhaitez scaler votre jeu Multiplayer sans la contrainte d'héberger des serveurs personnalisés, essayez gratuitement horizOn ou consultez notre documentation API pour en savoir plus.