Risolvere l'errore UBA Executor UBT di Unreal Engine nelle build da sorgenti di UE 5.8
In breve
Questa guida illustra come risolvere l'errore UBA Executor UBT che interrompe la compilazione da sorgenti di Unreal Engine 5.8. Viene analizzato il motivo per cui l'inizializzazione ricorsiva di UBT causa il crash dell'agente UBA a causa di conflitti di rete e sul file system. Vengono presentate soluzioni pratiche tramite file di configurazione XML, flag da riga di comando e una patch C# consigliata per preservare l'accelerazione di build. Infine, vengono condivise best practice per l'ottimizzazione della compilazione e la gestione delle build per dedicated server.
Poche cose rallentano il ritmo di lavoro di uno studio come una build dell'engine compromessa, specialmente quando si compila Unreal Engine 5.8.0 da sorgenti e Visual Studio si blocca con un'eccezione criptica. La build fallisce con un'eccezione non gestita che punta direttamente a UBAExecutor.cs. Questo specifico blocco, noto come unreal engine uba executor ubt error, interrompe completamente la compilazione. Impedisce al build graph di completare la generazione di helper program critici come UnrealHeaderTool. In questa guida analizzeremo perché Unreal Build Accelerator (UBA) fatica a gestire le chiamate nidificate, come la configurazione predefinita fallisce e come applicare una patch ai sorgenti dell'engine per ripristinare una pipeline di build funzionante.
Understanding the Build System Architecture
Per comprendere il motivo per cui si verifica questo errore, dobbiamo esaminare come Unreal Build Tool (UBT) orchestra la compilazione. I codebase di Unreal Engine sono enormi e spesso contengono decine di migliaia di file sorgente. Per compilarli in modo efficiente, UBT agisce come un meta-build system, generando grafi di dipendenza e distribuendo le azioni di compilazione.
What is Unreal Build Accelerator?
Epic Games ha introdotto Unreal Build Accelerator (UBA) come executor di compilazione predefinito per sostituire i vecchi sistemi di distribuzione. UBA è progettato per velocizzare la compilazione utilizzando un file system virtualizzato (VFS) leggero per intercettare le operazioni di I/O dei file. Indirizza i task del compilatore su più core locali o li distribuisce sui nodi di build di Horde.
Su una macchina di build standard da 64 core, UBA può ridurre i tempi di compilazione pulita dell'engine da circa 90 minuti a meno di 25 minuti. Tuttavia, poiché UBA si affida a un agente locale centralizzato per intercettare l'I/O, richiede un controllo rigoroso su come vengono avviati i processi del compilatore.
The Mechanism of Recursive UBT Calls
Durante una sessione di compilazione, UBT incontra frequentemente target che devono essere compilati prima dei binari principali dell'engine. Ad esempio, prima di compilare l'eseguibile UnrealEditor, UBT deve compilare UnrealHeaderTool (UHT) per analizzare i file header e generare i metadati di reflection.
Per fare questo, il processo UBT principale avvia un processo UBT secondario e nidificato per compilare il target richiesto come prerequisito. Questa invocazione nidificata è definita chiamata UBT ricorsiva. Quando una chiamata UBT ricorsiva è attiva, UBT imposta un flag interno (UnrealBuildTool.IsRecursive = true) e propaga le variabili d'ambiente per contrassegnare il processo come nidificato.
Why the UBA Executor Crashes on Recursive Invocations
Il crash si verifica perché l'executor di UBA non è progettato per supportare cicli di compilazione nidificati. Diamo un'occhiata al tipico call stack restituito da UBT quando si verifica questo errore in 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
The Safety Check in UBAExecutor.cs
All'interno del metodo UBAExecutor.Init (intorno alla linea 315 di UBAExecutor.cs), l'engine esegue esplicitamente un controllo di sicurezza sulla ricorsione:
// 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...
}
Questo controllo di sicurezza esiste per un motivo fondamentale. L'agente locale di UBA si associa a porte TCP specifiche per comunicare con i processi helper virtualizzati del compilatore.
Se un'invocazione ricorsiva di UBT tentasse di inizializzare una seconda istanza dell'executor UBA, entrambe le istanze proverebbero a effettuare il binding agli stessi socket di rete, entrando in conflitto sugli hook del file system virtualizzato. Ciò causerebbe errori di allocazione dei socket, corruzione del filesystem o deadlock infiniti della build. L'eccezione funge quindi da barriera protettiva.
The Root Cause: Executor selection Failure
Il vero bug nelle build da sorgenti di Unreal Engine 5.8.0 non è questo controllo di sicurezza. Si tratta piuttosto del fallimento della logica della factory dell'executor nel gestire correttamente le chiamate ricorsive.
Quando UBT deve determinare quale executor utilizzare, interroga la classe ExecutorFactory.cs. La factory verifica se UBA is abilitato e disponibile sulla macchina host.
Tuttavia, non verifica se il processo UBT corrente sia un'esecuzione ricorsiva. Di conseguenza, quando il processo UBT secondario si avvia per compilare UnrealHeaderTool, la factory tenta di assegnare l'UBAExecutor alla build nidificata, attivando il crash nel metodo Init.
The XML Configuration Trap
Molti sviluppatori cercano di aggirare questo problema modificando il file globale BuildConfiguration.xml. Il consiglio classico che si trova nei vecchi post sui forum è di disattivare UBA disabilitando il seguente tag:
<?xml version="1.0" encoding="utf-8" ?>
<Configuration xmlns="https://www.unrealengine.com/BuildConfiguration">
<BuildConfiguration>
<bAllowUBA>false</bAllowUBA>
</BuildConfiguration>
</Configuration>
Why bAllowUBA Is Ignored in UE 5.8
Se applichi la configurazione XML sopra indicata a una build da sorgenti di Unreal Engine 5.8.0, il compilatore tenterà comunque di avviare UBA e restituirà l'eccezione. Questo accade perché il sistema di configurazione della build dell'engine è stato rifattorizzato.
Il vecchio flag bAllowUBA è deprecato e non è più mappato sulla logica di selezione dell'executor. Il comportamento di UBA è invece controllato da due proprietà distinte: bAllowUBAExecutor e bAllowUBALocalExecutor.
Poiché UBT non trova bAllowUBAExecutor nel tuo file XML, il valore predefinito è impostato su true. Questo sovrascrive silenziosamente il tuo tentativo di disattivare UBA.
Correct XML Structure for UBA Configuration
Per disabilitare correttamente UBA tramite i file di configurazione, devi utilizzare i nomi aggiornati delle proprietà XML. Di seguito è mostrata la struttura corretta per forzare UBT a ripiegare sui classici executor locali:
<?xml version="1.0" encoding="utf-8" ?>
<Configuration xmlns="https://www.unrealengine.com/BuildConfiguration">
<BuildConfiguration>
<bAllowUBAExecutor>false</bAllowUBAExecutor>
<bAllowUBALocalExecutor>false</bAllowUBALocalExecutor>
</BuildConfiguration>
</Configuration>
Questa configurazione esclude con successo UBA. Tuttavia, disabilitare completamente UBA significa rinunciare ai significativi vantaggi in termini di velocità di compilazione che offre per le azioni di build principali.
Step-by-Step Guide to Fixing the Error
A seconda del tuo workflow, puoi scegliere di risolvere questo problema a livello globale modificando la configurazione XML, oppure applicando una patch direttamente al codice sorgente di UBT per preservare l'accelerazione di build per le compilazioni non ricorsive.
Method 1: The BuildConfiguration.xml Override
Se non vuoi modificare il codice sorgente dell'engine, puoi disabilitare UBA globalmente. Questo è il modo più rapido per avviare la compilazione del progetto, anche se aumenterà i tempi di compilazione per le build pulite dal ~40% al ~60% a seconda dell'hardware.
- Individua o crea il file globale
BuildConfiguration.xml. Su Windows, questo si trova solitamente in%AppData%\Roaming\Unreal Engine\UnrealBuildTool\BuildConfiguration.xml. Su Linux, si trova in~/.config/Unreal Engine/UnrealBuildTool/BuildConfiguration.xml. - Apri il file XML in un editor di testo.
- Sostituisci il contenuto con lo schema XML aggiornato mostrato di seguito.
- Salva il file e riavvia la build in 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>
Method 2: Patching UBT Source Code (Recommended)
Dato che stai compilando Unreal Engine 5.8 da sorgenti, la soluzione consigliata è applicare una patch al codice sorgente C# di UBT. Questo consente a UBA di essere eseguito sul target di compilazione principale, forzando al contempo il fallback sul classico ParallelExecutor durante le chiamate ricorsive.
- Vai alla directory dei sorgenti di UBT:
Engine/Source/Programs/UnrealBuildTool/Executors/. - Apri il file
ExecutorFactory.csin Visual Studio o in un editor di testo. - Individua il metodo
Create. Questo metodo è responsabile di valutare la configurazione e restituire l'ActionExecutorappropriato. - Modifica l'istruzione condizionale di selezione di UBA per includere un controllo sulle esecuzioni ricorsive di UBT.
// 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);
}
Questo patch impedisce all'istanza nidificata di UBT di selezionare l'executor UBA. Invece, la build ricorsiva (come la compilazione di UnrealHeaderTool) verrà eseguita in sicurezza utilizzando il ParallelExecutor locale, mentre la compilazione principale dell'engine continuerà a sfruttare tutta la potenza di UBA.
Method 3: Command Line Flags
Se esegui il processo di build tramite script da riga di comando personalizzati o pipeline di CI/CD, puoi disabilitare UBA per singola invocazione. Questo è particolarmente utile se desideri mantenere UBA abilitato per gli sviluppatori locali ma disattivarlo sui build server remoti.
Per farlo, aggiungi il flag -NoUBA al comando di build di UBT:
# Example command to build the editor without UBA
Engine\Build\BatchFiles\Build.bat UnrealEditor Win64 Development -NoUBA
In alternativa, puoi forzare UBT a utilizzare il parallel executor standard specificandolo esplicitamente con il flag -Executor:
Engine\Build\BatchFiles\Build.bat UnrealEditor Win64 Development -Executor=Parallel
Cleaning and Regenerating the Build Environment
Dopo aver applicato una qualsiasi delle correzioni descritte sopra, UBT potrebbe non riuscire a compilare a causa di file di assembly memorizzati in cache o metadati intermedi obsoleti. Per garantire che la correzione sia applicata in modo pulito, è necessario cancellare i binari generati del build tool e rigenerare i file di progetto.
For Windows Environments
Esegui i seguenti comandi in un prompt dei comandi o in un'istanza di PowerShell puntando alla directory dei sorgenti di 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
For Linux and macOS Environments
Esegui questi comandi nel tuo terminale:
# Remove cached build tool data
rm -rf Engine/Intermediate/Build/UnrealBuildTool
rm -rf Engine/Binaries/DotNET/UnrealBuildTool
# Regenerate project files
./GenerateProjectFiles.sh
Una volta pulito l'ambiente, apri il file di solution generato (UE5.sln) in Visual Studio e compila nuovamente il target. La build ora dovrebbe superare la fase di compilazione ricorsiva senza restituire l'eccezione dell'executor.
Actionable Best Practices for Unreal Engine Source Builds
Compilare un fork personalizzato dell'engine da sorgenti comporta diverse sfide di compilazione, ottimizzazione e packaging. L'applicazione delle seguenti best practice ti aiuterà a mantenere una pipeline di sviluppo stabile e altamente ottimizzata.
1. Optimize Concurrency to Prevent Memory Starvation
I compilatori C++ moderni richiedono una quantità significativa di RAM per thread di compilazione. Quando si compilano moduli di grandi dimensioni dell'engine, UBT può avviare più task paralleli di quanti ne possa supportare la RAM di sistema, causando il thrashing del file di paging o crash del compilatore.
È possibile limitare il numero massimo di processori configurando le impostazioni del ParallelExecutor nel file BuildConfiguration.xml:
<Configuration xmlns="https://www.unrealengine.com/BuildConfiguration">
<ParallelExecutor>
<MaxProcessorCount>16</MaxProcessorCount>
<ProcessorCountMultiplier>1.0</ProcessorCountMultiplier>
</ParallelExecutor>
</Configuration>
Limita il conteggio a circa 2 GB di RAM per thread. Ad esempio, una macchina con 32 GB di RAM dovrebbe limitare MaxProcessorCount a 16.
2. Master Dedicated Server Asset Stripping
Quando distribuisci il tuo gioco nel cloud, dovresti evitare di compilare asset client non necessari (come texture della UI, audio e mesh) nel binario del tuo dedicated server. Questo riduce i tempi di avvio del server e il memory footprint, il che è fondamentale per scalare le istanze in modo efficiente.
Per scoprire come configurare i tuoi script di build per escludere questi asset, segui la nostra guida dettagliata su Asset Stripping del Dedicated Server in Unreal Engine.
3. Verify Blueprint and Package Integrity Early
Una build dell'engine andata a buon fine non garantisce che il pacchetto del tuo progetto venga creato senza errori. Blueprint obsoleti o errori di serializzazione causano spesso crash durante la fase finale di packaging.
Per evitare che questi problemi blocchino la tua pipeline di rilascio, leggi la nostra guida su Risolvere il crash HasValidBlueprint di Unreal Package per impostare controlli di validazione automatizzati.
4. Configure UBA VFS Caching Correctly
Se decidi di mantenere abilitato UBA tramite la patch C#, configura la cache del file system virtuale per memorizzare i file oggetto compilati localmente. Questo ti consentirà di evitare la ricompilazione dei file sorgente non modificati quando passi da un branch all'altro.
Aggiungi il blocco di configurazione UnrealBuildAccelerator al tuo file XML per abilitare il caching:
<Configuration xmlns="https://www.unrealengine.com/BuildConfiguration">
<UnrealBuildAccelerator>
<WriteCache>true</WriteCache>
<Cache>127.0.0.1</Cache>
</UnrealBuildAccelerator>
</Configuration>
Assicurati che il tuo firewall non blocchi le porte di comunicazione di rete locale di UBA, utilizzate per gestire il ciclo di sincronizzazione della cache.
Elevating Your Backend Architecture
Risolvere problemi di build come l'unreal engine uba executor ubt error è fondamentale per mantenere un workflow di sviluppo sano. Tuttavia, configurare un ambiente di compilazione locale è solo il primo passo per sviluppare un moderno gioco multiplayer.
Una volta compilato il tuo engine personalizzato e pronti i tuoi dedicated server, dovrai affrontare le complesse sfide dell'infrastruttura backend. Scrivere da zero l'orchestrazione dei server, gli algoritmi di matchmaking e i database di persistenza richiede settimane di sviluppo.
Configurare load balancer, lo sharding del database e la gestione dei certificati SSL può facilmente richiedere da 4 a 6 settimane di lavoro dedicato. Con horizOn, questi servizi backend sono già preconfigurati e pronti a scalare.
Invece di scrivere codice infrastrutturale, puoi integrare i dati dei giocatori, le lobby in tempo reale e lo scaling dei server con poche semplici chiamate API. Questo ti consente di distribuire build di dedicated server e gestire lo stato dei giocatori con zero costi di manutenzione. Il tuo team può così concentrarsi sulle meccaniche di gameplay e sulle funzionalità dell'engine, mentre horizOn gestisce l'infrastruttura cloud.
Next Steps
Per risolvere questo errore di build, scegli l'override XML rapido oppure applica la patch sorgente in C# su ExecutorFactory.cs. Una volta che la tua pipeline di build funziona correttamente, cerca modi per ottimizzare il tuo workflow di deployment. Se vuoi scalare il tuo gioco multiplayer senza l'onere di ospitare server personalizzati, prova gratis horizOn o consulta la nostra documentazione API per saperne di più.