The following requires a source-built Unreal Engine 4, launcher builds won’t work.

Ever wanted to improve linking times by x10? What you need is incremental linking!

Incremental linking as the name suggests only links files that have changed since the last time linking was done, which in my particular case means that 2766 source files are spared and only the few I’ve changed get linked.
This for me results in 1.4 seconds spent on linking on average versus a whopping 14 seconds for a full relink of everything.

So why isn’t this the default? Turns out when Live Coding got integrated into the engine in 4.22, a linker flag named /FUNCTIONPADMIN got added which is mutually exclusive with incremental linking. Fear not though, all it takes is some planning and one line of change in engine source!

First, the code change: find the following line in your VCToolChain.cs under Engine\Source\Programs\UnrealBuildTool\Platform\Windows\

if (!bBuildImportLibraryOnly && Target.WindowsPlatform.bCreateHotpatchableImage)

Replace it with this:

if (!bBuildImportLibraryOnly && Target.WindowsPlatform.bCreateHotpatchableImage && !LinkEnvironment.bUseIncrementalLinking)

That’s all the engine changes you need. I’ve also made a PR for this as I don’t see why anyone shouldn’t have access to it: https://github.com/EpicGames/UnrealEngine/pull/7412
Next, open your project’s <project>.Target.cs and put this in it:

bUseIncrementalLinking = true;

This enables incremental linking in your game module. For me this is fine, since I only use Live Coding in the editor, never in a packaged/cooked/non-editor build.
Next, disable it in editor builds by adding this to your <project>Editor.Target.cs:

bUseIncrementalLinking = false;

You could of course disable Live Coding entirely by not adding this last line at all but to me LC in editor builds and incremental linking everywhere else strikes a fine balance.
Next, let’s measure the time linking takes! Find this line in your VCToolChain.cs:

Arguments.Add("/INCREMENTAL");

Add this right below it:

Arguments.Add("/verbose:incr");
Arguments.Add("/time");

Note that your engine might already have Arguments.Add(“/verbose:incr”);
The first line makes Visual Studio report on the incremental linking process while the second line makes it output the actual times taken. Output looks similar to this:

1>  LINK : 0 new modules and 1 (out of 2766) modules have changed since prior linking
1>  IncrPass2: Interval #1, time = 0.328s
1>    Wait PDB close: Total time = 0.000s
1>  IncrPass2: Interval #2, time = 0.907s
1>  Final: Total time = 1.235s

That 1.235s for 2766 source files is on a rusty old i7-4770k by the way. It takes around 14 seconds without incremental linking so the optimization is well worth it.

Finally, there’s one more flag you can set in your <project>.Target.cs to cut down on link times even further:

bUseFastPDBLinking = true;

Beware though as there’s currently a bug in Visual Studio 16.7.xxx that will make the Watch and Locals windows in debug mode react very slowly the first time you view them – the bug is supposedly fixed in 16.8 Preview so I would hold off on enabling bUseFastPDBLinking until 16.8 is out.

 

Published

Comments

No Comments

Leave a Reply