You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
RootDirectory, EngineDirectory, UnrealBuildToolPath are now found in BuildUtilities' UnrealBuild namesapce. The way these are computed has changed. Previously, it was assumed that the application is UnrealBuildTool, and paths were constructed relative to that assembly. Now, the assumption is that the process is located under a "Engine/Build/DotNET" sub-path and paths are constructed relative to that. #jira none #ROBOMERGE-SOURCE: CL 16607440 in //UE5/Main/... #ROBOMERGE-BOT: STARSHIP (Main -> Release-Engine-Test) (v828-16531559) [CL 16607455 by jonathan adamczewski in ue5-release-engine-test branch]
183 lines
6.4 KiB
C#
183 lines
6.4 KiB
C#
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using EpicGames.Core;
|
|
using UnrealBuildBase;
|
|
|
|
namespace UnrealBuildTool
|
|
{
|
|
/// <summary>
|
|
/// Caches predefined state ("prelude") for compiler versions and options
|
|
/// </summary>
|
|
static class VCPreludeCache
|
|
{
|
|
/// <summary>
|
|
/// Set of options which can influence the prelude state. Any options matching entries in this set will be used to generate a separate prelude file.
|
|
/// </summary>
|
|
static HashSet<string> FilterArguments = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
|
{
|
|
"/EH", // Exception handling mode
|
|
"/GR", // RTTI settings
|
|
"/MD", // Multithreaded DLL runtime library
|
|
"/MDd", // Multithreaded debug DLL runtime library
|
|
"/MT", // Multithreaded static runtime library
|
|
"/MTd", // Multithreaded debug static runtime library
|
|
};
|
|
|
|
/// <summary>
|
|
/// Object used for ensuring only one thread can create items in the cache at once
|
|
/// </summary>
|
|
static object LockObject = new object();
|
|
|
|
/// <summary>
|
|
/// File containing a list of macros to be used to generate a prelude file
|
|
/// </summary>
|
|
static readonly FileReference MacroNamesFile = FileReference.Combine(UnrealBuild.EngineDirectory, "Build", "Windows", "PreludeMacros.txt");
|
|
|
|
/// <summary>
|
|
/// Base directory for the cache
|
|
/// </summary>
|
|
static readonly DirectoryReference PreludeCacheDir = DirectoryReference.Combine(UnrealBuild.EngineDirectory, "Saved", "UnrealBuildTool", "Prelude", "MSVC");
|
|
|
|
/// <summary>
|
|
/// The parsed list of macros
|
|
/// </summary>
|
|
static List<string> MacroNames = new List<string>();
|
|
|
|
/// <summary>
|
|
/// Path to the file used to generate prelude headers
|
|
/// </summary>
|
|
static FileReference? PreludeGeneratorFile;
|
|
|
|
/// <summary>
|
|
/// Cached mapping from compiler filename to its version string
|
|
/// </summary>
|
|
static Dictionary<FileReference, string> CompilerExeToVersion = new Dictionary<FileReference, string>();
|
|
|
|
/// <summary>
|
|
/// Get the prelude file (or create it) for the given compiler executable and set of options
|
|
/// </summary>
|
|
/// <param name="Compiler">Path to the compiler executable</param>
|
|
/// <param name="Arguments">Command line arguments for generating the prelude file</param>
|
|
/// <returns>Path to the prelude file</returns>
|
|
public static FileReference GetPreludeHeader(FileReference Compiler, List<string> Arguments)
|
|
{
|
|
// Cache the compiler version
|
|
string? CompilerVersion;
|
|
lock (CompilerExeToVersion)
|
|
{
|
|
if (!CompilerExeToVersion.TryGetValue(Compiler, out CompilerVersion))
|
|
{
|
|
FileVersionInfo VersionInfo = FileVersionInfo.GetVersionInfo(Compiler.FullName);
|
|
CompilerVersion = String.Format("{0} {1}", VersionInfo.ProductName, VersionInfo.ProductVersion);
|
|
}
|
|
}
|
|
|
|
// Cache the macro list
|
|
lock (MacroNames)
|
|
{
|
|
if (MacroNames.Count == 0)
|
|
{
|
|
string[] MacroListLines = FileReference.ReadAllLines(MacroNamesFile);
|
|
foreach (string MacroListLine in MacroListLines)
|
|
{
|
|
string MacroName = MacroListLine.Trim();
|
|
if (MacroName.Length > 0 && MacroName[0] != ';')
|
|
{
|
|
MacroNames.Add(MacroName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Create a digest from the command line
|
|
string CommandLine = String.Join(" ", Arguments.Where(x => FilterArguments.Contains(x)).OrderBy(x => x));
|
|
ContentHash Digest = ContentHash.SHA1(String.Format("{0}\n{1}\n{2}", CompilerVersion, CommandLine, String.Join("\n", MacroNames)));
|
|
|
|
// Get the prelude file
|
|
FileReference PreludeHeader = FileReference.Combine(PreludeCacheDir, String.Format("{0}.h", Digest));
|
|
if (!FileReference.Exists(PreludeHeader))
|
|
{
|
|
lock (LockObject)
|
|
{
|
|
if (!FileReference.Exists(PreludeHeader))
|
|
{
|
|
CreatePreludeHeader(PreludeHeader, Compiler, CompilerVersion, CommandLine);
|
|
}
|
|
}
|
|
}
|
|
return PreludeHeader;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a prelude header
|
|
/// </summary>
|
|
/// <param name="PreludeHeader">Path to the file to create</param>
|
|
/// <param name="Compiler">Path to the compiler</param>
|
|
/// <param name="CompilerVersion">Version number of the compiler</param>
|
|
/// <param name="CommandLine">Command line arguments used to generate the header</param>
|
|
static void CreatePreludeHeader(FileReference PreludeHeader, FileReference Compiler, string CompilerVersion, string CommandLine)
|
|
{
|
|
// Make sure the cache directory exists
|
|
DirectoryReference.CreateDirectory(PreludeCacheDir);
|
|
|
|
// Make sure the prelude generator file exists
|
|
if (PreludeGeneratorFile == null)
|
|
{
|
|
PreludeGeneratorFile = FileReference.Combine(PreludeCacheDir, "PreludeGenerator.cpp");
|
|
using (StreamWriter Writer = new StreamWriter(PreludeGeneratorFile.FullName))
|
|
{
|
|
Writer.WriteLine("#define STRINGIZE_2(x) #x");
|
|
Writer.WriteLine("#define STRINGIZE(x) STRINGIZE_2(x)");
|
|
foreach (string MacroName in MacroNames)
|
|
{
|
|
Writer.WriteLine("");
|
|
Writer.WriteLine("#ifdef {0}", MacroName);
|
|
Writer.WriteLine("#pragma message(\"#define {0} \" STRINGIZE({0}))", MacroName);
|
|
Writer.WriteLine("#endif");
|
|
}
|
|
}
|
|
}
|
|
|
|
// Invoke the compiler and capture the output
|
|
using (ManagedProcessGroup ProcessGroup = new ManagedProcessGroup())
|
|
{
|
|
string FullCommandLine = String.Format("{0} /nologo /c {1}", CommandLine, Utils.MakePathSafeToUseWithCommandLine(PreludeGeneratorFile.FullName));
|
|
using (ManagedProcess Process = new ManagedProcess(ProcessGroup, Compiler.FullName, FullCommandLine, PreludeCacheDir.FullName, null, null, ProcessPriorityClass.Normal))
|
|
{
|
|
// Filter the output
|
|
FileReference TempPreludeFile = new FileReference(PreludeHeader.FullName + ".temp");
|
|
using (StreamWriter Writer = new StreamWriter(TempPreludeFile.FullName))
|
|
{
|
|
Writer.WriteLine("// Compiler: {0}", CompilerVersion);
|
|
Writer.WriteLine("// Arguments: {0}", CommandLine);
|
|
Writer.WriteLine();
|
|
|
|
string? Line;
|
|
while (Process.TryReadLine(out Line))
|
|
{
|
|
Line = Line.Trim();
|
|
if (Line.Length > 0)
|
|
{
|
|
if (Line.StartsWith("#define", StringComparison.Ordinal))
|
|
{
|
|
Writer.WriteLine(Line);
|
|
}
|
|
else if (Line.Trim() != PreludeGeneratorFile.GetFileName())
|
|
{
|
|
throw new BuildException("Unexpected output from compiler: {0}", Line);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
FileReference.Move(TempPreludeFile, PreludeHeader);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|