News & Blog

UE4 Coding: Speeding up Compilation

There was one thing that al­ways frus­trat­ed me alot in the be­gin­ning of de­vel­op­ment with Un­re­al En­gine 4: It was the com­pile times, es­pe­cial­ly those for it­er­at­ing on your game. But it turns out that, if you stick to a cou­ple of key prin­ci­ples, they are man­age­able af­ter all.

Dependencies

Com­pil­ing a sin­gle unit of code (~ a .h with .cpp file) is usu­al­ly not a prob­lem – al­though I will get in­to speed­ing that up in the next sec­tion. More prob­lem­at­ic is the sit­u­a­tion in which oth­er units have to be re­built, be­cause they de­pend on a unit you changed.

As de­scribed in one of the last blog posts, this can hap­pen with your main GameM­o­de class, as you tend to ei­ther have oth­er Ac­tors de­pend on it, or have it de­pend on a lot of Ac­tors im­por­tant for the game­l­og­ic. The key here is to get rid of these de­pen­den­cies, de­cou­pling the units from each oth­er, as de­scribed in that blog post.

An easy way to go about this for a giv­en unit, is to go through all your in­cludes to oth­er units and de­cide one by one, if there isn’t a way to re­move the de­pen­den­cy by in­stead us­ing a del­e­gate, or a more gen­er­al type: an “AAc­tor” in­stead of “AMySpe­cialAc­tor” for ex­am­ple. You are un­like­ly to ev­er change the Ac­tor unit, hence it is less like­ly that the unit has to be re­com­piled be­cause of an­oth­er change.

Includes

Sup­pose you did the above and have no more avoid­able de­pen­den­cies be­tween your units. Now when you change a file, ide­al­ly on­ly that file will be re­com­piled and linked against the rest, fi­nal­ly hot-reload­ing the mod­ule in case the ed­i­tor or game is run­ning.

This can still take a while, as of­ten, you will in­clude a cou­ple of head­ers of the en­gine that con­tain a lot of sym­bols (func­tions, types…) and in­clude oth­er en­gine head­ers that again con­tain a lot of sym­bols and in­clude oth­er files etc. The com­pil­er loads all of these sym­bols from all of these files.

Ob­vi­ous­ly the eas­i­est way to speed that up is to get an SSD :D But a cheap­er op­tion – or if you al­ready have one… I hope you do – is to re­move su­per­flu­ous in­cludes. It turns out that units gen­er­at­ed from the Un­re­al En­gine ed­i­tor (e.g. an Ac­tor class) will in­clude “CoreM­i­ni­mal.h”. While that sounds min­i­mal, it ac­tu­al­ly di­rect­ly in­cludes over 150 head­ers of which 99% you like­ly won’t even need. Or at least will be in­clud­ed in oth­er head­ers that you will use any­way.

My rec­om­men­da­tion is to re­move that in­clude di­rec­tive ev­ery­where and in­stead man­u­al­ly in­clude ex­act­ly those head­ers that you ac­tu­al­ly use.

Forward Declarations

There is a dif­fer­ence be­tween us­ing a type – and as a re­sult ac­tu­al­ly need­ing the head­er – or just need­ing to know that there is a type. For point­ers for ex­am­ple: as long as you don’t call a method on it, it is suf­fi­cient to know that the type ex­ists.

In the lat­ter case you don’t ac­tu­al­ly need the head­er, as you can in­stead just add a for­ward dec­la­ra­tion:

#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 in­clude ei­ther “Com­po­nents/SceneCom­po­nent.h” or “Com­po­nents/Stat­icMesh­Com­po­nent.h” or any of the head­ers for the oth­er types, be­cause we mere­ly re­quire point­ers to them. In the .cpp file ac­com­pa­ny­ing this “Sim­ple­Ac­tor.h” ex­am­ple head­er, we will prob­a­bly use both types and in­clude the head­ers there.

Why does this even make a dif­fer­ence, if you have to in­clude the head­ers in the cpp file any­ways?
If an­oth­er unit in­cludes Sim­ple­Ac­tor.h, it will al­so in­clude all of its in­cludes. But not the in­cludes of the cpp file. For the oth­er unit that is cur­rent­ly be­ing com­piled you can ex­plic­it­ly de­cide which types it needs to use and in­clude. The im­por­tant thing here is that you can al­so de­cide which are bet­ter left un­in­clud­ed to min­i­mal­ly speed up com­pi­la­tion a bit in­stead. But those lit­tle speedups ac­cu­mu­late.

(Note: As @f00n point­ed out on twit­ter, this is at least very sim­i­lar to In­clude what you use (IWYU) which the Un­re­al Build sys­tem can help you fol­low.)

Use Stock Unreal Engine

We start­ed out build­ing Un­re­al En­gine from source. This gave us the abil­i­ty to stick to a cer­tain ver­sion of UE4, merge in bug­fix­es be­fore they were re­leased and make our own mod­i­fi­ca­tions to the en­gine (which apart from a VR ren­der­ing op­ti­miza­tion ex­per­i­ment, we didn’t do any­way… and that didn’t work out, so we’re not even us­ing those changes).

In re­turn, though, we start­ed run­ning in­to prob­lems try­ing to use pre­built plug­ins, as they have the en­gine ver­sion stored in­side them and want to be re­built when us­ing non-of­fi­cial builds.
Ad­di­tion­al­ly, the “stick to a cer­tain ver­sion” ar­gu­ment is kin­da ob­so­let­ed by the fact that the launch­er al­lows you to in­stall mul­ti­ple ver­sions in par­al­lel.

And fi­nal­ly, cus­tom source builds come with two big is­sues: the in­ter­me­di­ate build files blow up to 160 GB on your hard­drive and you ev­ery once in a while ac­ci­den­tal­ly re­build the en­tire en­gine when you just meant to re­build the project (aka. 30 mins build time vs. just sec­onds to 5 mins).

Since we switched to Un­re­al En­gine from the launch­er, a lot of things got eas­i­er for us. And faster.

Discuss

Join the dis­cus­sion over on