UE4 Coding: Speeding up Compilation


There was one thing that always frustrated me alot in the beginning of development with Unreal Engine 4: It was the compile times, especially those for iterating on your game. But it turns out that, if you stick to a couple of key principles, they are manageable after all.

 

Dependencies

Compiling a single unit of code (~ a .h with .cpp file) is usually not a problem — although I will get into speeding that up in the next section. More problematic is the situation in which other units have to be rebuilt, because they depend on a unit you changed.

As described in one of the last blog posts, this can happen with your main GameMode class, as you tend to either have other Actors depend on it, or have it depend on a lot of Actors important for the gamelogic. The key here is to get rid of these dependencies, decoupling the units from each other, as described in that blog post.

An easy way to go about this for a given unit, is to go through all your includes to other units and decide one by one, if there isn’t a way to remove the dependency by instead using a delegate, or a more general type: an “AActor” instead of “AMySpecialActor” for example. You are unlikely to ever change the Actor unit, hence it is less likely that the unit has to be recompiled because of another change.

Includes

Suppose you did the above and have no more avoidable dependencies between your units. Now when you change a file, ideally only that file will be recompiled and linked against the rest, finally hot-reloading the module in case the editor or game is running.

This can still take a while, as often, you will include a couple of headers of the engine that contain a lot of symbols (functions, types…) and include other engine headers that again contain a lot of symbols and include other files etc. The compiler loads all of these symbols from all of these files.

Obviously the easiest way to speed that up is to get an SSD 😀 But a cheaper option — or if you already have one… I hope you do — is to remove superfluous includes. It turns out that units generated from the Unreal Engine editor (e.g. an Actor class) will include “CoreMinimal.h”. While that sounds minimal, it actually directly includes over 150 headers of which 99% you likely won’t even need. Or at least will be included in other headers that you will use anyway.

My recommendation is to remove that include directive everywhere and instead manually include exactly those headers that you actually use.

Forward Declarations

There is a difference between using a type — and as a result actually needing the header — or just needing to know that there is a type. For pointers for example: as long as you don’t call a method on it, it is sufficient to know that the type exists.

In the latter case you don’t actually need the header, as you can instead just add a forward declaration:

#pragma once

#include "GameFramework/Actor.h" // Using this, as we're deriving from AActor
#include "SimpleActor.generated.h"

/* Forward declarations */
class UStaticMeshComponent;
class USceneComponent;
class UClass;
class USoundsBase;

UCLASS()
class EXAMPLE_API ASimpleActor: public AActor {
 GENERATED_BODY()

public:
    UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
    USceneComponent* Root;

    UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
    UStaticMeshComponent* Mesh;

    UFUNCTION()
    UClass* SomeMadeupFunction(USoundBase* YouGetTheIdea);
};

As you can see, we don’t need to include either “Components/SceneComponent.h” or “Components/StaticMeshComponent.h” or any of the headers for the other types, because we merely require pointers to them. In the .cpp file accompanying this “SimpleActor.h” example header, we will probably use both types and include the headers there.

Why does this even make a difference, if you have to include the headers in the cpp file anyways?
If another unit includes SimpleActor.h, it will also include all of its includes. But not the includes of the cpp file. For the other unit that is currently being compiled you can explicitly decide which types it needs to use and include. The important thing here is that you can also decide which are better left unincluded to minimally speed up compilation a bit instead. But those little speedups accumulate.

(Note: As @f00n pointed out on twitter, this is at least very similar to Include what you use (IWYU) which the Unreal Build system can help you follow.)

Use Stock Unreal Engine

We started out building Unreal Engine from source. This gave us the ability to stick to a certain version of UE4, merge in bugfixes before they were released and make our own modifications to the engine (which apart from a VR rendering optimization experiment, we didn’t do anyway… and that didn’t work out, so we’re not even using those changes).

In return, though, we started running into problems trying to use prebuilt plugins, as they have the engine version stored inside them and want to be rebuilt when using non-official builds.
Additionally, the “stick to a certain version” argument is kinda obsoleted by the fact that the launcher allows you to install multiple versions in parallel.

And finally, custom source builds come with two big issues: the intermediate build files blow up to 160 GB on your harddrive and you every once in a while accidentally rebuild the entire engine when you just meant to rebuild the project (aka. 30 mins build time vs. just seconds to 5 mins).

Since we switched to Unreal Engine from the launcher, a lot of things got easier for us. And faster.

Discuss

Join the discussion over on

May 28th 2018 11:03 PM | by Squareys | posted in Coding, Unreal Engine 4