Slower build times in JetBrains Rider due to unnecessary UnrealBuildTool project dependency?

It seems that projects all contains a dependency on UnrealBuildTool, e.g.

Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MyProject", "Engine\Intermediate\ProjectFiles\M2Development.vcxproj", "{0E758EC9-BA36-3D62-994B-326C861BB9F4}"
ProjectSection(ProjectDependencies) = postProject
{7E468C9C-2CAF-3A25-AE9C-2199BEDEB41A} = {7E468C9C-2CAF-3A25-AE9C-2199BEDEB41A}
EndProjectSection
EndProject

Where we have:

Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnrealBuildTool", "Engine\Source\Programs\UnrealBuildTool\UnrealBuildTool.csproj", "{7E468C9C-2CAF-3A25-AE9C-2199BEDEB41A}"

When building with Rider, this dependency then causes a bunch of unnecessary extra projects to be built when building our game project, e.g.

CONSOLE: Use build tool: C:\Program Files\Microsoft Visual Studio\2022\Professional\MSBuild\Current\Bin\MSBuild.exe
15:06:37 Building C:\dev\m2up\Game\Engine\Source\Programs\UnrealBuildTool\UnrealBuildTool.csproj
15:06:38 Building C:\dev\m2up\Game\Engine\Source\Programs\Shared\EpicGames.Build\EpicGames.Build.csproj
15:06:38 Building C:\dev\m2up\Game\Engine\Source\Programs\Shared\EpicGames.Core\EpicGames.Core.csproj
15:06:38 Building C:\dev\m2up\Game\Engine\Source\Programs\Shared\EpicGames.Horde\EpicGames.Horde.csproj
15:06:38 Building C:\dev\m2up\Game\Engine\Source\Programs\Shared\EpicGames.IoHash\EpicGames.IoHash.csproj
15:06:38 Building C:\dev\m2up\Game\Engine\Source\Programs\Shared\EpicGames.OIDC\EpicGames.OIDC.csproj
15:06:38 Building C:\dev\m2up\Game\Engine\Source\Programs\Shared\EpicGames.Serialization\EpicGames.Serialization.csproj
15:06:38 Building C:\dev\m2up\Game\Engine\Source\Programs\Shared\EpicGames.UBA\EpicGames.UBA.csproj
15:06:38 Building C:\dev\m2up\Game\Engine\Source\Programs\Shared\EpicGames.UHT\EpicGames.UHT.csproj
15:06:38 Building C:\dev\m2up\Game\Engine\Source\Programs\Shared\EpicGames.MsBuild\EpicGames.MsBuild.csproj
15:06:38 Building C:\dev\m2up\Game\Engine\Source\Programs\Shared\EpicGames.Oodle\EpicGames.Oodle.csproj

When using visual studio, it seems that it is detected that they don’t need to be built, and so are skipped, where they aren’t in Rider.

I was wondering whether you could provide context on this UBTProject dependency? In our project, I have removed it with the following change to VCProjectFileGenerator.cs, which has noticeably improved build times through rider and doesn’t seem to have any issues so far:

