summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeko-san2022-06-30 13:25:36 -0500
committerNeko-san2022-06-30 13:25:36 -0500
commitd6a99cd3ced52428c0bc3ac2020927801a5e67d3 (patch)
treec2a62e31be55f218648f9a68dd164cd1d99573e5
downloadaur-d6a99cd3ced52428c0bc3ac2020927801a5e67d3.tar.gz
Initilize repository for the Unreal Engine 4 AUR
-rw-r--r--.SRCINFO35
-rw-r--r--PKGBUILD154
-rw-r--r--ccache_executor.patch586
-rw-r--r--clang_path_fix.patch15
-rw-r--r--com.unrealengine.UE4Editor.desktop11
5 files changed, 801 insertions, 0 deletions
diff --git a/.SRCINFO b/.SRCINFO
new file mode 100644
index 000000000000..40d89fe228d3
--- /dev/null
+++ b/.SRCINFO
@@ -0,0 +1,35 @@
+pkgbase = unreal-engine-4
+ pkgdesc = A 3D game engine by Epic Games which can be used non-commercially for free.
+ pkgver = 4.27
+ pkgrel = 1
+ url = https://www.unrealengine.com/
+ arch = x86_64
+ arch = x86_64_v2
+ arch = x86_64_v3
+ arch = x86_64_v4
+ license = custom:UnrealEngine
+ makedepends = git
+ makedepends = openssh
+ depends = icu63
+ depends = sdl2
+ depends = python
+ depends = lld
+ depends = clang
+ depends = xdg-user-dirs
+ depends = dos2unix
+ optdepends = qt5-base: qmake build system for projects
+ optdepends = cmake: build system for projects
+ optdepends = qtcreator: IDE for projects
+ optdepends = codelite: IDE for projects
+ optdepends = kdevelop: IDE for projects
+ optdepends = clion: IDE for projects
+ options = !strip
+ options = staticlibs
+ source = com.unrealengine.UE4Editor.desktop
+ source = clang_path_fix.patch
+ source = ccache_executor.patch
+ sha256sums = 15e9f9d8dc8bd8513f6a5eca990e2aab21fd38724ad57d213b06a6610a951d58
+ sha256sums = 960c5a100e0c3732f3c73fb645d3989d39acf4576d74615bbef38ebeee008b90
+ sha256sums = 33982486f7fafac35a33dfa37c85cfba8543aa78b5fe13c395d9cccf691ef4b3
+
+pkgname = unreal-engine-4
diff --git a/PKGBUILD b/PKGBUILD
new file mode 100644
index 000000000000..ec1f36619885
--- /dev/null
+++ b/PKGBUILD
@@ -0,0 +1,154 @@
+# Maintainer: Neko-san <aur at mycat dot anonaddy dot me>
+
+# The source is about 200 MiB, with an extra ~11 GiB of dependencies downloaded in Setup.sh, and may take several hours to compile.
+# If you want to turn on additional patches there are switches below.
+pkgname=unreal-engine-4
+pkgver=4.27
+pkgrel=0
+pkgdesc='A 3D game engine by Epic Games which can be used non-commercially for free.'
+arch=('x86_64' 'x86_64_v2' 'x86_64_v3' 'x86_64_v4')
+url=https://www.unrealengine.com/
+makedepends=('git' 'openssh')
+depends=('icu63' 'sdl2' 'python' 'lld' 'clang' 'xdg-user-dirs' 'dos2unix')
+optdepends=('qt5-base: qmake build system for projects'
+ 'cmake: build system for projects'
+ 'qtcreator: IDE for projects'
+ 'codelite: IDE for projects'
+ 'kdevelop: IDE for projects'
+ 'clion: IDE for projects')
+license=('custom:UnrealEngine')
+source=('com.unrealengine.UE4Editor.desktop'
+ 'clang_path_fix.patch'
+ 'ccache_executor.patch')
+sha256sums=('15e9f9d8dc8bd8513f6a5eca990e2aab21fd38724ad57d213b06a6610a951d58'
+ '960c5a100e0c3732f3c73fb645d3989d39acf4576d74615bbef38ebeee008b90'
+ '33982486f7fafac35a33dfa37c85cfba8543aa78b5fe13c395d9cccf691ef4b3')
+# Not sure if compiling Unreal with LTO is legal? Lot's of different proprietary software goes into Unreal
+options=('!strip' 'staticlibs') # Package is 3 Gib smaller with "strip" but it takes a long time and generates many warnings
+
+_install_dir="opt/${pkgname}" # Default engine installation directory. Can be useful if you do not have a lot of space in /opt directory.
+_ccache_support=false # Patches for ccache. More optimizations might be needed?
+_WithDDC=false # Change this to true if you have a modern system and don't mind the extra packaging time (and size) to avoid compiling shaders on UE startup later; set to false by default for those with less robust systems
+
+## Courtesy of the original author of this patch from https://aur.archlinux.org/packages/unreal-engine
+## This patch is a bit more complex, so I'll try to maintain it, but don't be surprised if updates for this patch is not speedy
+if [[ ${_ccache_support} == true ]]
+then
+ depends+=(ccache)
+fi
+
+## Use this if you prefer opendoas; the benefit here is that doas won't time out on you if you wait too long to authenticate after compilation
+if [ -f /usr/bin/doas ] && [ -f /etc/doas.conf ]; then
+ PACMAN_AUTH=(doas)
+fi
+
+## This is for detecting your CPU architecture automatically; set to false if you want to enforce your own makepkg.conf file
+
+## Note: the resulting package will still be named containing "x86_64" unless the build was done with an "official" Arch distro for that architecture (like Arch ARM - [I don't advise using Arch ARM though])
+## or if you manage to trick your Arch installation to accept other architecture extensions by fiddling with the $CARCH variable and /etc/pacman.conf - this method has flaws, namely due to a bug:
+## it doesn't work with "makechrootpkg" - though, this PKGBUILD doesn't work in with this method anyway because of Github SSH Agent nonsense
+
+arch_auto=true
+
+if [[ ${arch_auto} == true ]]
+then
+ ## Architecture checks and compile flag adjustments - shellcheck throws a fit about the build function but it looks fine to me; checks for the highest available x64 support level and falls back to "native" if either not available
+ if test "$(/lib/ld-linux-x86-64.so.2 --help | grep -w '^ x86-64-v4' | cut -d ',' -f 1)" == ' x86-64-v4 (supported'; then
+ export CFLAGS="${CFLAGS} -march=x86-64-v4 -mtune=x86-64-v4 -O3 -pipe"
+ export CXXFLAGS="${CFLAGS} -Wp,-D_GLIBCXX_ASSERTIONS"
+ export LDFLAGS="-Wl,-O3,--sort-common,--as-needed,-z,relro,-z,now"
+ elif test "$(/lib/ld-linux-x86-64.so.2 --help | grep -w '^ x86-64-v3' | cut -d ',' -f 1)" == ' x86-64-v3 (supported'; then
+ export CFLAGS="${CFLAGS} -march=x86-64-v3 -mtune=x86-64-v3 -O3 -pipe"
+ export CXXFLAGS="${CFLAGS} -Wp,-D_GLIBCXX_ASSERTIONS"
+ export LDFLAGS="-Wl,-O3,--sort-common,--as-needed,-z,relro,-z,now"
+ elif test "$(/lib/ld-linux-x86-64.so.2 --help | grep -w '^ x86-64-v2' | cut -d ',' -f 1)" == ' x86-64-v2 (supported'; then
+ export CFLAGS="${CFLAGS} -march=x86-64-v2 -mtune=x86-64-v2 -O3 -pipe"
+ export CXXFLAGS="${CFLAGS} -Wp,-D_GLIBCXX_ASSERTIONS"
+ export LDFLAGS="-Wl,-O3,--sort-common,--as-needed,-z,relro,-z,now"
+ elif test "$(/lib/ld-linux-x86-64.so.2 --help | grep -w '^ x86_64 (AT_PLATFORM; supported' | cut -d ',' -f 1)" == ' x86_64 (AT_PLATFORM; supported'; then
+ export CFLAGS="${CFLAGS} -march=x86-64 -mtune=x86-64 -O3 -pipe"
+ export CXXFLAGS="${CFLAGS} -Wp,-D_GLIBCXX_ASSERTIONS"
+ export LDFLAGS="-Wl,-O3,--sort-common,--as-needed,-z,relro,-z,now"
+ else
+ export CFLAGS="${CFLAGS} -march=native -mtune=native -O3 -pipe"
+ export CXXFLAGS="${CFLAGS} -Wp,-D_GLIBCXX_ASSERTIONS"
+ export LDFLAGS="-Wl,-O3,--sort-common,--as-needed,-z,relro,-z,now"
+ fi
+fi
+
+prepare() {
+ # Check access to the repository
+ if ! git ls-remote git@github.com:EpicGames/UnrealEngine &>/dev/null
+ then
+ error 'You must register at unrealengine.com and link your github account to access this private repo. See the wiki for more info: https://wiki.archlinux.org/index.php/Unreal_Engine_4'
+ exit 1
+ fi
+
+ # Download Unreal Engine source or update if the folder exists
+ if [[ ! -d ${pkgname} ]]
+ then
+ git clone --depth=1 --branch=${pkgver}-release git@github.com:EpicGames/UnrealEngine ${pkgname}
+ cd ${pkgname}
+ else
+ cd ${pkgname}
+ rm -f .git/index.lock
+ git fetch --depth=1 origin tag ${pkgver}-release
+ git reset --hard ${pkgver}-release
+ fi
+
+ # Apply custom patches
+ patch -p1 -i "${srcdir}/clang_path_fix.patch" # Replace Windows specific search with the correct path (used for -mode=GenerateClangDatabase in UBT)
+ if [[ ${_ccache_support} == true ]]
+ then
+ patch -p1 -i "${srcdir}/ccache_executor.patch"
+ fi
+
+ # Qt Creator source code access
+ if [[ ! -d Engine/Plugins/Developer/QtCreatorSourceCodeAccess ]]
+ then
+ git -C Engine/Plugins/Developer clone --depth=1 git@github.com:fire/QtCreatorSourceCodeAccess
+ fi
+
+ # For some reason, despite this file explicitly asking not to be removed, it was removed from the UE5 source; it has to be re-added or the build will fail - this is the UE4 package, but this will remain in place in-case this occurs for UE4 branches
+ if [[ ! -f ${pkgname}/Engine/Source/ThirdParty/Linux/HaveLinuxDependencies ]]
+ then
+ mkdir -p ${pkgname}/Engine/Source/ThirdParty/Linux/
+ touch ${pkgname}/Engine/Source/ThirdParty/Linux/HaveLinuxDependencies
+ sed -i "1c\This file must have no extension so that GitDeps considers it a binary dependency - it will only be pulled by the Setup script if Linux is enabled. Please do not remove this file." ${pkgname}/Engine/Source/ThirdParty/Linux/HaveLinuxDependencies
+ fi
+
+ ./Setup.sh
+}
+
+build() {
+ cd ${pkgname}
+ if [[ ${_WithDDC} == true ]]; then
+ Engine/Build/BatchFiles/RunUAT.sh BuildGraph -target="Make Installed Build Linux" -script=Engine/Build/InstalledEngineBuild.xml -set:WithDDC=true -set:HostPlatformOnly=false -set:WithLinux=true -set:WithWin64=true -set:WithWin32=false -set:WithMac=false -set:WithAndroid=false -set:WithIOS=false -set:WithTVOS=false -set:WithLumin=false -set:WithHTML5=false
+ else
+ Engine/Build/BatchFiles/RunUAT.sh BuildGraph -target="Make Installed Build Linux" -script=Engine/Build/InstalledEngineBuild.xml -set:WithDDC=false -set:HostPlatformOnly=false -set:WithLinux=true -set:WithWin64=true -set:WithWin32=false -set:WithMac=false -set:WithAndroid=false -set:WithIOS=false -set:WithTVOS=false -set:WithLumin=false -set:WithHTML5=false
+ fi
+}
+
+package() {
+ # Desktop entry
+ if [[ "${_install_dir}" != "opt/${pkgname}" ]] # Set new path if dir changed
+ then
+ sed -i "5c\Path=/${_install_dir}/Engine/Binaries/Linux/" com.unrealengine.UE4Editor.desktop
+ sed -i "6c\Exec=/${_install_dir}/Engine/Binaries/Linux/UE4Editor %F" com.unrealengine.UE4Editor.desktop
+ fi
+ install -Dm775 com.unrealengine.UE4Editor.desktop "$pkgdir/usr/share/applications/com.unrealengine.UE4Editor.desktop"
+
+ cd ${pkgname}
+
+ # Icon for Desktop entry
+ install -Dm770 Engine/Source/Programs/UnrealVS/Resources/Preview.png "${pkgdir}/usr/share/pixmaps/ue4editor.png"
+
+ # License
+ install -Dm770 LICENSE.md "${pkgdir}/usr/share/licenses/UnrealEngine/LICENSE.md"
+
+ # Engine
+ ## Set to all permissions to prevent the engine from breaking itself; more elegant solutions might exist - suggest them if they can be automated here
+ ## Also, correct me if I package this improperly; I added Win64 support for the build in hopes of supporting cross-compilation
+ install -dm777 "${pkgdir}/${_install_dir}/Engine"
+ mv LocalBuilds/Engine/Linux/* "${pkgdir}/${_install_dir}"
+}
diff --git a/ccache_executor.patch b/ccache_executor.patch
new file mode 100644
index 000000000000..d652a9546683
--- /dev/null
+++ b/ccache_executor.patch
@@ -0,0 +1,586 @@
+diff --git a/Engine/Source/Programs/UnrealBuildTool/Configuration/BuildConfiguration.cs b/Engine/Source/Programs/UnrealBuildTool/Configuration/BuildConfiguration.cs
+index 0957ae99925..a20a95da3aa 100644
+--- a/Engine/Source/Programs/UnrealBuildTool/Configuration/BuildConfiguration.cs
++++ b/Engine/Source/Programs/UnrealBuildTool/Configuration/BuildConfiguration.cs
+@@ -61,6 +61,9 @@ namespace UnrealBuildTool
+ [CommandLine("-NoFASTBuild", Value = "false")]
+ public bool bAllowFASTBuild = true;
+
++ [XmlConfigFile] [CommandLine("-Noccache", Value = "false")]
++ public bool bAllowCCache = true;
++
+ /// <summary>
+ /// Whether SN-DBS may be used.
+ /// </summary>
+diff --git a/Engine/Source/Programs/UnrealBuildTool/Executors/Experimental/CCache.cs b/Engine/Source/Programs/UnrealBuildTool/Executors/Experimental/CCache.cs
+new file mode 100644
+index 00000000000..4f00dc80bbf
+--- /dev/null
++++ b/Engine/Source/Programs/UnrealBuildTool/Executors/Experimental/CCache.cs
+@@ -0,0 +1,74 @@
++using System.Collections.Generic;
++using System.Diagnostics;
++using Tools.DotNETCommon;
++
++namespace UnrealBuildTool
++{
++ class CCache : LocalExecutor
++ {
++ private readonly string ClangPath;
++ private readonly string CCachePath;
++
++ private string ClangCommand;
++ private string CompileCommand;
++
++ public CCache()
++ :base(0)
++ {
++ ClangPath = LinuxCommon.WhichClang();
++ CCachePath = LinuxCommon.Which("ccache");
++ }
++
++ public override string Name => "ccache";
++ public static bool IsAvailable()
++ {
++ if (BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Linux)
++ {
++ if (!string.IsNullOrEmpty(LinuxCommon.Which("ccache")))
++ return true;
++ }
++
++ return false;
++ }
++ public override bool ExecuteActions(List<Action> Actions, bool bLogDetailedActionStats)
++ {
++ Log.TraceInformation("Using CCache");
++ ClangCommand = ClangPath + " -fpch-preprocess -Xclang -fno-validate-pch ";
++
++ return base.ExecuteActions(Actions, bLogDetailedActionStats);
++ }
++
++ protected override void Run(Action Action)
++ {
++ switch (Action.ActionType)
++ {
++ case ActionType.Compile:
++ if (Action.StatusDescription.EndsWith(".ispc"))
++ CompileCommand = Action.CommandPath.ToString() + " " + Action.CommandArguments;
++ else
++ CompileCommand = ClangCommand + Action.CommandArguments;
++ ProcessStartInfo CcacheStartInfo = new ProcessStartInfo(CCachePath, CompileCommand);
++ CcacheStartInfo.UseShellExecute = false;
++ CcacheStartInfo.WorkingDirectory = Action.WorkingDirectory.FullName;
++ CcacheStartInfo.RedirectStandardError = true;
++ CcacheStartInfo.RedirectStandardOutput = true;
++
++ // Sloppiness Settings to try
++ // pch_defines,time_macros,file_stat_matches, file_stat_matches_ctime,include_file_ctime,include_file_mtime
++ CcacheStartInfo.EnvironmentVariables.Add("CCache_SLOPPINESS",
++ "pch_defines,modules,locale,time_macros");
++ base.Run(CcacheStartInfo, Action);
++ break;
++ case ActionType.Link:
++ case ActionType.WriteMetadata:
++ case ActionType.BuildProject:
++ base.Run(Action);
++ break;
++ default:
++ Log.TraceInformation("Action types not handled: {0}",
++ Action.ActionType.ToString());
++ break;
++ }
++ }
++ }
++}
+\ No newline at end of file
+diff --git a/Engine/Source/Programs/UnrealBuildTool/Executors/LocalExecutor.cs b/Engine/Source/Programs/UnrealBuildTool/Executors/LocalExecutor.cs
+index 8f4f153bd75..0636a29be10 100644
+--- a/Engine/Source/Programs/UnrealBuildTool/Executors/LocalExecutor.cs
++++ b/Engine/Source/Programs/UnrealBuildTool/Executors/LocalExecutor.cs
+@@ -63,6 +63,12 @@ namespace UnrealBuildTool
+ }
+
+
++ protected void ThreadFunc(ProcessStartInfo ActionStartInfo)
++ {
++ Action.StartTime = DateTimeOffset.Now;
++ ActionProgress(ActionStartInfo);
++ RunActionProcess(ActionStartInfo);
++ }
+ /// <summary>
+ /// The actual function to run in a thread. This is potentially long and blocking
+ /// </summary>
+@@ -81,9 +87,15 @@ namespace UnrealBuildTool
+ ActionStartInfo.RedirectStandardOutput = false;
+ ActionStartInfo.RedirectStandardError = false;
+
++ ActionProgress(ActionStartInfo);
++ RunActionProcess(ActionStartInfo);
++ // Try to launch the action's process, and produce a friendly error message if it fails.
++ }
++
++ private void ActionProgress(ProcessStartInfo ActionStartInfo)
++ {
+ // Log command-line used to execute task if debug info printing is enabled.
+ Log.TraceVerbose("Executing: {0} {1}", ActionStartInfo.FileName, ActionStartInfo.Arguments);
+-
+ // Log summary if wanted.
+ if (Action.bShouldOutputStatusDescription)
+ {
+@@ -97,68 +109,14 @@ namespace UnrealBuildTool
+ Log.TraceInformation("[{0}/{1}] {2} {3}", JobNumber, TotalJobs, CommandDescription, Action.StatusDescription);
+ }
+ }
+-
+- // Try to launch the action's process, and produce a friendly error message if it fails.
+- Process ActionProcess = null;
++ }
++
++ private void RunActionProcess(ProcessStartInfo ActionStartInfo)
++ {
++ Process ActionProcess = LaunchActionProcess(ActionStartInfo);
+ try
+ {
+- try
+- {
+- ActionProcess = new Process();
+- ActionProcess.StartInfo = ActionStartInfo;
+- ActionStartInfo.RedirectStandardOutput = true;
+- ActionStartInfo.RedirectStandardError = true;
+- ActionProcess.OutputDataReceived += new DataReceivedEventHandler(ActionDebugOutput);
+- ActionProcess.ErrorDataReceived += new DataReceivedEventHandler(ActionDebugOutput);
+- ActionProcess.Start();
+-
+- ActionProcess.BeginOutputReadLine();
+- ActionProcess.BeginErrorReadLine();
+- }
+- catch (Exception ex)
+- {
+- Log.TraceError("Failed to start local process for action: {0} {1}", Action.CommandPath, Action.CommandArguments);
+- Log.WriteException(ex, null);
+- ExitCode = 1;
+- bComplete = true;
+- return;
+- }
+-
+- // wait for process to start
+- // NOTE: this may or may not be necessary; seems to depend on whether the system UBT is running on start the process in a timely manner.
+- int checkIterations = 0;
+- bool haveConfiguredProcess = false;
+- do
+- {
+- if (ActionProcess.HasExited)
+- {
+- if (haveConfiguredProcess == false)
+- Debug.WriteLine("Process for action exited before able to configure!");
+- break;
+- }
+-
+- if (!haveConfiguredProcess)
+- {
+- try
+- {
+- ActionProcess.PriorityClass = ProcessPriorityClass.BelowNormal;
+- haveConfiguredProcess = true;
+- }
+- catch (Exception)
+- {
+- }
+- break;
+- }
+-
+- Thread.Sleep(10);
+-
+- checkIterations++;
+- } while (checkIterations < 100);
+- if (checkIterations == 100)
+- {
+- throw new BuildException("Failed to configure local process for action: {0} {1}", Action.CommandPath, Action.CommandArguments);
+- }
+-
++ //CheckIterations(ActionProcess); Might be needed for Local Executor. Doesn't seem to do anything
+ // block until it's complete
+ // @todo iosmerge: UBT had started looking at: if (Utils.IsValidProcess(Process))
+ // do we need to check that in the thread model?
+@@ -181,8 +139,79 @@ namespace UnrealBuildTool
+
+ // we are done!!
+ bComplete = true;
++
+ }
+
++ private void CheckIterations(Process ActionProcess)
++ {
++ // wait for process to start
++ // NOTE: this may or may not be necessary; seems to depend on whether the system UBT is running on start the process in a timely manner.
++ int checkIterations = 0;
++ bool haveConfiguredProcess = false;
++ do
++ {
++ if (ActionProcess.HasExited)
++ {
++ if (haveConfiguredProcess == false)
++ Debug.WriteLine("Process for action exited before able to configure!");
++ break;
++ }
++
++ if (!haveConfiguredProcess)
++ {
++ try
++ {
++ ActionProcess.PriorityClass = ProcessPriorityClass.BelowNormal;
++ haveConfiguredProcess = true;
++ }
++ catch (Exception)
++ {
++ }
++ break;
++ }
++
++ Thread.Sleep(10);
++
++ checkIterations++;
++ } while (checkIterations < 100);
++ if (checkIterations == 100)
++ {
++ throw new BuildException("Failed to configure local process for action: {0} {1}", Action.CommandPath, Action.CommandArguments);
++ }
++ }
++
++ private Process LaunchActionProcess(ProcessStartInfo ActionStartInfo)
++ {
++ Process ActionProcess = null;
++ try
++ {
++ ActionProcess = new Process();
++ ActionProcess.StartInfo = ActionStartInfo;
++ ActionStartInfo.RedirectStandardOutput = true;
++ ActionStartInfo.RedirectStandardError = true;
++ ActionProcess.OutputDataReceived += new DataReceivedEventHandler(ActionDebugOutput);
++ ActionProcess.ErrorDataReceived += new DataReceivedEventHandler(ActionDebugOutput);
++ ActionProcess.Start();
++
++ ActionProcess.BeginOutputReadLine();
++ ActionProcess.BeginErrorReadLine();
++ return ActionProcess;
++ }
++ catch (Exception ex)
++ {
++ Log.TraceError("Failed to start local process for action: {0} {1}", Action.CommandPath, Action.CommandArguments);
++ Log.WriteException(ex, null);
++ ExitCode = 1;
++ bComplete = true;
++ return ActionProcess;
++ }
++ }
++
++ public void Run(ProcessStartInfo ActionStartInfo)
++ {
++ Thread T = new Thread(() => ThreadFunc(ActionStartInfo));
++ T.Start();
++ }
+ /// <summary>
+ /// Starts a thread and runs the action in that thread
+ /// </summary>
+@@ -214,6 +243,10 @@ namespace UnrealBuildTool
+ /// </summary>
+ int NumParallelProcesses;
+
++ private int JobNumber;
++ private int TotalJobs;
++ private int ProgressValue;
++
+ /// <summary>
+ /// Constructor
+ /// </summary>
+@@ -304,43 +337,16 @@ namespace UnrealBuildTool
+ Log.TraceInformation("Performing {0} actions ({1} in parallel)", Actions.Count, NumParallelProcesses);
+
+ Dictionary<Action, ActionThread> ActionThreadDictionary = new Dictionary<Action, ActionThread>();
+- int JobNumber = 1;
++ JobNumber = 1;
++ TotalJobs = Actions.Count;
++ ProgressValue = 0;
+ using (ProgressWriter ProgressWriter = new ProgressWriter("Compiling C++ source code...", false))
+ {
+- int ProgressValue = 0;
+ while (true)
+ {
+- // Count the number of pending and still executing actions.
+- int NumUnexecutedActions = 0;
+ int NumExecutingActions = 0;
+- foreach (Action Action in Actions)
+- {
+- ActionThread ActionThread = null;
+- bool bFoundActionProcess = ActionThreadDictionary.TryGetValue(Action, out ActionThread);
+- if (bFoundActionProcess == false)
+- {
+- NumUnexecutedActions++;
+- }
+- else if (ActionThread != null)
+- {
+- if (ActionThread.bComplete == false)
+- {
+- NumUnexecutedActions++;
+- NumExecutingActions++;
+- }
+- }
+- }
+-
+- // Update the current progress
+- int NewProgressValue = Actions.Count + 1 - NumUnexecutedActions;
+- if (ProgressValue != NewProgressValue)
+- {
+- ProgressWriter.Write(ProgressValue, Actions.Count + 1);
+- ProgressValue = NewProgressValue;
+- }
+-
+ // If there aren't any pending actions left, we're done executing.
+- if (NumUnexecutedActions == 0)
++ if (ExecuteActionCount(Actions, ProgressWriter, ref NumExecutingActions))
+ {
+ break;
+ }
+@@ -350,65 +356,14 @@ namespace UnrealBuildTool
+ foreach (Action Action in Actions)
+ {
+ ActionThread ActionProcess = null;
+- bool bFoundActionProcess = ActionThreadDictionary.TryGetValue(Action, out ActionProcess);
+- if (bFoundActionProcess == false)
++ if (!FoundActionProcess(Action))
+ {
+ if (NumExecutingActions < Math.Max(1, NumParallelProcesses))
+ {
+- // Determine whether there are any prerequisites of the action that are outdated.
+- bool bHasOutdatedPrerequisites = false;
+- bool bHasFailedPrerequisites = false;
+- foreach (Action PrerequisiteAction in Action.PrerequisiteActions)
+- {
+- if (Actions.Contains(PrerequisiteAction))
+- {
+- ActionThread PrerequisiteProcess = null;
+- bool bFoundPrerequisiteProcess = ActionThreadDictionary.TryGetValue(PrerequisiteAction, out PrerequisiteProcess);
+- if (bFoundPrerequisiteProcess == true)
+- {
+- if (PrerequisiteProcess == null)
+- {
+- bHasFailedPrerequisites = true;
+- }
+- else if (PrerequisiteProcess.bComplete == false)
+- {
+- bHasOutdatedPrerequisites = true;
+- }
+- else if (PrerequisiteProcess.ExitCode != 0)
+- {
+- bHasFailedPrerequisites = true;
+- }
+- }
+- else
+- {
+- bHasOutdatedPrerequisites = true;
+- }
+- }
+- }
+-
+- // If there are any failed prerequisites of this action, don't execute it.
+- if (bHasFailedPrerequisites)
+- {
+- // Add a null entry in the dictionary for this action.
+- ActionThreadDictionary.Add(Action, null);
+- }
+ // If there aren't any outdated prerequisites of this action, execute it.
+- else if (!bHasOutdatedPrerequisites)
++ if (!ExecutePrerequisiteActions(Actions, Action))
+ {
+- ActionThread ActionThread = new ActionThread(Action, JobNumber, Actions.Count);
+- JobNumber++;
+-
+- try
+- {
+- ActionThread.Run();
+- }
+- catch (Exception ex)
+- {
+- throw new BuildException(ex, "Failed to start thread for action: {0} {1}\r\n{2}", Action.CommandPath, Action.CommandArguments, ex.ToString());
+- }
+-
+- ActionThreadDictionary.Add(Action, ActionThread);
+-
++ Run(Action);
+ NumExecutingActions++;
+ }
+ }
+@@ -512,5 +467,119 @@ namespace UnrealBuildTool
+
+ return bSuccess;
+ }
++
++ private ActionThread CreateActionThread(Action Action)
++ {
++ return new ActionThread(Action, JobNumber++, TotalJobs);
++ }
++ protected virtual void Run(ProcessStartInfo ProcessStartInfo, Action Action)
++ {
++ ActionThread ActionThread = CreateActionThread(Action);
++ try
++ {
++ ActionThread.Run(ProcessStartInfo);
++ }
++ catch (Exception ex)
++ {
++ throw new BuildException(ex, "Failed to start thread for action: {0} {1}\r\n{2}", Action.CommandPath, Action.CommandArguments, ex.ToString());
++ }
++ ActionThreadDictionary.Add(Action, ActionThread);
++ }
++ protected virtual void Run(Action Action)
++ {
++ ActionThread ActionThread = CreateActionThread(Action);
++ try
++ {
++ ActionThread.Run();
++ }
++ catch (Exception ex)
++ {
++ throw new BuildException(ex, "Failed to start thread for action: {0} {1}\r\n{2}", Action.CommandPath, Action.CommandArguments, ex.ToString());
++ }
++ ActionThreadDictionary.Add(Action, ActionThread);
++ }
++
++ private Dictionary<Action, ActionThread> ActionThreadDictionary = new Dictionary<Action, ActionThread>();
++ private bool FoundActionProcess(Action Action)
++ {
++ ActionThread ActionProcess = null;
++ return ActionThreadDictionary.TryGetValue(Action, out ActionProcess);
++ }
++
++ private bool ExecutePrerequisiteActions(List<Action> Actions, Action Action)
++ {
++ bool bHasOutdatedPrerequisites = false;
++ bool bHasFailedPrerequisites = false;
++ foreach (Action PrerequisiteAction in Action.PrerequisiteActions)
++ {
++ if (Actions.Contains(PrerequisiteAction))
++ {
++ ActionThread PrerequisiteProcess = null;
++ bool bFoundPrerequisiteProcess =
++ ActionThreadDictionary.TryGetValue(PrerequisiteAction,
++ out PrerequisiteProcess);
++ if (bFoundPrerequisiteProcess == true)
++ {
++ if (PrerequisiteProcess == null)
++ {
++ bHasFailedPrerequisites = true;
++ }
++ else if (PrerequisiteProcess.bComplete == false)
++ {
++ bHasOutdatedPrerequisites = true;
++ }
++ else if (PrerequisiteProcess.ExitCode != 0)
++ {
++ bHasFailedPrerequisites = true;
++ }
++ }
++ else
++ {
++ bHasOutdatedPrerequisites = true;
++ }
++ }
++ }
++
++
++ if (bHasFailedPrerequisites)
++ {
++ // Add a null entry in the dictionary for this action.
++ ActionThreadDictionary.Add(Action, null);
++ }
++
++ return bHasOutdatedPrerequisites;
++ }
++
++ private bool ExecuteActionCount(List<Action> Actions, ProgressWriter ProgressWriter, ref int NumExecutingActions)
++ {
++ int NumUnexecutedActions = 0;
++ foreach (Action Action in Actions)
++ {
++ ActionThread ActionThread = null;
++ bool bFoundActionProcess = ActionThreadDictionary.TryGetValue(Action, out ActionThread);
++ if (bFoundActionProcess == false)
++ {
++ NumUnexecutedActions++;
++ }
++ else if (ActionThread != null)
++ {
++ if (ActionThread.bComplete == false)
++ {
++ NumUnexecutedActions++;
++ NumExecutingActions++;
++ }
++ }
++ }
++
++ int NewProgressValue = TotalJobs + 1 - NumUnexecutedActions;
++ if (ProgressValue != NewProgressValue)
++ {
++ ProgressWriter.Write(ProgressValue, TotalJobs + 1);
++ ProgressValue = NewProgressValue;
++ }
++
++ // If there aren't any pending actions left, we're done executing.
++ return NumUnexecutedActions == 0;
++ }
+ };
+ }
+diff --git a/Engine/Source/Programs/UnrealBuildTool/System/ActionGraph.cs b/Engine/Source/Programs/UnrealBuildTool/System/ActionGraph.cs
+index a1cdcdad1ed..27725550c87 100644
+--- a/Engine/Source/Programs/UnrealBuildTool/System/ActionGraph.cs
++++ b/Engine/Source/Programs/UnrealBuildTool/System/ActionGraph.cs
+@@ -184,6 +184,10 @@ namespace UnrealBuildTool
+ {
+ Executor = new FASTBuild();
+ }
++ else if (BuildConfiguration.bAllowCCache && CCache.IsAvailable())
++ {
++ Executor = new CCache();
++ }
+ else if (BuildConfiguration.bAllowDistcc)
+ {
+ Executor = new Distcc();
+diff --git a/Engine/Source/Programs/UnrealBuildTool/ToolChain/UEToolChain.cs b/Engine/Source/Programs/UnrealBuildTool/ToolChain/UEToolChain.cs
+index 7f1baf9a147..fc7c9ae84cc 100644
+--- a/Engine/Source/Programs/UnrealBuildTool/ToolChain/UEToolChain.cs
++++ b/Engine/Source/Programs/UnrealBuildTool/ToolChain/UEToolChain.cs
+@@ -420,12 +420,10 @@ namespace UnrealBuildTool
+ }
+ }
+
+- // Build target triplet
+ Arguments.Add(String.Format("--target-os={0}", GetISPCOSTarget(CompileEnvironment.Platform)));
+ Arguments.Add(String.Format("--arch={0}", GetISPCArchTarget(CompileEnvironment.Platform, null)));
+ Arguments.Add(String.Format("--target={0}", TargetString));
+-
+- // PIC is needed for modular builds except on Windows
++
+ if ((CompileEnvironment.bIsBuildingDLL ||
+ CompileEnvironment.bIsBuildingLibrary) &&
+ !UEBuildPlatform.IsPlatformInGroup(CompileEnvironment.Platform, UnrealPlatformGroup.Windows))
+@@ -433,6 +431,8 @@ namespace UnrealBuildTool
+ Arguments.Add("--pic");
+ }
+
++ // PIC is needed for modular builds except on Windows
++
+ // Include paths. Don't use AddIncludePath() here, since it uses the full path and exceeds the max command line length.
+ // Because ISPC response files don't support white space in arguments, paths with white space need to be passed to the command line directly.
+ foreach (DirectoryReference IncludePath in CompileEnvironment.UserIncludePaths)
+diff --git a/Engine/Source/Programs/UnrealBuildTool/UnrealBuildTool.csproj b/Engine/Source/Programs/UnrealBuildTool/UnrealBuildTool.csproj
+index 2736ef225e2..453153cc0cc 100644
+--- a/Engine/Source/Programs/UnrealBuildTool/UnrealBuildTool.csproj
++++ b/Engine/Source/Programs/UnrealBuildTool/UnrealBuildTool.csproj
+@@ -142,6 +142,7 @@
+ </Choose>
+ <ItemGroup>
+ <Compile Include="Configuration\ModuleRulesContext.cs" />
++ <Compile Include="Executors\Experimental\CCache.cs" />
+ <Compile Include="Executors\HybridExecutor.cs" />
+ <Compile Include="Modes\BuildMode.cs" />
+ <Compile Include="Modes\CleanMode.cs" />
diff --git a/clang_path_fix.patch b/clang_path_fix.patch
new file mode 100644
index 000000000000..5e45cefcbf55
--- /dev/null
+++ b/clang_path_fix.patch
@@ -0,0 +1,15 @@
+diff --git a/Engine/Source/Programs/UnrealBuildTool/Modes/GenerateClangDatabase.cs b/Engine/Source/Programs/UnrealBuildTool/Modes/GenerateClangDatabase.cs
+index 66044e95b..5c62d17dd 100644
+--- a/Engine/Source/Programs/UnrealBuildTool/Modes/GenerateClangDatabase.cs
++++ b/Engine/Source/Programs/UnrealBuildTool/Modes/GenerateClangDatabase.cs
+@@ -63,8 +63,8 @@ namespace UnrealBuildTool
+ UEBuildTarget Target = UEBuildTarget.Create(TargetDescriptor, BuildConfiguration.bSkipRulesCompile, BuildConfiguration.bUsePrecompiled);
+
+ // Find the location of the compiler
+- VCEnvironment Environment = VCEnvironment.Create(WindowsCompiler.Clang, Target.Platform, Target.Rules.WindowsPlatform.Architecture, null, Target.Rules.WindowsPlatform.WindowsSdkVersion, null);
+- FileReference ClangPath = FileReference.Combine(Environment.CompilerDir, "bin", "clang++.exe");
++ //VCEnvironment Environment = VCEnvironment.Create(WindowsCompiler.Clang, Target.Platform, Target.Rules.WindowsPlatform.Architecture, null, Target.Rules.WindowsPlatform.WindowsSdkVersion, null);
++ FileReference ClangPath = new FileReference("/usr/bin/clang++");
+
+ // Convince each module to output its generated code include path
+ foreach (UEBuildBinary Binary in Target.Binaries)
diff --git a/com.unrealengine.UE4Editor.desktop b/com.unrealengine.UE4Editor.desktop
new file mode 100644
index 000000000000..d86cd555754d
--- /dev/null
+++ b/com.unrealengine.UE4Editor.desktop
@@ -0,0 +1,11 @@
+[Desktop Entry]
+Type=Application
+Name=Unreal Engine 4 Editor
+Comment=Create next-generation video games
+Path=/opt/unreal-engine/Engine/Binaries/Linux/
+Exec=/opt/unreal-engine/Engine/Binaries/Linux/UE4Editor %F
+MimeType=text/x-uproject
+Icon=ue4editor
+Terminal=false
+Categories=Development;
+