// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.Collections.Generic; using System.Text.RegularExpressions; using EpicGames.Core; using Microsoft.Extensions.Logging; using UnrealBuildBase; namespace UnrealBuildTool { abstract class UEToolChain { protected readonly ILogger Logger; public UEToolChain(ILogger InLogger) { Logger = InLogger; } public virtual void SetEnvironmentVariables() { } public virtual void GetVersionInfo(List Lines) { } public virtual void GetExternalDependencies(HashSet ExternalDependencies) { } public static DirectoryReference GetModuleInterfaceDir(DirectoryReference OutputDir) { return DirectoryReference.Combine(OutputDir, "Ifc"); } // Return the path to the cpp compiler that will be used by this toolchain. public virtual FileReference? GetCppCompilerPath() { return null; } public abstract CPPOutput CompileCPPFiles(CppCompileEnvironment CompileEnvironment, List InputFiles, DirectoryReference OutputDir, string ModuleName, IActionGraphBuilder Graph); public virtual CPPOutput CompileRCFiles(CppCompileEnvironment Environment, List InputFiles, DirectoryReference OutputDir, IActionGraphBuilder Graph) { CPPOutput Result = new CPPOutput(); return Result; } public virtual CPPOutput CompileISPCFiles(CppCompileEnvironment Environment, List InputFiles, DirectoryReference OutputDir, IActionGraphBuilder Graph) { CPPOutput Result = new CPPOutput(); return Result; } public virtual CPPOutput GenerateISPCHeaders(CppCompileEnvironment Environment, List InputFiles, DirectoryReference OutputDir, IActionGraphBuilder Graph) { CPPOutput Result = new CPPOutput(); return Result; } public virtual void GenerateTypeLibraryHeader(CppCompileEnvironment CompileEnvironment, ModuleRules.TypeLibrary TypeLibrary, FileReference OutputFile, IActionGraphBuilder Graph) { throw new NotSupportedException("This platform does not support type libraries."); } public abstract FileItem? LinkFiles(LinkEnvironment LinkEnvironment, bool bBuildImportLibraryOnly, IActionGraphBuilder Graph); public virtual FileItem[] LinkAllFiles(LinkEnvironment LinkEnvironment, bool bBuildImportLibraryOnly, IActionGraphBuilder Graph) { FileItem? LinkFile = LinkFiles(LinkEnvironment, bBuildImportLibraryOnly, Graph); return LinkFile != null ? new FileItem[] { LinkFile } : new FileItem[] { }; } /// /// Get the name of the response file for the current linker environment and output file /// /// /// /// public static FileReference GetResponseFileName(LinkEnvironment LinkEnvironment, FileItem OutputFile) { // Construct a relative path for the intermediate response file return FileReference.Combine(LinkEnvironment.IntermediateDirectory!, OutputFile.Location.GetFileName() + ".response"); } public virtual ICollection PostBuild(FileItem Executable, LinkEnvironment ExecutableLinkEnvironment, IActionGraphBuilder Graph) { return new List(); } public virtual void SetUpGlobalEnvironment(ReadOnlyTargetRules Target) { } public virtual void ModifyBuildProducts(ReadOnlyTargetRules Target, UEBuildBinary Binary, List Libraries, List BundleResources, Dictionary BuildProducts) { } public virtual void ModifyTargetReceipt(TargetReceipt Receipt) { } public virtual void FinalizeOutput(ReadOnlyTargetRules Target, TargetMakefileBuilder MakefileBuilder) { } public virtual void PrepareRuntimeDependencies(List RuntimeDependencies, Dictionary TargetFileToSourceFile, DirectoryReference ExeDir) { } /// /// Adds a build product and its associated debug file to a receipt. /// /// Build product to add /// The type of build product public virtual bool ShouldAddDebugFileToReceipt(FileReference OutputFile, BuildProductType OutputType) { return true; } public virtual FileReference GetDebugFile(FileReference OutputFile, string DebugExtension) { // by default, just change the extension to the debug extension return OutputFile.ChangeExtension(DebugExtension); } public virtual void SetupBundleDependencies(List Binaries, string GameName) { } public virtual string GetSDKVersion() { return "Not Applicable"; } /// /// Runs the provided tool and argument. Returns the output, using a rexex capture if one is provided /// /// Full path to the tool to run /// Argument that will be passed to the tool /// null, or a Regular expression to capture in the output /// protected string? RunToolAndCaptureOutput(FileReference Command, string ToolArg, string? Expression = null) { string ProcessOutput = Utils.RunLocalProcessAndReturnStdOut(Command.FullName, ToolArg, Logger); if (string.IsNullOrEmpty(Expression)) { return ProcessOutput; } Match M = Regex.Match(ProcessOutput, Expression); return M.Success ? M.Groups[1].ToString() : null; } /// /// Runs the provided tool and argument and parses the output to retrieve the version /// /// Full path to the tool to run /// Argument that will result in the version string being shown (it's ok this is a byproduct of a command that returns an error) /// Regular expression to capture the version. By default we look for four integers separated by periods, with the last two optional /// public Version RunToolAndCaptureVersion(FileReference Command, string VersionArg, string VersionExpression = @"(\d+\.\d+(\.\d+)?(\.\d+)?)") { string? ProcessOutput = RunToolAndCaptureOutput(Command, VersionArg, VersionExpression); Version? ToolVersion; if (Version.TryParse(ProcessOutput, out ToolVersion)) { return ToolVersion; } Logger.LogWarning("Unable to retrieve version from {Command} {Arg}", Command, VersionArg); return new Version(0, 0); } }; }