// Setup dependency on UnrealBuildTool, if we need that.  This makes sure that UnrealBuildTool is
// freshly compiled before kicking off any build operations on this target project
if (!CurProject.IsStubProject)
{
    List<ProjectFile> Dependencies = new List<ProjectFile>();
    if (CurProject.IsGeneratedProject && UBTProject != null && CurProject != UBTProject)
    {
       // M2_ENGINE_CHANGE_BEGIN
       // 26/87/2025 - Ben Naccarato - don't add the UBTProject dependency for the game uproject (this causes unnecessary extra files to be dragged in to builds when using Rider)
       // (Check that we have a target that points to a non-engine uproject) 
       if (CurProject.ProjectTargets.Any(t => t.UnrealProjectFilePath != null && !t.UnrealProjectFilePath.IsUnderDirectory(Unreal.EngineDirectory)))
       {
          Console.WriteLine(); // Add an extra line to ensure we're not on the same line as the e.g. "Writing project files... 99%"
          Console.WriteLine("Skipping UBT Project dependency for " + CurProject.ToString());
       }
       else
       {
          Dependencies.Add(UBTProject);
       }
       // M2_ENGINE_CHANGE_END
       Dependencies.AddRange(UBTProject.DependsOnProjects);
    }
    Dependencies.AddRange(CurProject.DependsOnProjects);

Steps to Reproduce
Have a C++ Unreal project, generate the sln file using `GenerateProjectFiles.bat`

Observe that inside the solution file, the game project contains a dependency on UnrealBuildTool, e.g.

Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MyProject", "Engine\Intermediate\ProjectFiles\M2Development.vcxproj", "{0E758EC9-BA36-3D62-994B-326C861BB9F4}"
ProjectSection(ProjectDependencies) = postProject
{7E468C9C-2CAF-3A25-AE9C-2199BEDEB41A} = {7E468C9C-2CAF-3A25-AE9C-2199BEDEB41A}
EndProjectSection
EndProject

Where we have:

Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnrealBuildTool", "Engine\Source\Programs\UnrealBuildTool\UnrealBuildTool.csproj", "{7E468C9C-2CAF-3A25-AE9C-2199BEDEB41A}"

When building with Rider, this dependency then causes a bunch of unnecessary extra projects to be built, e.g.

CONSOLE: Use build tool: C:\Program Files\Microsoft Visual Studio\2022\Professional\MSBuild\Current\Bin\MSBuild.exe
15:06:37 Building C:\dev\m2up\Game\Engine\Source\Programs\UnrealBuildTool\UnrealBuildTool.csproj
15:06:38 Building C:\dev\m2up\Game\Engine\Source\Programs\Shared\EpicGames.Build\EpicGames.Build.csproj
15:06:38 Building C:\dev\m2up\Game\Engine\Source\Programs\Shared\EpicGames.Core\EpicGames.Core.csproj
15:06:38 Building C:\dev\m2up\Game\Engine\Source\Programs\Shared\EpicGames.Horde\EpicGames.Horde.csproj
15:06:38 Building C:\dev\m2up\Game\Engine\Source\Programs\Shared\EpicGames.IoHash\EpicGames.IoHash.csproj
15:06:38 Building C:\dev\m2up\Game\Engine\Source\Programs\Shared\EpicGames.OIDC\EpicGames.OIDC.csproj
15:06:38 Building C:\dev\m2up\Game\Engine\Source\Programs\Shared\EpicGames.Serialization\EpicGames.Serialization.csproj
15:06:38 Building C:\dev\m2up\Game\Engine\Source\Programs\Shared\EpicGames.UBA\EpicGames.UBA.csproj
15:06:38 Building C:\dev\m2up\Game\Engine\Source\Programs\Shared\EpicGames.UHT\EpicGames.UHT.csproj
15:06:38 Building C:\dev\m2up\Game\Engine\Source\Programs\Shared\EpicGames.MsBuild\EpicGames.MsBuild.csproj
15:06:38 Building C:\dev\m2up\Game\Engine\Source\Programs\Shared\EpicGames.Oodle\EpicGames.Oodle.csproj
When using visual studio, it seems that it is detected that they don't need to be built, and so are skipped, where they aren't in Rider.

Hi Ben,

The UnrealBuildTool is Epic’s make-like tool that takes care of compiling the engine executable. As such it is a dependency of your project and must be properly compiled before building your project. Looking at the time stamps from the Rider log, it seems like nothing is built as they are within a 2 second timeframe. There is probably a cost to fire MSBuild and I’m guessing that VS might do a better job here. That being said, your team will run into problems if you remove the dependency in the projects. You are probably fine without it as UBT is already compiled on your system but I’m pretty sure this will be problematic with a new worskpace or when the engine version is updated.

Regards,

Martin

Thanks for getting back to me, Martin!

Yeah, seems like it’s slightly less consistent than I was originally thinking - rather than consistently being slower, it seems that sometimes it adds some extra output, which coincides with e.g. a build with a 1-line cpp change going from ~14s to ~30s

```

C:\Program Files\Microsoft Visual Studio\2022\Professional\MSBuild\Current\Bin\Roslyn\csc.exe /noconfig /unsafe+ /checked- /nowarn:1701,1702,1701,1702 /fullpaths … /analyzer:“C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.17\analyzers/dotnet/cs/System.Text.RegularExpressions.Generator.dll” AppContainer.cs ArrayExtensions.cs AssemblyUtils.cs AsyncEvent.cs … (some unreasonably long line which can’t fit in this comment)

EpicGames.Core -> C:\dev\m2up\Game\Engine\Source\Programs\Shared\EpicGames.Core\bin\Development\net8.0\EpicGames.Core.dll

```

(There’s one of these for each correpsonding `15:06:38 Building C:\dev\m2up\Game\Engine\Source\Programs\Shared\EpicGames.Core\EpicGames.Core.csproj` line)

Also, side-note, seems that when the sln file is auto-generated through UGS, deleting the sln file and then running a sync, instead of running `GenerateProjectFiles.bat`, the created solution file is considerably smaller. It doesn’t define a UnrealBuildTool, and doesn’t have the dependency. Would this solution still be expected to work?

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31314.256
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Engine", "Engine", "{233774A8-CC9D-3FA9-86D1-90573E92B704}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Games", "Games", "{DE1F8B53-6C02-3C13-9101-A7C8D96F3FF6}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UE5", "Engine\Intermediate\ProjectFiles\UE5.vcxproj", "{F2796131-D270-33F6-9035-AA9C90C6729D}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "M2Development", "Engine\Intermediate\ProjectFiles\M2Development.vcxproj", "{0E758EC9-BA36-3D62-994B-326C861BB9F4}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Visualizers", "Visualizers", "{1CCEC849-CC72-4C59-8C36-2F7C38706D4C}"
	ProjectSection(SolutionItems) = preProject
		Engine\Extras\VisualStudioDebugging\Unreal.natvis = Engine\Extras\VisualStudioDebugging\Unreal.natvis
		Engine\Extras\VisualStudioDebugging\Unreal.natstepfilter = Engine\Extras\VisualStudioDebugging\Unreal.natstepfilter
	EndProjectSection
EndProject
Global
...

I must backtrack a bit on my original answer. I didn’t think of the different batch files in Engine\Build\BatchFiles.. They are trying to compile UBT before invoking it of the UBT csproj is found. See Build.bat and BuildUBT.bat as reference.

There are likely some gains to not have UBT as a dependency in the project\engine solution since the batch files will also do a dependency check before using it. It really depends if you intend to debug UBT from the main solution. I personally prefer to do it from the UnrealBuildTool solution.

Thanks! Yeah, our two typical flows are using UGS or the GenerateProjectFiles.bat, which we confirmed both build the UnrealBuildTool if it is missing. So for the time being we’ll proceed with the UBT dependency for our project removed - if we do find issues later down the line as a result, we’ll let you know! (We are unlikely to need to debug UBT from the main solution)