Skip to content
This repository was archived by the owner on May 3, 2021. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 23 additions & 17 deletions FASTBuild.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@
using System.IO;
using System.Diagnostics;
using System.Linq;
using Tools.DotNETCommon;

namespace UnrealBuildTool
{
public class FASTBuild : ActionExecutor
class FASTBuild : ActionExecutor
{
/*---- Configurable User settings ----*/

Expand All @@ -22,11 +23,11 @@ public class FASTBuild : ActionExecutor
private bool bEnableDistribution = true;

// Controls whether to use caching at all. CachePath and CacheMode are only relevant if this is enabled.
private bool bEnableCaching = false;
private bool bEnableCaching = true;

// Location of the shared cache, it could be a local or network path (i.e: @"\\DESKTOP-BEAST\FASTBuildCache").
// Only relevant if bEnableCaching is true;
private string CachePath = ""; //@"\\YourCacheFolderPath";
private string CachePath = @"\\YourCacheFolderPath";

public enum eCacheMode
{
Expand Down Expand Up @@ -60,6 +61,14 @@ public static bool IsAvailable()
fbuild = "fbuild.exe";
}

var integratedPath = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, @"..\Binaries\ThirdParty\FASTBuild", fbuild));
if (File.Exists(integratedPath))
{
FBuildExePathOverride = integratedPath;
Console.WriteLine($"Using integrated FBuild at {integratedPath}");
return true;
}

// Search the path for it
string PathVariable = Environment.GetEnvironmentVariable("PATH");
foreach (string SearchPath in PathVariable.Split(Path.PathSeparator))
Expand Down Expand Up @@ -130,13 +139,13 @@ private string GetCompilerName()
}

