Github Actions And Unreal
Introduction
I am learning more and more about Unreal Engine, and it is truly an astonishing piece of software. However, I couldn't shake the feeling that it conflicted with my approach to software development when it comes to build systems. I was making a concerted effort to integrate it with GitHub Actions, but the proposed solutions on the Internet seem absurd to me. Disclaimer: my case is not a regular Unreal one—I am not part of a AAA company using Perforce repos with a local build machine. I am trying to create a workflow for a source-available plugin for Unreal hosted on GitHub.
Attempts
I was required to create a Windows Dockerfile container with Unreal, but it kept failing during the build process. I eventually managed to build version 5.3.2 using the great helper tool ue4-docker. I learned that Unreal does not support building Windows builds from Linux, so I needed to learn about Windows Docker containers. It took some time, but eventually I was able to create an image that could be used for building a test Unreal project with our plugin. This was a solution that seemed to make sense, at least at that moment. Time passed, and Unreal released version 5.4, so I went back to update our build system. However, when I tried to build version 5.4.2 with the same command, it failed, citing a missing C++ toolchain:
Visual Studio 2022 is installed, but is missing the C++ toolchain. Please verify that the "MSVC v143 - VS 2022 C++ x64/x86 build tools (Latest)" component is selected in the Visual Studio 2022 installation options.
Total execution time: 13.78 seconds
UnrealBuildTool has banned the MSVC 14.39.33519-14.39.99999 toolchains due to compiler issues. Please install a different toolchain such as 14.38.33130 by opening the generated solution and installing recommended components or from the Visual Studio installer.
Took 13.88s to run dotnet.exe, ExitCode=6
I struggled with this issue for some time and tried to search for help, but without success.
I did get a response a few weeks later, but it would require applying specific patches to version 5.4.2. For me, it was a no-go since I wanted to build against the released version, not my own variation of it.
Of course, given enough time I could fix it, but thinking that if 5.5 comes along I would get another round of issues that do not appear locally made me sweat. The second issue with my first solution was that we basically had two build systems: one for Linux using images provided by Epic Games, and another with handcrafted Windows images built by us.
Dev Platform Support
Additionally, it feels as though the entire build system is designed with a Windows-oriented and centralized mindset. This makes introducing CI for a source-available project feel like fighting against the foundational principles of the Unreal build system. It doesn't help that I cannot cross-compile from Linux to Windows as I could with Unity. So the only solution that makes any sense to me for now is the usage of self-hosted runner with preinstalled Unreal.
The Route
The solutions that made sense for our case was:
- We have VM on AWS.
- Install and configure the Github Self Hosted Runner there.
- Install C++ toolchains. We went full Windows and installed toolchain for building Linux builds from Windows as well- this way it works.
- Clone Unreal Engine repo and build it there. I have saved path to it in Env variable
UNREAL_ENGINE_PATH
so I can do the same locally and test the build scripts on my local machine first. - For a faster builds installed Octobuild.
- Created build bash script that we run using git-bash on Windows.
- Simple Github Actions job that check if plugin code changed or any of the sample projects code changed and run builds accordingly.
The script is nothing complicated:
#!/bin/bash
buildType=${1:-"client"}
platform=${2:-"Win64"}
extraArg=""
if [ "$buildType" == "server" ]; then
extraArg="-server"
fi
unrealPath="${UNREAL_ENGINE_PATH}"
if [ -z "$UNREAL_ENGINE_PATH" ]; then
unrealPath="C:/Users/Administrator/Documents/Git/UnrealEngine/Engine"
fi
if command -v cygpath >/dev/null 2>&1; then
parentDirectory=$(cygpath -da "$(dirname "$0")")
else
parentDirectory=$(realpath "$0")
fi
archiveDir="${parentDirectory}/PackagedProject"
echo "Starting a $buildType build for $platform platform."
"${unrealPath}/Binaries/ThirdParty/DotNet/6.0.302/windows/dotnet.exe" \
"${unrealPath}/Binaries/DotNET/UnrealBuildTool/UnrealBuildTool.dll" \
-ProjectFiles -UsePrecompiled -Game "${parentDirectory}/PROJECT.uproject"
"${unrealPath}/Build/BatchFiles/RunUAT.bat" BuildCookRun -project="${parentDirectory}/PROJECT.uproject" \
-utf8output \
-platform="${platform}" \
"$extraArg" \
-noP4 -nodebuginfo -allmaps \
-cook -build -stage -prereqs -pak -archive \
-archivedirectory="${archiveDir}"
UEC
One more thing that I developed as a result of working on this build system is my own CLI tool for interacting with Unreal Engine: uec. It was and is useful for me since I was switching constantly between engine versions and I like to work with CLI instead of depending on Windows Explorer.
Ending notes
I am writing this not to say that Unreal Engine is garbage, because it is not. I am writing it to when you consider using Docker for building it you would know more and make sure that it would be your use case. With my newly aquired experience I would say if you are developing Unreal plugin or project using GitHub I would learn about GitHub Self Hosted Runners. For a start you can use your local machine as runner. I would not go Docker way unless you know that this is what you need.
Learn from my mistakes and make new ones.
This work is licensed under CC BY-NC-SA 4.0.
Piotr Siuszko @Mev Lyshkin
GameDev tool engineer, C#/C++ at day, Rust at night.