Update: Good news. I figured out a workaround. I was combing through build logs for the working UE 5.4 case and the non-working UE 5.5 case. Specifically, I was looking at these logs:
/Users/miroberts/Library/Logs/Unreal Engine/LocalBuildLogs/UBA-MyProject1Editor-Mac-Development.txt
/Users/miroberts/Library/Logs/Unreal Engine/LocalBuildLogs/UBA-MyProject3Editor-Mac-Development.txt
Here is an excerpt from the working UE 5.4 log:
...
Compile module: WorldMetricsTest
Compile module: CsvMetrics
Compile module: RHICore
Compile module: MetalCPP
Compile module: MetalShaderConverter
Compile module: MetalRHI
Writing manifest to /Users/miroberts/Downloads/MyProject1/Intermediate/Build/Manifest-2-MyProject1-Mac-Development.xml
Targets are up to date
Deploying MyProject1Editor Mac Development...
Deploying now!
Deploying MyProject1 Mac Development...
Deploying now!
Total execution time: 4.32 seconds
WriteFileIfChanged() wrote 0 changed files of 65 requested writes.
...
Here is the corresponding excerpt from the non-working UE 5.5 log. Notice all of the SharedPCH.Engine.Project.ValApi.Cpp20.h is produced by outdated action
messages:
...
Compile module: WorldMetricsTest
Compile module: CsvMetrics
Compile module: NVAftermath
Compile module: RHICore
Compile module: MetalCPP
Compile module: MetalShaderConverter
Compile module: MetalRHI
Writing manifest to /Users/miroberts/Downloads/MyProject3/Intermediate/Build/Manifest-2-MyProject3-Mac-Development.xml
SharedPCH.Engine.Project.ValApi.Cpp20.h: Prerequisite /Users/miroberts/Downloads/MyProject3/Intermediate/Build/Mac/arm64/MyProject3/Development/Engine/SharedPCH.Engine.Project.ValApi.Cpp20.h.gch.rsp is newer than the last execution of the action: 11/16/2024 10:51:35 vs 11/14/2024 00:44:28
Executing PostBuildSync [/Users/miroberts/Downloads/MyProject3/Binaries/Mac/MyProject3]: Produced item "/Users/miroberts/Downloads/MyProject3/Binaries/Mac/MyProject3.app/Contents/PkgInfo" was produced by outdated attributes.
New attributes: /Users/Shared/Epic_Games/UE_5.5/Engine/Binaries/ThirdParty/DotNet/8.0.300/mac-arm64/dotnet "/Users/Shared/Epic_Games/UE_5.5/Engine/Binaries/DotNET/UnrealBuildTool/UnrealBuildTool.dll" -Session="{78cbdb8b-3513-440e-a5c4-d94ab2b03178}" -Mode=ApplePostBuildSync -modernxcode -Input="/Users/miroberts/Downloads/MyProject3/Intermediate/Build/Mac/arm64/MyProject3/Development/PostBuildSync.dat" -XmlConfigCache="/Users/miroberts/Documents/Library/Application Support/Epic/UnrealEngine/XmlConfigCache-+Users+Shared+Epic_Games+UE_5.5.bin" -remoteini="" (ver 0)
MyProject3.cpp: Prerequisite SharedPCH.Engine.Project.ValApi.Cpp20.h is produced by outdated action.
MyProject3: Prerequisite MyProject3.cpp is produced by outdated action.
MyProject3.init.gen.cpp: Prerequisite SharedPCH.Engine.Project.ValApi.Cpp20.h is produced by outdated action.
MyProject3Character.cpp: Prerequisite SharedPCH.Engine.Project.ValApi.Cpp20.h is produced by outdated action.
MyProject3Character.gen.cpp: Prerequisite SharedPCH.Engine.Project.ValApi.Cpp20.h is produced by outdated action.
MyProject3GameMode.cpp: Prerequisite SharedPCH.Engine.Project.ValApi.Cpp20.h is produced by outdated action.
MyProject3GameMode.gen.cpp: Prerequisite SharedPCH.Engine.Project.ValApi.Cpp20.h is produced by outdated action.
Updating version file: /Users/miroberts/Downloads/MyProject3/Intermediate/Build/Versions.xcconfig: Prerequisite MyProject3 is produced by outdated action.
MyProject3.target: Prerequisite MyProject3 is produced by outdated action.
Checking for live coding mutex: Global\LiveCoding_+Users+Shared+Epic_Games+UE_5.5+Engine+Binaries+Mac+UnrealEditor
Checking for live coding mutex: Global\LiveCoding_+Users+miroberts+Downloads+MyProject3+Binaries+Mac+MyProject3
Deleting outdated item: /Users/miroberts/Downloads/MyProject3/Binaries/Mac/MyProject3
Building MyProject3Editor and MyProject3...
Determining max actions to execute in parallel (16 physical cores, 16 logical cores)
Executing up to 16 processes, one per physical core
Using Unreal Build Accelerator local executor to run 11 action(s)
Storage capacity 40Gb
---- Starting trace ----
UbaSessionServer - Disable remote execution (remote sessions will finish current processes)
------ Building 11 action(s) started ------
** For MyProject3-Mac-Development **
[1/11] Compile [Apple] SharedPCH.Engine.Project.ValApi.Cpp20.h (UBA disabled)
[2/11] Compile [Apple] MyProject3GameMode.gen.cpp
[3/11] Compile [Apple] MyProject3Character.gen.cpp
[4/11] Compile [Apple] MyProject3GameMode.cpp
[5/11] Compile [Apple] MyProject3.cpp
[6/11] Compile [Apple] MyProject3Character.cpp
[7/11] Compile [Apple] MyProject3.init.gen.cpp
[8/11] Link [Apple] MyProject3 (UBA disabled)
[9/11] Updating version file: /Users/miroberts/Downloads/MyProject3/Intermediate/Build/Versions.xcconfig (UBA disabled)
[10/11] ApplePostBuildSync Executing PostBuildSync [/Users/miroberts/Downloads/MyProject3/Binaries/Mac/MyProject3] (UBA disabled)
...
All these SharedPCH.Engine.Project.ValApi.Cpp20.h
messages made me suspect that the issue was being caused by a bug in Unreal’s precompiled header logic. So, as a sanity check, I set PCHUsage = PCHUsageMode.NoPCHs
in my Build.cs
file. This change restored the desired incremental build behavior in UE 5.5.
As you might expect, this change makes RunUAT.sh
more strict about including what you use. It took me a while to add all of the missing includes that had crept into my project over time. In particular, for the plugins in my codebase, I needed to explicitly include <HAL/Platform.h>
so Unreal would recognize the MYPLUGIN_API
macros used throughout my plugins.
For me, the increased strictness imposed by RunUAT.sh
after making this change is a feature, not a bug. I want Unreal to be strict about including what you use, and I don’t like how Unreal’s precompiled headers can obfuscate missing include directives throughout my code. As far as I’m concerned, if a source file is using the FHitResult
type, it should always explicitly include <Engine/HitResult.h>
, if for no other reason than to improve readability. So, even if Epic Games fixes the incremental build bug from my original post, I think I’m going to keep precompiled headers turned off.