//Run FASTBuild on the list of actions. Relies on fbuild.exe being in the path.
public override bool ExecuteActions(List<Action> Actions)
public override bool ExecuteActions(List<Action> Actions, bool bLogDetailedActionStats)
{
bool FASTBuildResult = true;
if (Actions.Count > 0)
{
DetectBuildType(Actions);
string FASTBuildFilePath = Path.Combine(BuildConfiguration.BaseIntermediatePath, "fbuild.bff");
string FASTBuildFilePath = FileReference.Combine(UnrealBuildTool.EngineDirectory, "Intermediate", "Build", "fbuild.bff").FullName;
CreateBffFile(Actions, FASTBuildFilePath);
return ExecuteBffFile(FASTBuildFilePath);
}
Expand Down Expand Up @@ -444,7 +453,7 @@ private void WriteEnvironmentSetup()
{
// This may fail if the caller emptied PATH; we try to ignore the problem since
// it probably means we are building for another platform.
VCEnv = VCEnvironment.SetEnvironment(CPPTargetPlatform.Win64, false);
VCEnv = VCEnvironment.SetEnvironment(CppPlatform.Win64, WindowsCompiler.Default);
}
catch (Exception)
{
Expand All @@ -466,19 +475,20 @@ private void WriteEnvironmentSetup()
if (VCEnv != null)
{
AddText(string.Format(".VSBasePath = '{0}\\'\n", VCEnv.VSInstallDir));
AddText(string.Format(".VCBasePath = '{0}\\'\n", VCEnv.VCInstallDir));
AddText(string.Format(".WindowsSDKBasePath = '{0}'\n", VCEnv.WindowsSDKDir));

AddText("Compiler('UE4ResourceCompiler') \n{\n");
AddText("\t.Executable = '$WindowsSDKBasePath$/bin/x64/rc.exe'\n}\n\n");

AddText("Compiler('UE4Compiler') \n{\n");
AddText("\t.Root = '$VSBasePath$/VC/bin/amd64'\n");
AddText("\t.Root = '$VCBasePath$/bin/amd64'\n");
AddText("\t.Executable = '$Root$/cl.exe'\n");
AddText("\t.ExtraFiles =\n\t{\n");
AddText("\t\t'$Root$/c1.dll'\n");
AddText("\t\t'$Root$/c1xx.dll'\n");
AddText("\t\t'$Root$/c2.dll'\n");
string CompilerRoot = VCEnv.VSInstallDir + "/VC/bin/amd64/";
string CompilerRoot = VCEnv.VCInstallDir + "/bin/amd64/";
if (File.Exists(CompilerRoot + "1033/clui.dll")) //Check English first...
{
AddText("\t\t'$Root$/1033/clui.dll'\n");
Expand All @@ -496,22 +506,18 @@ private void WriteEnvironmentSetup()
AddText("\t\t'$Root$/mspdbcore.dll'\n");

string platformVersionNumber = "140";
if (WindowsPlatform.Compiler == WindowsCompiler.VisualStudio2013)
{
platformVersionNumber = "120";
}

/* Maybe not needed to compile anymore?
if(!WindowsPlatform.bUseWindowsSDK10)
AddText(string.Format("\t\t'$VSBasePath$/VC/redist/x64/Microsoft.VC{0}.CRT/msvcr{1}.dll'\n", platformVersionNumber, platformVersionNumber));
AddText(string.Format("\t\t'$VCBasePath$/redist/x64/Microsoft.VC{0}.CRT/msvcr{1}.dll'\n", platformVersionNumber, platformVersionNumber));
else
AddText("\t\t'$WindowsSDKBasePath$/Redist/ucrt/DLLs/x64/ucrtbase.dll'\n\n");
*/
AddText(string.Format("\t\t'$Root$/mspft{0}.dll'\n", platformVersionNumber));
AddText(string.Format("\t\t'$Root$/msobj{0}.dll'\n", platformVersionNumber));
AddText(string.Format("\t\t'$Root$/mspdb{0}.dll'\n", platformVersionNumber));
AddText(string.Format("\t\t'$VSBasePath$/VC/redist/x64/Microsoft.VC{0}.CRT/msvcp{1}.dll'\n", platformVersionNumber, platformVersionNumber));
AddText(string.Format("\t\t'$VSBasePath$/VC/redist/x64/Microsoft.VC{0}.CRT/vccorlib{1}.dll'\n", platformVersionNumber, platformVersionNumber));
AddText(string.Format("\t\t'$VCBasePath$/redist/x64/Microsoft.VC{0}.CRT/msvcp{1}.dll'\n", platformVersionNumber, platformVersionNumber));
AddText(string.Format("\t\t'$VCBasePath$/redist/x64/Microsoft.VC{0}.CRT/vccorlib{1}.dll'\n", platformVersionNumber, platformVersionNumber));
AddText("\t}\n"); //End extra files

AddText("}\n\n"); //End compiler
Expand Down Expand Up @@ -568,7 +574,7 @@ private void WriteEnvironmentSetup()
//Start Environment
AddText("\t.Environment = \n\t{\n");
if (VCEnv != null)
AddText("\t\t\"PATH=$VSBasePath$\\Common7\\IDE\\;$VSBasePath$\\VC\\bin\\\",\n");
AddText("\t\t\"PATH=$VSBasePath$\\Common7\\IDE\\;$VCBasePath$\\bin\\\",\n");
if (envVars.ContainsKey("TMP"))
AddText(string.Format("\t\t\"TMP={0}\",\n", envVars["TMP"]));
if (envVars.ContainsKey("SystemRoot"))
Expand Down Expand Up @@ -928,7 +934,7 @@ private bool ExecuteBffFile(string BffFilePath)
ProcessStartInfo FBStartInfo = new ProcessStartInfo(string.IsNullOrEmpty(FBuildExePathOverride) ? "fbuild" : FBuildExePathOverride, FBCommandLine);

FBStartInfo.UseShellExecute = false;
FBStartInfo.WorkingDirectory = Path.Combine(BuildConfiguration.RelativeEnginePath, "Source");
FBStartInfo.WorkingDirectory = FileReference.Combine(UnrealBuildTool.EngineDirectory, "Source").FullName;

try
{
Expand Down
12 changes: 3 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
# Unreal_FASTBuild
Allows the usage of FASTBuild with Unreal Engine 4 with a few minor modifications. It supports Visual Studio 2015 and the Windows 10 SDK and UE4 4.15, although you should be able to use this with previous versions of UE4 by looking at the history of the file.
Allows the usage of FASTBuild with Unreal Engine 4 with a few minor modifications.

To use, place the under Engine/Source/Programs/UnrealBuildTool/System/ and add to the UnrealBuildTool project or regenerate the projects. You can then call it from ExecuteActions() in ActionGraph.cs a similar manner to XGE, for 4.15 it will look something like it does in the gist here: https://gist.github.com/liamkf/9e8a660be117c85428054fe76dfd5eff
For engine version prior or equal to 4.15, please refer to the [4.15 Branch](https://github.com/hillin/Unreal_FASTBuild/tree/4.15).

It requires FBuild.exe to be in your path or modifying FBuildExePathOverride to point to where your FBuild executable is.

Building UE4 with VS2015 and Windows 10 may require some other minor fixes to compile, we ran into https://answers.unrealengine.com/questions/310966/vs2015-toolchain-blocked-by-errors-c3646.html and are using the modified Core.Build.cs as mentioned in the answer.

One example of the diffs and how to use it was made available here https://github.com/liamkf/Unreal_FASTBuild/issues/3 by Fire. Likewise following the steps here https://github.com/ClxS/FASTBuild-UE4 but using this version of the FASTBuild.cs file should also work.

There is also a few posts here http://knownshippable.com/blog/2017/03/07/fastbuild-with-unreal-engine-4-setup/ which may help people get setup with UE4, FASTBuild, as well as setting up distribution and caching.
For engine version 4.16, please refer to the [4.16 Branch](https://github.com/hillin/Unreal_FASTBuild/tree/4.16).
174 changes: 174 additions & 0 deletions integration-guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
FASTBuild is an open-source distributed build system, which could be a free alternative to Incredibuild. Unreal Engine 4 (UE4) does not support FASTBuild natively, however it's not hard to integrate it manually.

## Integrate FASTBuild with UE4

### Install FASTBuild
We assume you already have the full UE4 source code. First you'll need to grab the latest FASTBuild tools from [here](http://www.fastbuild.org/docs/home.html). We use v0.93 Windows x64 version in this tutorial. Download it and extract all the files. Here you have several choices:
- Place the files under any folder which could be found with your system's `PATH` environment variable. To see where these folders are, run the `PATH` command in a command prompt window;
- Place the files under the `Engine\Binaries\ThirdParty\FASTBuild` folder of your engine. This is the recommended place;
- Place the files anywhere you like. This is not recommended because you'll have to hard-code the path later.

### ActionExecutor
Then you'll need an `ActionExecutor`, which acts as a bridge between Unreal Build Tool (UBT) and FASTBuild. There is already one written by [liamkf](https://github.com/liamkf/Unreal_FASTBuild), I also forked it and made my own version, which contains bug fixes and improvements, as well as 4.16 support. In this tutorial, we will use this variant. You can get it [here](https://github.com/hillin/Unreal_FASTBuild).

The `ActionExeuctor` is simply a C# class. Download the file `FASTBuild.cs` and place it under the `Engine\Source\Programs\UnrealBuildTool\System` folder of your engine.

If you have placed your FASTBuild files in a random location, you can change the default value of `FBuildExePathOverride` in `FASTBuild.cs`.

### Modify UBT
The next step is to teach Unreal Build Tool how to use FASTBuild. This involves several modifications to the engine code. Add the lines with the plus sign before them to your engine's source code.

#### BuildConfiguration.cs
Location: *Engine\Source\Programs\UnrealBuildTool\Configuration\BuildConfiguration.cs*
```csharp
[XmlConfig]
public static bool bUseUHTMakefiles;

+ [XmlConfig]
+ public static bool bAllowFastbuild;

/// <summary>
/// Whether DMUCS/Distcc may be used.
/// </summary>
[XmlConfig]
public static bool bAllowDistcc;
```

#### UEBuildPlatform.cs
Location: *Engine\Source\Programs\UnrealBuildTool\Configuration\UEBuildPlatform.cs*
```csharp
public virtual bool CanUseDistcc()
{
return false;
}

+ public virtual bool CanUseFastbuild()
+ {
+ return false;
+ }

/// <summary>
/// If this platform can be compiled with SN-DBS
/// </summary>
public virtual bool CanUseSNDBS()
{
return false;
}
```
#### ActionGraph.cs
Location: *Engine\Source\Programs\UnrealBuildTool\System\ActionGraph.cs*
```csharp
if ((XGE.IsAvailable() && BuildConfiguration.bAllowXGE) || BuildConfiguration.bXGEExport)
{
Executor = new XGE();
}
+ else if (FASTBuild.IsAvailable() && BuildConfiguration.bAllowFastbuild)
+ {
+ Executor = new FASTBuild();
+ }
else if(BuildConfiguration.bAllowDistcc)
{
Executor = new Distcc();
}
```
#### UEBuildWindows.cs
Location: *Engine\Source\Programs\UnrealBuildTool\Windows\UEBuildWindows.cs*
```csharp
[XmlConfig]
public static bool bLogDetailedCompilerTimingInfo = false;

+ public override bool CanUseFastbuild()
+ {
+ return true;
+ }

/// True if we should use Clang/LLVM instead of MSVC to compile code on Windows platform
public static readonly bool bCompileWithClang = false;
```
That should be all. Your UE4 source code compilation will be handled by FASTBuild from now on.

## Unleash the Power of FASTBuild

### Setting up Network Distribution

[FASTBuild Documentation](http://www.fastbuild.org/docs/features/distribution.html) has fully covered this topic. Essentially, you'll need to:
- Have a shared folder which everyone in the intra-network can read and write
- Have the build machine (master) and all worker machines (slaves) set their `FASTBUILD_BROKERAGE_PATH` environment variable to the address of this shared folder. You can use the [`setx`](https://technet.microsoft.com/en-us/library/cc755104(v=ws.11).aspx) command or the [Advanced System Settings window](https://www.computerhope.com/issues/ch000549.htm) to do this.
- Run `FBuildWorker.exe` on all worker machines

I prefer to write a batch file so all team members can set this up in a double-click:
```bat
setx FASTBUILD_BROKERAGE_PATH "\\smellyriver\FASTBuild" :: set environment variable
reg add HKCU\Software\Microsoft\Windows\CurrentVersion\Run /v FASTBuildWorker /d FBuildWorker.exe :: start with windows
start FBuildWorker.exe :: run build worker
```

You can check the shared folder to see which worker machines are available.

### Enable Cached Mode

FASTBuild can cache built objects. As long as the corresponding source is not changed, FASTBuild can reuse the cached object, rather than compile it again. This brings a tremendous boost to compile speed.
You can either place the cache folder locally or in a network sharing place. Local cache has better performance (due to heavy IO), but network cache could be shared with your team, so team members could take advantage of others' build result.

To enable cache mode, you can either:
- set the `FASTBUILD_CACHE_PATH` environment variable to the path of your cache folder
- or, modify *FASTBuild.cs*:
```C#
private bool bEnableCaching = true; // enable caching
private string CachePath = @"\\YourCacheFolderPath"; // set cache folder path
```

## Troubleshooting

### Incredibuild is used over FASTBuild
If you have Incredibuild installed, it will have a higher priority over FASTBuild. You can turn off UE4's Incredibuild support by modifying `BuildConfiguration.xml`:
#### BuildConfiguration.xml
Location: *Engine\Saved\UnrealBuildTool\BuildConfiguration.xml*
```xml
<?xml version="1.0" encoding="utf-8" ?>
<Configuration xmlns="https://www.unrealengine.com/BuildConfiguration">
<BuildConfiguration>
+ <bAllowXGE>false</bAllowXGE>
</BuildConfiguration>
</Configuration>

```
### Issue with Windows 10 SDK
If you are using Windows 10 SDK, there could be some issues with the XInput library. Modify `Core.Build.cs` to fix this:
#### Core.Build.cs
Location: *Engine\Source\Runtime\Core\Core.Build.cs*
```csharp
- AddEngineThirdPartyPrivateStaticDependencies(Target,
- "IntelTBB",
- "XInput");

+ AddEngineThirdPartyPrivateStaticDependencies(Target,
+ "IntelTBB");

+ if (!WindowsPlatform.bUseWindowsSDK10)
+ {
+ AddEngineThirdPartyPrivateStaticDependencies(Target, "XInput");
+ }
+ else
+ {
+ PublicAdditionalLibraries.Add("XInput.lib"); //Included in Win10 SDK
+ }
```
### Warning C4628
The following warning could be raised during compilation:
```
warning C4628: digraphs not supported with -Ze. Character sequence '<:' not interpreted as alternate token for '['
```
You can suppress this warning by modifying `WindowsPlatformCompilerSetup.h`:
#### WindowsPlatformCompilerSetup.h
Location: *Engine\Source\Runtime\Core\Public\Windows\WindowsPlatformCompilerSetup*
```cpp
- #pragma warning(default : 4628) // digraphs not supported with -Ze. Character sequence 'digraph' not interpreted as alternate token for 'char'
+ #pragma warning(disable : 4628) // digraphs not supported with -Ze. Character sequence 'digraph' not interpreted as alternate token for 'char'
```
(i.e. change `default` to `disable`.)

## Further Reading
[FASTBuild Documentation](http://www.fastbuild.org/docs/documentation.html)

[Unreal_FASTBuild](https://github.com/liamkf/Unreal_FASTBuild)