/// <summary> /// Constructor /// </summary> public HybridExecutor() { this.LocalExecutor = new ParallelExecutor(); this.RemoteExecutor = new XGE(); XmlConfig.ApplyTo(this); if (MaxLocalActions == 0) { MaxLocalActions = Utils.GetPhysicalProcessorCount(); } }
/// <summary> /// Execute this command /// </summary> /// <param name="Arguments">Command line arguments</param> /// <returns>Exit code (always zero)</returns> public override int Execute(CommandLineArguments Arguments) { Arguments.ApplyTo(this); List <TargetDescriptor> TargetDescriptors = TargetDescriptor.ParseCommandLine(Arguments, false, false); foreach (TargetDescriptor TargetDescriptor in TargetDescriptors) { // Create the target UEBuildTarget Target = UEBuildTarget.Create(TargetDescriptor, false, false); // Get the output file FileReference OutputFile = TargetDescriptor.AdditionalArguments.GetFileReferenceOrDefault("-OutputFile=", null); if (OutputFile == null) { OutputFile = Target.ReceiptFileName.ChangeExtension(".json"); } // Execute code generation actions if (bExecCodeGenActions) { using (ISourceFileWorkingSet WorkingSet = new EmptySourceFileWorkingSet()) { // Create the build configuration object, and read the settings BuildConfiguration BuildConfiguration = new BuildConfiguration(); XmlConfig.ApplyTo(BuildConfiguration); Arguments.ApplyTo(BuildConfiguration); // Create the makefile const bool bIsAssemblingBuild = true; TargetMakefile Makefile = Target.Build(BuildConfiguration, WorkingSet, bIsAssemblingBuild, TargetDescriptor.SingleFileToCompile); ActionGraph.Link(Makefile.Actions); // Filter all the actions to execute HashSet <FileItem> PrerequisiteItems = new HashSet <FileItem>(Makefile.Actions.SelectMany(x => x.ProducedItems).Where(x => x.HasExtension(".h") || x.HasExtension(".cpp"))); List <Action> PrerequisiteActions = ActionGraph.GatherPrerequisiteActions(Makefile.Actions, PrerequisiteItems); // Execute these actions if (PrerequisiteActions.Count > 0) { Log.TraceInformation("Exeucting actions that produce source files..."); ActionGraph.ExecuteActions(BuildConfiguration, PrerequisiteActions); } } } // Write the output file Log.TraceInformation("Writing {0}...", OutputFile); Target.ExportJson(OutputFile); } return(0); }
/// <summary> /// Gets the default compiler which should be used, if it's not set explicitly by the target, command line, or config file. /// </summary> /// <returns>The default compiler version</returns> internal static WindowsCompiler GetDefaultCompiler() { // If there's no specific compiler set, try to pick the matching compiler for the selected IDE object ProjectFormatObject; if (XmlConfig.TryGetValue(typeof(VCProjectFileGenerator), "Version", out ProjectFormatObject)) { VCProjectFileFormat ProjectFormat = (VCProjectFileFormat)ProjectFormatObject; if (ProjectFormat == VCProjectFileFormat.VisualStudio2017) { return(WindowsCompiler.VisualStudio2017); } else if (ProjectFormat == VCProjectFileFormat.VisualStudio2015) { return(WindowsCompiler.VisualStudio2015); } } // Second, default based on what's installed, test for 2017 first DirectoryReference VCInstallDir; if (TryGetVCInstallDir(WindowsCompiler.VisualStudio2017, out VCInstallDir)) { return(WindowsCompiler.VisualStudio2017); } if (TryGetVCInstallDir(WindowsCompiler.VisualStudio2015, out VCInstallDir)) { return(WindowsCompiler.VisualStudio2015); } // If we do have a Visual Studio installation, but we're missing just the C++ parts, warn about that. DirectoryReference VSInstallDir; if (TryGetVSInstallDir(WindowsCompiler.VisualStudio2015, out VSInstallDir)) { Log.TraceWarning("Visual Studio 2015 is installed, but is missing the C++ toolchain. Please verify that \"Common Tools for Visual C++ 2015\" are selected from the Visual Studio 2015 installation options."); } else if (TryGetVSInstallDir(WindowsCompiler.VisualStudio2017, out VSInstallDir)) { Log.TraceWarning("Visual Studio 2017 is installed, but is missing the C++ toolchain. Please verify that the \"VC++ 2017 toolset\" component is selected in the Visual Studio 2017 installation options."); } else { Log.TraceWarning("No Visual C++ installation was found. Please download and install Visual Studio 2015 with C++ components."); } // Finally, default to VS2015 anyway return(WindowsCompiler.VisualStudio2015); }
/// <summary> /// Initialize UBT in the context of another host process (presumably UAT) /// </summary> /// <param name="bIsEngineInstalled">Whether the engine is installed</param> /// <returns>True if initialization was successful</returns> public static bool Initialize(bool bIsEngineInstalled) { UnrealBuildTool.SetIsEngineInstalled(bIsEngineInstalled); // Read the XML configuration files if (!XmlConfig.ReadConfigFiles()) { return(false); } // Register all the platform classes UnrealBuildTool.RegisterAllUBTClasses(SDKOutputLevel.Quiet, false); return(true); }
/// <summary> /// Constructor /// </summary> /// <param name="MaxLocalActions">How many actions to execute in parallel. When 0 a default will be chosen based on system resources</param> public LocalExecutor(int MaxLocalActions = 0) { XmlConfig.ApplyTo(this); // if specified this caps how many processors we can use if (MaxLocalActions > 0) { NumParallelProcesses = MaxLocalActions; } else { // Figure out how many processors to use NumParallelProcesses = GetMaxActionsToExecuteInParallel(); } }
/// <summary> /// Constructor /// </summary> /// <param name="MaxLocalActions">How many actions to execute in parallel</param> public ParallelExecutor(int MaxLocalActions) { XmlConfig.ApplyTo(this); // if specified this caps how many processors we can use if (MaxLocalActions > 0) { NumParallelProcesses = MaxLocalActions; } else { // Figure out how many processors to use NumParallelProcesses = Math.Min((int)(Environment.ProcessorCount * ProcessorCountMultiplier), MaxProcessorCount); } }
/// <summary> /// Default constructor /// </summary> /// <param name="InOnlyGameProject">The single project to generate project files for, or null</param> /// <param name="InProjectFileFormat">Override the project file format to use</param> /// <param name="InOverrideCompiler">Override the compiler version to use</param> public VCProjectFileGenerator(FileReference InOnlyGameProject, VCProjectFileFormat InProjectFileFormat, WindowsCompiler InOverrideCompiler) : base(InOnlyGameProject) { XmlConfig.ApplyTo(this); if (InProjectFileFormat != VCProjectFileFormat.Default) { ProjectFileFormat = InProjectFileFormat; } if (InOverrideCompiler == WindowsCompiler.VisualStudio2015) { BuildToolOverride = "-2015"; } else if (InOverrideCompiler == WindowsCompiler.VisualStudio2017) { BuildToolOverride = "-2017"; } }
/// <summary> /// Default constructor /// </summary> /// <param name="InOnlyGameProject">The single project to generate project files for, or null</param> /// <param name="InProjectFileFormat">Override the project file format to use</param> /// <param name="InArguments">Additional command line arguments</param> public VCProjectFileGenerator(FileReference InOnlyGameProject, VCProjectFileFormat InProjectFileFormat, CommandLineArguments InArguments) : base(InOnlyGameProject) { XmlConfig.ApplyTo(this); if (InProjectFileFormat != VCProjectFileFormat.Default) { ProjectFileFormat = InProjectFileFormat; } if (InArguments.HasOption("-2015")) { BuildToolOverride = "-2015"; } else if (InArguments.HasOption("-2017")) { BuildToolOverride = "-2017"; } else if (InArguments.HasOption("-2019")) { BuildToolOverride = "-2019"; } }
/// <summary> /// Execute the mode /// </summary> /// <param name="Arguments">Command line arguments</param> /// <returns></returns> public override int Execute(CommandLineArguments Arguments) { Arguments.ApplyTo(this); // Create the build configuration object, and read the settings BuildConfiguration BuildConfiguration = new BuildConfiguration(); XmlConfig.ApplyTo(BuildConfiguration); Arguments.ApplyTo(BuildConfiguration); // Ensure the path to the output file is valid if (OutputFile == null) { OutputFile = GetDefaultOutputFile(ProjectFile); } // Create the rules assembly RulesAssembly Assembly; if (ProjectFile != null) { Assembly = RulesCompiler.CreateProjectRulesAssembly(ProjectFile, BuildConfiguration.bUsePrecompiled, BuildConfiguration.bSkipRulesCompile); } else if (DirectoryReference.Exists(UnrealBuildTool.EnterpriseDirectory)) { Assembly = RulesCompiler.CreateEnterpriseRulesAssembly(BuildConfiguration.bUsePrecompiled, BuildConfiguration.bSkipRulesCompile); } else { Assembly = RulesCompiler.CreateEngineRulesAssembly(BuildConfiguration.bUsePrecompiled, BuildConfiguration.bSkipRulesCompile); } // Write information about these targets WriteTargetInfo(ProjectFile, Assembly, OutputFile, Arguments); Log.TraceInformation("Written {0}", OutputFile); return(0); }
/// <summary> /// Entry point for this command /// </summary> /// <returns></returns> public override int Execute(CommandLineArguments Arguments) { Arguments.ApplyTo(this); Arguments.CheckAllArgumentsUsed(); switch (Type) { case DocumentationType.BuildConfiguration: XmlConfig.WriteDocumentation(OutputFile); break; case DocumentationType.ModuleRules: RulesDocumentation.WriteDocumentation(typeof(ModuleRules), OutputFile); break; case DocumentationType.TargetRules: RulesDocumentation.WriteDocumentation(typeof(TargetRules), OutputFile); break; default: throw new BuildException("Invalid documentation type: {0}", Type); } return(0); }
/// <summary> /// Default constructor. Reads settings from the XmlConfig files. /// </summary> public BuildConfiguration() { XmlConfig.ApplyTo(this); }
/// <summary> /// Main entry point /// </summary> /// <param name="Arguments">Command-line arguments</param> /// <returns>One of the values of ECompilationResult</returns> public override int Execute(CommandLineArguments Arguments) { Arguments.ApplyTo(this); // Initialize the log system, buffering the output until we can create the log file StartupTraceListener StartupListener = new StartupTraceListener(); Trace.Listeners.Add(StartupListener); // Write the command line Log.TraceLog("Command line: {0}", Environment.CommandLine); // Grab the environment. UnrealBuildTool.InitialEnvironment = Environment.GetEnvironmentVariables(); if (UnrealBuildTool.InitialEnvironment.Count < 1) { throw new BuildException("Environment could not be read"); } // Read the XML configuration files XmlConfig.ApplyTo(this); // Fixup the log path if it wasn't overridden by a config file if (BaseLogFileName == null) { BaseLogFileName = FileReference.Combine(UnrealBuildTool.EngineProgramSavedDirectory, "UnrealBuildTool", "Log.txt").FullName; } // Create the log file, and flush the startup listener to it if (!Arguments.HasOption("-NoLog") && !Log.HasFileWriter()) { FileReference LogFile = new FileReference(BaseLogFileName); foreach (string LogSuffix in Arguments.GetValues("-LogSuffix=")) { LogFile = LogFile.ChangeExtension(null) + "_" + LogSuffix + LogFile.GetExtension(); } TextWriterTraceListener LogTraceListener = Log.AddFileWriter("DefaultLogTraceListener", LogFile); StartupListener.CopyTo(LogTraceListener); } Trace.Listeners.Remove(StartupListener); // Create the build configuration object, and read the settings BuildConfiguration BuildConfiguration = new BuildConfiguration(); XmlConfig.ApplyTo(BuildConfiguration); Arguments.ApplyTo(BuildConfiguration); // Check the root path length isn't too long if (BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Win64 && UnrealBuildTool.RootDirectory.FullName.Length > BuildConfiguration.MaxRootPathLength) { Log.TraceWarning("Running from a path with a long directory name (\"{0}\" = {1} characters). Root paths shorter than {2} characters are recommended to avoid exceeding maximum path lengths on Windows.", UnrealBuildTool.RootDirectory, UnrealBuildTool.RootDirectory.FullName.Length, BuildConfiguration.MaxRootPathLength); } // now that we know the available platforms, we can delete other platforms' junk. if we're only building specific modules from the editor, don't touch anything else (it may be in use). if (!bIgnoreJunk && !UnrealBuildTool.IsEngineInstalled()) { using (Timeline.ScopeEvent("DeleteJunk()")) { JunkDeleter.DeleteJunk(); } } // Parse and build the targets try { List <TargetDescriptor> TargetDescriptors; // Parse all the target descriptors using (Timeline.ScopeEvent("TargetDescriptor.ParseCommandLine()")) { TargetDescriptors = TargetDescriptor.ParseCommandLine(Arguments, BuildConfiguration.bUsePrecompiled, BuildConfiguration.bSkipRulesCompile); } // Hack for specific files compile; don't build the ShaderCompileWorker target that's added to the command line for generated project files if (TargetDescriptors.Count >= 2) { TargetDescriptors.RemoveAll(x => (x.Name == "ShaderCompileWorker" || x.Name == "LiveCodingConsole") && x.SpecificFilesToCompile.Count > 0); } // Handle remote builds for (int Idx = 0; Idx < TargetDescriptors.Count; ++Idx) { TargetDescriptor TargetDesc = TargetDescriptors[Idx]; if (RemoteMac.HandlesTargetPlatform(TargetDesc.Platform)) { FileReference BaseLogFile = Log.OutputFile ?? new FileReference(BaseLogFileName); FileReference RemoteLogFile = FileReference.Combine(BaseLogFile.Directory, BaseLogFile.GetFileNameWithoutExtension() + "_Remote.txt"); RemoteMac RemoteMac = new RemoteMac(TargetDesc.ProjectFile); if (!RemoteMac.Build(TargetDesc, RemoteLogFile, bSkipPreBuildTargets)) { return((int)CompilationResult.Unknown); } TargetDescriptors.RemoveAt(Idx--); } } // Handle local builds if (TargetDescriptors.Count > 0) { // Get a set of all the project directories HashSet <DirectoryReference> ProjectDirs = new HashSet <DirectoryReference>(); foreach (TargetDescriptor TargetDesc in TargetDescriptors) { if (TargetDesc.ProjectFile != null) { DirectoryReference ProjectDirectory = TargetDesc.ProjectFile.Directory; FileMetadataPrefetch.QueueProjectDirectory(ProjectDirectory); ProjectDirs.Add(ProjectDirectory); } } // Get all the build options BuildOptions Options = BuildOptions.None; if (bSkipBuild) { Options |= BuildOptions.SkipBuild; } if (bXGEExport) { Options |= BuildOptions.XGEExport; } if (bNoEngineChanges) { Options |= BuildOptions.NoEngineChanges; } // Create the working set provider per group. using (ISourceFileWorkingSet WorkingSet = SourceFileWorkingSet.Create(UnrealBuildTool.RootDirectory, ProjectDirs)) { Build(TargetDescriptors, BuildConfiguration, WorkingSet, Options, WriteOutdatedActionsFile, bSkipPreBuildTargets); } } } finally { // Save all the caches SourceFileMetadataCache.SaveAll(); CppDependencyCache.SaveAll(); } return(0); }
public LocalExecutor() { XmlConfig.ApplyTo(this); }
public Distcc() { XmlConfig.ApplyTo(this); // The default for normal Mac users should be to use DistCode which installs as an Xcode plugin and provides dynamic host management if (BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac) { string UserDir = Environment.GetEnvironmentVariable("HOME"); string MacDistccExecutablesPath = UserDir + "/Library/Application Support/Developer/Shared/Xcode/Plug-ins/Distcc 3.2.xcplugin/Contents/usr/bin"; // But we should use the standard Posix directory when not installed - a build farm would use a static .dmucs hosts file not DistCode. if (System.IO.Directory.Exists(MacDistccExecutablesPath)) { DistccExecutablesPath = MacDistccExecutablesPath; } if (System.IO.File.Exists(UserDir + "/Library/Preferences/com.marksatt.DistCode.plist")) { using (System.Diagnostics.Process DefaultsProcess = new System.Diagnostics.Process()) { try { DefaultsProcess.StartInfo.FileName = "/usr/bin/defaults"; DefaultsProcess.StartInfo.CreateNoWindow = true; DefaultsProcess.StartInfo.UseShellExecute = false; DefaultsProcess.StartInfo.RedirectStandardOutput = true; DefaultsProcess.StartInfo.RedirectStandardError = true; DefaultsProcess.StartInfo.Arguments = "read com.marksatt.DistCode DistProp"; DefaultsProcess.Start(); string Output = DefaultsProcess.StandardOutput.ReadToEnd(); DefaultsProcess.WaitForExit(); if (DefaultsProcess.ExitCode == 0) { DMUCSDistProp = Output; } } catch (Exception) { } } using (System.Diagnostics.Process CoordModeProcess = new System.Diagnostics.Process()) { using (System.Diagnostics.Process DefaultsProcess = new System.Diagnostics.Process()) { try { CoordModeProcess.StartInfo.FileName = "/usr/bin/defaults"; CoordModeProcess.StartInfo.CreateNoWindow = true; CoordModeProcess.StartInfo.UseShellExecute = false; CoordModeProcess.StartInfo.RedirectStandardOutput = true; CoordModeProcess.StartInfo.RedirectStandardError = true; CoordModeProcess.StartInfo.Arguments = "read com.marksatt.DistCode CoordinatorMode"; CoordModeProcess.Start(); string CoordModeProcessOutput = CoordModeProcess.StandardOutput.ReadToEnd(); CoordModeProcess.WaitForExit(); if (CoordModeProcess.ExitCode == 0 && CoordModeProcessOutput.StartsWith("1")) { DefaultsProcess.StartInfo.FileName = "/usr/bin/defaults"; DefaultsProcess.StartInfo.CreateNoWindow = true; DefaultsProcess.StartInfo.UseShellExecute = false; DefaultsProcess.StartInfo.RedirectStandardOutput = true; DefaultsProcess.StartInfo.RedirectStandardError = true; DefaultsProcess.StartInfo.Arguments = "read com.marksatt.DistCode CoordinatorIP"; DefaultsProcess.Start(); string Output = DefaultsProcess.StandardOutput.ReadToEnd(); DefaultsProcess.WaitForExit(); if (DefaultsProcess.ExitCode == 0) { DMUCSCoordinator = Output; } } } catch (Exception) { } } } } } }
/// <summary> /// Constructor /// </summary> public LinuxTargetRules() { XmlConfig.ApplyTo(this); }
/// <summary> /// Execute the tool mode /// </summary> /// <param name="Arguments">Command line arguments</param> /// <returns>Exit code</returns> public override int Execute(CommandLineArguments Arguments) { // Apply any command line arguments to this class Arguments.ApplyTo(this); // Apply the XML config to this class XmlConfig.ApplyTo(this); // Parse rocket-specific arguments. FileReference ProjectFile; TryParseProjectFileArgument(Arguments, out ProjectFile); // If there aren't any formats set, read the default project file format from the config file if (ProjectFileFormats.Count == 0) { // Read from the XML config if (!String.IsNullOrEmpty(ProjectFileGeneratorSettings.Format)) { ProjectFileFormats.UnionWith(ProjectFileGeneratorSettings.ParseFormatList(ProjectFileGeneratorSettings.Format)); } // Read from the editor config ProjectFileFormat PreferredSourceCodeAccessor; if (ProjectFileGenerator.GetPreferredSourceCodeAccessor(ProjectFile, out PreferredSourceCodeAccessor)) { ProjectFileFormats.Add(PreferredSourceCodeAccessor); } // If there's still nothing set, get the default project file format for this platform if (ProjectFileFormats.Count == 0) { ProjectFileFormats.UnionWith(BuildHostPlatform.Current.GetDefaultProjectFileFormats()); } } // Register all the platform project generators PlatformProjectGeneratorCollection PlatformProjectGenerators = new PlatformProjectGeneratorCollection(); foreach (Type CheckType in Assembly.GetExecutingAssembly().GetTypes()) { if (CheckType.IsClass && !CheckType.IsAbstract && CheckType.IsSubclassOf(typeof(PlatformProjectGenerator))) { PlatformProjectGenerator Generator = (PlatformProjectGenerator)Activator.CreateInstance(CheckType, Arguments); foreach (UnrealTargetPlatform Platform in Generator.GetPlatforms()) { if (DisablePlatformProjectGenerators == null || !DisablePlatformProjectGenerators.Any(x => x.Equals(Platform.ToString(), StringComparison.OrdinalIgnoreCase))) { Log.TraceVerbose("Registering project generator {0} for {1}", CheckType, Platform); PlatformProjectGenerators.RegisterPlatformProjectGenerator(Platform, Generator); } } } } // Create each project generator and run it List <ProjectFileGenerator> Generators = new List <ProjectFileGenerator>(); foreach (ProjectFileFormat ProjectFileFormat in ProjectFileFormats.Distinct()) { ProjectFileGenerator Generator; switch (ProjectFileFormat) { case ProjectFileFormat.Make: Generator = new MakefileGenerator(ProjectFile); break; case ProjectFileFormat.CMake: Generator = new CMakefileGenerator(ProjectFile); break; case ProjectFileFormat.QMake: Generator = new QMakefileGenerator(ProjectFile); break; case ProjectFileFormat.KDevelop: Generator = new KDevelopGenerator(ProjectFile); break; case ProjectFileFormat.CodeLite: Generator = new CodeLiteGenerator(ProjectFile, Arguments); break; case ProjectFileFormat.VisualStudio: Generator = new VCProjectFileGenerator(ProjectFile, VCProjectFileFormat.Default, Arguments); break; case ProjectFileFormat.VisualStudio2012: Generator = new VCProjectFileGenerator(ProjectFile, VCProjectFileFormat.VisualStudio2012, Arguments); break; case ProjectFileFormat.VisualStudio2013: Generator = new VCProjectFileGenerator(ProjectFile, VCProjectFileFormat.VisualStudio2013, Arguments); break; case ProjectFileFormat.VisualStudio2015: Generator = new VCProjectFileGenerator(ProjectFile, VCProjectFileFormat.VisualStudio2015, Arguments); break; case ProjectFileFormat.VisualStudio2017: Generator = new VCProjectFileGenerator(ProjectFile, VCProjectFileFormat.VisualStudio2017, Arguments); break; case ProjectFileFormat.VisualStudio2019: Generator = new VCProjectFileGenerator(ProjectFile, VCProjectFileFormat.VisualStudio2019, Arguments); break; case ProjectFileFormat.XCode: Generator = new XcodeProjectFileGenerator(ProjectFile, Arguments); break; case ProjectFileFormat.Eddie: Generator = new EddieProjectFileGenerator(ProjectFile); break; case ProjectFileFormat.VisualStudioCode: Generator = new VSCodeProjectFileGenerator(ProjectFile); break; case ProjectFileFormat.CLion: Generator = new CLionGenerator(ProjectFile); break; case ProjectFileFormat.VisualStudioMac: Generator = new VCMacProjectFileGenerator(ProjectFile, Arguments); break; default: throw new BuildException("Unhandled project file type '{0}", ProjectFileFormat); } Generators.Add(Generator); } // Check there are no superfluous command line arguments // TODO (still pass raw arguments below) // Arguments.CheckAllArgumentsUsed(); // Now generate project files ProjectFileGenerator.bGenerateProjectFiles = true; foreach (ProjectFileGenerator Generator in Generators) { if (!Generator.GenerateProjectFiles(PlatformProjectGenerators, Arguments.GetRawArray())) { return((int)CompilationResult.OtherCompilationError); } } return((int)CompilationResult.Succeeded); }
/// <summary> /// /// </summary> /// <param name="ProjectFile"></param> /// <param name="Executable"></param> /// <param name="StageDirectory"></param> /// <param name="PlatformType"></param> public static void GenerateAssetCatalog(FileReference ProjectFile, string Executable, string StageDirectory, UnrealTargetPlatform PlatformType) { // Initialize the toolchain. IOSProjectSettings ProjectSettings = ((IOSPlatform)UEBuildPlatform.GetBuildPlatform(PlatformType)).ReadProjectSettings(null); IOSToolChain ToolChain = new IOSToolChain(ProjectFile, ProjectSettings); // Determine whether the user has modified icons that require a remote Mac to build. CppPlatform Platform = PlatformType == UnrealTargetPlatform.IOS ? CppPlatform.IOS : CppPlatform.TVOS; bool bUserImagesExist = false; ToolChain.GenerateAssetCatalog(Platform, ref bUserImagesExist); // Don't attempt to do anything remotely if the user is using the default UE4 images. if (!bUserImagesExist) { return; } // Also don't attempt to use a remote Mac if packaging for TVOS on PC. if (Platform == CppPlatform.TVOS && BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac) { return; } // Save off the current bUseRPCUtil setting to restore at the end of this function. // At this time, iPhonePackager needs to be called with bUseRPCUtil == true. bool bSaveUseRPCUtil = RemoteToolChain.bUseRPCUtil; // Initialize the remote calling environment, taking into account the user's SSH setting. ToolChain.SetUpGlobalEnvironment(false); // Build the asset catalog ActionGraph. ActionGraph ActionGraph = new ActionGraph(); List <FileItem> OutputFiles = new List <FileItem>(); ToolChain.CompileAssetCatalog(FileItem.GetItemByPath(Executable), Platform, ActionGraph, OutputFiles); ActionGraph.FinalizeActionGraph(); // I'm not sure how to derive the UE4Game and Development arguments programmatically. string[] Arguments = new string[] { "UE4Game", (PlatformType == UnrealTargetPlatform.IOS ? "IOS" : "TVOS"), "Development", "-UniqueBuildEnvironment" }; // Perform all of the setup necessary to actually execute the ActionGraph instance. ReadOnlyBuildVersion Version = new ReadOnlyBuildVersion(BuildVersion.ReadDefault()); List <string[]> TargetSettings = new List <string[]>(); TargetSettings.Add(Arguments); var Targets = new List <UEBuildTarget>(); Dictionary <UEBuildTarget, CPPHeaders> TargetToHeaders = new Dictionary <UEBuildTarget, CPPHeaders>(); List <TargetDescriptor> TargetDescs = new List <TargetDescriptor>(); foreach (string[] TargetSetting in TargetSettings) { TargetDescs.AddRange(TargetDescriptor.ParseCommandLine(TargetSetting, ref ProjectFile)); } foreach (TargetDescriptor TargetDesc in TargetDescs) { UEBuildTarget Target = UEBuildTarget.CreateTarget(TargetDesc, Arguments, false, Version); if (Target == null) { continue; } Targets.Add(Target); TargetToHeaders.Add(Target, null); } bool bIsRemoteCompile = BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac; // Create the build configuration object, and read the settings BuildConfiguration BuildConfiguration = new BuildConfiguration(); XmlConfig.ApplyTo(BuildConfiguration); CommandLine.ParseArguments(Arguments, BuildConfiguration); BuildConfiguration.bUseUBTMakefiles = false; Action[] PrerequisiteActions; { HashSet <Action> PrerequisiteActionsSet = new HashSet <Action>(); foreach (FileItem OutputFile in OutputFiles) { ActionGraph.GatherPrerequisiteActions(OutputFile, ref PrerequisiteActionsSet); } PrerequisiteActions = PrerequisiteActionsSet.ToArray(); } // Copy any asset catalog files to the remote Mac, if necessary. foreach (UEBuildTarget Target in Targets) { UEBuildPlatform.GetBuildPlatform(Target.Platform).PreBuildSync(); } // Begin execution of the ActionGraph. Dictionary <UEBuildTarget, List <FileItem> > TargetToOutdatedPrerequisitesMap; List <Action> ActionsToExecute = ActionGraph.GetActionsToExecute(BuildConfiguration, PrerequisiteActions, Targets, TargetToHeaders, true, true, out TargetToOutdatedPrerequisitesMap); string ExecutorName = "Unknown"; bool bSuccess = ActionGraph.ExecuteActions(BuildConfiguration, ActionsToExecute, bIsRemoteCompile, out ExecutorName, "", EHotReload.Disabled); if (bSuccess) { if (bIsRemoteCompile) { // Copy the remotely built AssetCatalog directory locally. foreach (FileItem OutputFile in OutputFiles) { string RemoteDirectory = System.IO.Path.GetDirectoryName(OutputFile.AbsolutePath).Replace("\\", "/"); FileItem LocalExecutable = ToolChain.RemoteToLocalFileItem(FileItem.GetItemByPath(Executable)); string LocalDirectory = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(LocalExecutable.AbsolutePath), "AssetCatalog"); LocalDirectory = StageDirectory; RPCUtilHelper.CopyDirectory(RemoteDirectory, LocalDirectory, RPCUtilHelper.ECopyOptions.DoNotReplace); } } else { // Copy the built AssetCatalog directory to the StageDirectory. foreach (FileItem OutputFile in OutputFiles) { string SourceDirectory = System.IO.Path.GetDirectoryName(OutputFile.AbsolutePath).Replace("\\", "/"); System.IO.DirectoryInfo SourceDirectoryInfo = new System.IO.DirectoryInfo(SourceDirectory); if (!System.IO.Directory.Exists(StageDirectory)) { System.IO.Directory.CreateDirectory(StageDirectory); } System.IO.FileInfo[] SourceFiles = SourceDirectoryInfo.GetFiles(); foreach (System.IO.FileInfo SourceFile in SourceFiles) { string DestinationPath = System.IO.Path.Combine(StageDirectory, SourceFile.Name); SourceFile.CopyTo(DestinationPath, true); } } } } // Restore the former bUseRPCUtil setting. RemoteToolChain.bUseRPCUtil = bSaveUseRPCUtil; }
/// <summary> /// Constructor /// </summary> /// <param name="ProjectFile">Project to read settings from</param> public RemoteMac(FileReference ProjectFile) { this.RsyncExe = FileReference.Combine(UnrealBuildTool.EngineDirectory, "Extras", "ThirdPartyNotUE", "DeltaCopy", "Binaries", "Rsync.exe"); this.SshExe = FileReference.Combine(UnrealBuildTool.EngineDirectory, "Extras", "ThirdPartyNotUE", "DeltaCopy", "Binaries", "Ssh.exe"); this.ProjectFile = ProjectFile; this.ProjectDirectory = DirectoryReference.FromFile(ProjectFile); // Apply settings from the XML file XmlConfig.ApplyTo(this); // Get the project config file path DirectoryReference EngineIniPath = ProjectFile != null ? ProjectFile.Directory : null; if (EngineIniPath == null && UnrealBuildTool.GetRemoteIniPath() != null) { EngineIniPath = new DirectoryReference(UnrealBuildTool.GetRemoteIniPath()); } ConfigHierarchy Ini = ConfigCache.ReadHierarchy(ConfigHierarchyType.Engine, EngineIniPath, UnrealTargetPlatform.IOS); // Read the project settings if we don't have anything in the build configuration settings if (String.IsNullOrEmpty(ServerName)) { // Read the server name string IniServerName; if (Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "RemoteServerName", out IniServerName) && !String.IsNullOrEmpty(IniServerName)) { this.ServerName = IniServerName; } else { throw new BuildException("Remote compiling requires a server name. Use the editor (Project Settings > IOS) to set up your remote compilation settings."); } // Parse the username string IniUserName; if (Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "RSyncUsername", out IniUserName) && !String.IsNullOrEmpty(IniUserName)) { this.UserName = IniUserName; } } // Split port out from the server name int PortIdx = ServerName.LastIndexOf(':'); if (PortIdx != -1) { string Port = ServerName.Substring(PortIdx + 1); if (!int.TryParse(Port, out ServerPort)) { throw new BuildException("Unable to parse port number from '{0}'", ServerName); } ServerName = ServerName.Substring(0, PortIdx); } // If a user name is not set, use the current user if (String.IsNullOrEmpty(UserName)) { UserName = Environment.UserName; } // Print out the server info Log.TraceInformation("[Remote] Using remote server '{0}' on port {1} (user '{2}')", ServerName, ServerPort, UserName); // Get the path to the SSH private key string OverrideSshPrivateKeyPath; if (Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "SSHPrivateKeyOverridePath", out OverrideSshPrivateKeyPath) && !String.IsNullOrEmpty(OverrideSshPrivateKeyPath)) { SshPrivateKey = new FileReference(OverrideSshPrivateKeyPath); if (!FileReference.Exists(SshPrivateKey)) { throw new BuildException("SSH private key specified in config file ({0}) does not exist.", SshPrivateKey); } } // If it's not set, look in the standard locations. If that fails, spawn the batch file to generate one. if (SshPrivateKey == null && !TryGetSshPrivateKey(out SshPrivateKey)) { Log.TraceWarning("No SSH private key found for {0}@{1}. Launching SSH to generate one.", UserName, ServerName); StringBuilder CommandLine = new StringBuilder(); CommandLine.AppendFormat("/C \"\"{0}\"", FileReference.Combine(UnrealBuildTool.EngineDirectory, "Build", "BatchFiles", "MakeAndInstallSSHKey.bat")); CommandLine.AppendFormat(" \"{0}\"", SshExe); CommandLine.AppendFormat(" \"{0}\"", ServerPort); CommandLine.AppendFormat(" \"{0}\"", RsyncExe); CommandLine.AppendFormat(" \"{0}\"", UserName); CommandLine.AppendFormat(" \"{0}\"", ServerName); CommandLine.AppendFormat(" \"{0}\"", DirectoryReference.GetSpecialFolder(Environment.SpecialFolder.MyDocuments)); CommandLine.AppendFormat(" \"{0}\"", GetLocalCygwinPath(DirectoryReference.GetSpecialFolder(Environment.SpecialFolder.MyDocuments))); CommandLine.AppendFormat(" \"{0}\"", UnrealBuildTool.EngineDirectory); CommandLine.Append("\""); using (Process ChildProcess = Process.Start("C:\\Windows\\System32\\Cmd.exe", CommandLine.ToString())) { ChildProcess.WaitForExit(); } if (!TryGetSshPrivateKey(out SshPrivateKey)) { throw new BuildException("Failed to generate SSH private key for {0}@{1}.", UserName, ServerName); } } // resolve the rest of the strings RsyncAuthentication = ExpandVariables(RsyncAuthentication); SshAuthentication = ExpandVariables(SshAuthentication); // Get the remote base directory RemoteBaseDir = String.Format("/Users/{0}/UE4/Builds/{1}", UserName, Environment.MachineName); // Build the list of directory mappings between the local and remote machines Mappings = new List <RemoteMapping>(); Mappings.Add(new RemoteMapping(UnrealBuildTool.EngineDirectory, GetRemotePath(UnrealBuildTool.EngineDirectory))); if (ProjectFile != null && !ProjectFile.IsUnderDirectory(UnrealBuildTool.EngineDirectory)) { Mappings.Add(new RemoteMapping(ProjectFile.Directory, GetRemotePath(ProjectFile.Directory))); } // Build a list of arguments for SSH CommonSshArguments = new List <string>(); CommonSshArguments.Add("-o BatchMode=yes"); CommonSshArguments.Add(SshAuthentication); CommonSshArguments.Add(String.Format("-p {0}", ServerPort)); CommonSshArguments.Add(String.Format("\"{0}@{1}\"", UserName, ServerName)); // Build a list of arguments for Rsync CommonRsyncArguments = new List <string>(); CommonRsyncArguments.Add("--compress"); CommonRsyncArguments.Add("--recursive"); CommonRsyncArguments.Add("--delete"); // Delete anything not in the source directory CommonRsyncArguments.Add("--delete-excluded"); // Delete anything not in the source directory CommonRsyncArguments.Add("--times"); // Preserve modification times CommonRsyncArguments.Add("--verbose"); CommonRsyncArguments.Add("-m"); CommonRsyncArguments.Add("--chmod=ug=rwX,o=rxX"); CommonRsyncArguments.Add(String.Format("--rsh=\"{0} -p {1}\"", RsyncAuthentication, ServerPort)); }
/// <summary> /// Main entry point /// </summary> /// <param name="Arguments">Command-line arguments</param> /// <returns>One of the values of ECompilationResult</returns> public override int Execute(CommandLineArguments Arguments) { Arguments.ApplyTo(this); // Initialize the log system, buffering the output until we can create the log file StartupTraceListener StartupListener = new StartupTraceListener(); Trace.Listeners.Add(StartupListener); // Write the command line Log.TraceLog("Command line: {0}", Environment.CommandLine); // Grab the environment. UnrealBuildTool.InitialEnvironment = Environment.GetEnvironmentVariables(); if (UnrealBuildTool.InitialEnvironment.Count < 1) { throw new BuildException("Environment could not be read"); } // Read the XML configuration files XmlConfig.ApplyTo(this); // Create the log file, and flush the startup listener to it if (!Arguments.HasOption("-NoLog") && !Log.HasFileWriter()) { FileReference LogFile = new FileReference(BaseLogFileName); foreach (string LogSuffix in Arguments.GetValues("-LogSuffix=")) { LogFile = LogFile.ChangeExtension(null) + "_" + LogSuffix + LogFile.GetExtension(); } TextWriterTraceListener LogTraceListener = Log.AddFileWriter("DefaultLogTraceListener", LogFile); StartupListener.CopyTo(LogTraceListener); } Trace.Listeners.Remove(StartupListener); // Create the build configuration object, and read the settings BuildConfiguration BuildConfiguration = new BuildConfiguration(); XmlConfig.ApplyTo(BuildConfiguration); Arguments.ApplyTo(BuildConfiguration); // now that we know the available platforms, we can delete other platforms' junk. if we're only building specific modules from the editor, don't touch anything else (it may be in use). if (!bIgnoreJunk && !UnrealBuildTool.IsEngineInstalled()) { using (Timeline.ScopeEvent("DeleteJunk()")) { JunkDeleter.DeleteJunk(); } } // Parse and build the targets try { // Parse all the target descriptors List <TargetDescriptor> TargetDescriptors; using (Timeline.ScopeEvent("TargetDescriptor.ParseCommandLine()")) { TargetDescriptors = TargetDescriptor.ParseCommandLine(Arguments, BuildConfiguration.bUsePrecompiled, BuildConfiguration.bSkipRulesCompile); } // Hack for single file compile; don't build the ShaderCompileWorker target that's added to the command line for generated project files if (TargetDescriptors.Count >= 2) { TargetDescriptors.RemoveAll(x => x.Name == "ShaderCompileWorker" && x.SingleFileToCompile != null); } // Handle remote builds for (int Idx = 0; Idx < TargetDescriptors.Count; Idx++) { TargetDescriptor TargetDesc = TargetDescriptors[Idx]; if (RemoteMac.HandlesTargetPlatform(TargetDesc.Platform)) { FileReference BaseLogFile = Log.OutputFile ?? new FileReference(BaseLogFileName); FileReference RemoteLogFile = FileReference.Combine(BaseLogFile.Directory, BaseLogFile.GetFileNameWithoutExtension() + "_Remote.txt"); RemoteMac RemoteMac = new RemoteMac(TargetDesc.ProjectFile); if (!RemoteMac.Build(TargetDesc, RemoteLogFile)) { return((int)CompilationResult.Unknown); } TargetDescriptors.RemoveAt(Idx--); } } // Handle local builds if (TargetDescriptors.Count > 0) { // Get a set of all the project directories HashSet <DirectoryReference> ProjectDirs = new HashSet <DirectoryReference>(); foreach (TargetDescriptor TargetDesc in TargetDescriptors) { if (TargetDesc.ProjectFile != null) { DirectoryReference ProjectDirectory = TargetDesc.ProjectFile.Directory; FileMetadataPrefetch.QueueProjectDirectory(ProjectDirectory); ProjectDirs.Add(ProjectDirectory); } } // Get all the build options BuildOptions Options = BuildOptions.None; if (bSkipBuild) { Options |= BuildOptions.SkipBuild; } if (bXGEExport) { Options |= BuildOptions.XGEExport; } // Create the working set provider using (ISourceFileWorkingSet WorkingSet = SourceFileWorkingSet.Create(UnrealBuildTool.RootDirectory, ProjectDirs)) { Build(TargetDescriptors, BuildConfiguration, WorkingSet, Options); } } } finally { // Save all the caches SourceFileMetadataCache.SaveAll(); CppDependencyCache.SaveAll(); } return(0); }
/// <summary> /// Constructor /// </summary> public WindowsTargetRules() { XmlConfig.ApplyTo(this); }
/// <summary> /// Loads a UBTMakefile from disk /// </summary> /// <param name="MakefilePath">Path to the makefile to load</param> /// <param name="ProjectFile">Path to the project file</param> /// <param name="ReasonNotLoaded">If the function returns null, this string will contain the reason why</param> /// <param name="WorkingSet">Interface to query which source files are in the working set</param> /// <returns>The loaded makefile, or null if it failed for some reason. On failure, the 'ReasonNotLoaded' variable will contain information about why</returns> public static UBTMakefile LoadUBTMakefile(FileReference MakefilePath, FileReference ProjectFile, ISourceFileWorkingSet WorkingSet, out string ReasonNotLoaded) { // Check the directory timestamp on the project files directory. If the user has generated project files more // recently than the UBTMakefile, then we need to consider the file to be out of date FileInfo UBTMakefileInfo = new FileInfo(MakefilePath.FullName); if (!UBTMakefileInfo.Exists) { // UBTMakefile doesn't even exist, so we won't bother loading it ReasonNotLoaded = "no existing makefile"; return(null); } // Check the build version FileInfo BuildVersionFileInfo = new FileInfo(BuildVersion.GetDefaultFileName().FullName); if (BuildVersionFileInfo.Exists && UBTMakefileInfo.LastWriteTime.CompareTo(BuildVersionFileInfo.LastWriteTime) < 0) { Log.TraceVerbose("Existing makefile is older than Build.version, ignoring it"); ReasonNotLoaded = "Build.version is newer"; return(null); } // @todo ubtmake: This will only work if the directory timestamp actually changes with every single GPF. Force delete existing files before creating new ones? Eh... really we probably just want to delete + create a file in that folder // -> UPDATE: Seems to work OK right now though on Windows platform, maybe due to GUID changes // @todo ubtmake: Some platforms may not save any files into this folder. We should delete + generate a "touch" file to force the directory timestamp to be updated (or just check the timestamp file itself. We could put it ANYWHERE, actually) // Installed Build doesn't need to check engine projects for outdatedness if (!UnrealBuildTool.IsEngineInstalled()) { if (DirectoryReference.Exists(ProjectFileGenerator.IntermediateProjectFilesPath)) { DateTime EngineProjectFilesLastUpdateTime = new FileInfo(ProjectFileGenerator.ProjectTimestampFile).LastWriteTime; if (UBTMakefileInfo.LastWriteTime.CompareTo(EngineProjectFilesLastUpdateTime) < 0) { // Engine project files are newer than UBTMakefile Log.TraceVerbose("Existing makefile is older than generated engine project files, ignoring it"); ReasonNotLoaded = "project files are newer"; return(null); } } } // Check the game project directory too if (ProjectFile != null) { string ProjectFilename = ProjectFile.FullName; FileInfo ProjectFileInfo = new FileInfo(ProjectFilename); if (!ProjectFileInfo.Exists || UBTMakefileInfo.LastWriteTime.CompareTo(ProjectFileInfo.LastWriteTime) < 0) { // .uproject file is newer than UBTMakefile Log.TraceVerbose("Makefile is older than .uproject file, ignoring it"); ReasonNotLoaded = ".uproject file is newer"; return(null); } DirectoryReference MasterProjectRelativePath = ProjectFile.Directory; string GameIntermediateProjectFilesPath = Path.Combine(MasterProjectRelativePath.FullName, "Intermediate", "ProjectFiles"); if (Directory.Exists(GameIntermediateProjectFilesPath)) { DateTime GameProjectFilesLastUpdateTime = new DirectoryInfo(GameIntermediateProjectFilesPath).LastWriteTime; if (UBTMakefileInfo.LastWriteTime.CompareTo(GameProjectFilesLastUpdateTime) < 0) { // Game project files are newer than UBTMakefile Log.TraceVerbose("Makefile is older than generated game project files, ignoring it"); ReasonNotLoaded = "game project files are newer"; return(null); } } } // Check to see if UnrealBuildTool.exe was compiled more recently than the UBTMakefile DateTime UnrealBuildToolTimestamp = new FileInfo(Assembly.GetExecutingAssembly().Location).LastWriteTime; if (UBTMakefileInfo.LastWriteTime.CompareTo(UnrealBuildToolTimestamp) < 0) { // UnrealBuildTool.exe was compiled more recently than the UBTMakefile Log.TraceVerbose("Makefile is older than UnrealBuildTool.exe, ignoring it"); ReasonNotLoaded = "UnrealBuildTool.exe is newer"; return(null); } // Check to see if any BuildConfiguration files have changed since the last build List <XmlConfig.InputFile> InputFiles = XmlConfig.FindInputFiles(); foreach (XmlConfig.InputFile InputFile in InputFiles) { FileInfo InputFileInfo = new FileInfo(InputFile.Location.FullName); if (InputFileInfo.LastWriteTime > UBTMakefileInfo.LastWriteTime) { Log.TraceVerbose("Makefile is older than BuildConfiguration.xml, ignoring it"); ReasonNotLoaded = "BuildConfiguration.xml is newer"; return(null); } } UBTMakefile LoadedUBTMakefile = null; try { DateTime LoadUBTMakefileStartTime = DateTime.UtcNow; using (FileStream Stream = new FileStream(UBTMakefileInfo.FullName, FileMode.Open, FileAccess.Read)) { BinaryFormatter Formatter = new BinaryFormatter(); LoadedUBTMakefile = Formatter.Deserialize(Stream) as UBTMakefile; } if (UnrealBuildTool.bPrintPerformanceInfo) { double LoadUBTMakefileTime = (DateTime.UtcNow - LoadUBTMakefileStartTime).TotalSeconds; Log.TraceInformation("LoadUBTMakefile took " + LoadUBTMakefileTime + "s"); } } catch (Exception Ex) { Log.TraceWarning("Failed to read makefile: {0}", Ex.Message); ReasonNotLoaded = "couldn't read existing makefile"; return(null); } if (!LoadedUBTMakefile.IsValidMakefile()) { Log.TraceWarning("Loaded makefile appears to have invalid contents, ignoring it ({0})", UBTMakefileInfo.FullName); ReasonNotLoaded = "existing makefile appears to be invalid"; return(null); } // Check if any of the target's Build.cs files are newer than the makefile foreach (UEBuildTarget Target in LoadedUBTMakefile.Targets) { string TargetCsFilename = Target.TargetRulesFile.FullName; if (TargetCsFilename != null) { FileInfo TargetCsFile = new FileInfo(TargetCsFilename); bool bTargetCsFileExists = TargetCsFile.Exists; if (!bTargetCsFileExists || TargetCsFile.LastWriteTime > UBTMakefileInfo.LastWriteTime) { Log.TraceVerbose("{0} has been {1} since makefile was built, ignoring it ({2})", TargetCsFilename, bTargetCsFileExists ? "changed" : "deleted", UBTMakefileInfo.FullName); ReasonNotLoaded = string.Format("changes to target files"); return(null); } } IEnumerable <string> BuildCsFilenames = Target.GetAllModuleBuildCsFilenames(); foreach (string BuildCsFilename in BuildCsFilenames) { if (BuildCsFilename != null) { FileInfo BuildCsFile = new FileInfo(BuildCsFilename); bool bBuildCsFileExists = BuildCsFile.Exists; if (!bBuildCsFileExists || BuildCsFile.LastWriteTime > UBTMakefileInfo.LastWriteTime) { Log.TraceVerbose("{0} has been {1} since makefile was built, ignoring it ({2})", BuildCsFilename, bBuildCsFileExists ? "changed" : "deleted", UBTMakefileInfo.FullName); ReasonNotLoaded = string.Format("changes to module files"); return(null); } } } foreach (FlatModuleCsDataType FlatCsModuleData in Target.FlatModuleCsData.Values) { if (FlatCsModuleData.BuildCsFilename != null && FlatCsModuleData.ExternalDependencies.Count > 0) { string BaseDir = Path.GetDirectoryName(FlatCsModuleData.BuildCsFilename); foreach (string ExternalDependency in FlatCsModuleData.ExternalDependencies) { FileInfo DependencyFile = new FileInfo(Path.Combine(BaseDir, ExternalDependency)); bool bDependencyFileExists = DependencyFile.Exists; if (!bDependencyFileExists || DependencyFile.LastWriteTime > UBTMakefileInfo.LastWriteTime) { Log.TraceVerbose("{0} has been {1} since makefile was built, ignoring it ({2})", DependencyFile.FullName, bDependencyFileExists ? "changed" : "deleted", UBTMakefileInfo.FullName); ReasonNotLoaded = string.Format("changes to external dependency"); return(null); } } } } } // We do a check to see if any modules' headers have changed which have // acquired or lost UHT types. If so, which should be rare, // we'll just invalidate the entire makefile and force it to be rebuilt. foreach (UEBuildTarget Target in LoadedUBTMakefile.Targets) { // Get all H files in processed modules newer than the makefile itself HashSet <string> HFilesNewerThanMakefile = new HashSet <string>( Target.FlatModuleCsData .SelectMany(x => x.Value.ModuleSourceFolder != null ? Directory.EnumerateFiles(x.Value.ModuleSourceFolder.FullName, "*.h", SearchOption.AllDirectories) : Enumerable.Empty <string>()) .Where(y => Directory.GetLastWriteTimeUtc(y) > UBTMakefileInfo.LastWriteTimeUtc) .OrderBy(z => z).Distinct() ); // Get all H files in all modules processed in the last makefile build HashSet <string> AllUHTHeaders = new HashSet <string>(Target.FlatModuleCsData.Select(x => x.Value).SelectMany(x => x.UHTHeaderNames)); // Check whether any headers have been deleted. If they have, we need to regenerate the makefile since the module might now be empty. If we don't, // and the file has been moved to a different module, we may include stale generated headers. foreach (string FileName in AllUHTHeaders) { if (!File.Exists(FileName)) { Log.TraceVerbose("File processed by UHT was deleted ({0}); invalidating makefile", FileName); ReasonNotLoaded = string.Format("UHT file was deleted"); return(null); } } // Makefile is invalid if: // * There are any newer files which contain no UHT data, but were previously in the makefile // * There are any newer files contain data which needs processing by UHT, but weren't not previously in the makefile foreach (string Filename in HFilesNewerThanMakefile) { bool bContainsUHTData = CPPHeaders.DoesFileContainUObjects(Filename); bool bWasProcessed = AllUHTHeaders.Contains(Filename); if (bContainsUHTData != bWasProcessed) { Log.TraceVerbose("{0} {1} contain UHT types and now {2} , ignoring it ({3})", Filename, bWasProcessed ? "used to" : "didn't", bWasProcessed ? "doesn't" : "does", UBTMakefileInfo.FullName); ReasonNotLoaded = string.Format("new files with reflected types"); return(null); } } } // If adaptive unity build is enabled, do a check to see if there are any source files that became part of the // working set since the Makefile was created (or, source files were removed from the working set.) If anything // changed, then we'll force a new Makefile to be created so that we have fresh unity build blobs. We always // want to make sure that source files in the working set are excluded from those unity blobs (for fastest possible // iteration times.) if (LoadedUBTMakefile.bUseAdaptiveUnityBuild) { // Check if any source files in the working set no longer belong in it foreach (FileItem SourceFile in LoadedUBTMakefile.SourceFileWorkingSet) { if (!WorkingSet.Contains(SourceFile.Location) && File.GetLastWriteTimeUtc(SourceFile.AbsolutePath) > UBTMakefileInfo.LastWriteTimeUtc) { Log.TraceVerbose("{0} was part of source working set and now is not; invalidating makefile ({1})", SourceFile.AbsolutePath, UBTMakefileInfo.FullName); ReasonNotLoaded = string.Format("working set of source files changed"); return(null); } } // Check if any source files that are eligible for being in the working set have been modified foreach (FileItem SourceFile in LoadedUBTMakefile.CandidateSourceFilesForWorkingSet) { if (WorkingSet.Contains(SourceFile.Location) && File.GetLastWriteTimeUtc(SourceFile.AbsolutePath) > UBTMakefileInfo.LastWriteTimeUtc) { Log.TraceVerbose("{0} was part of source working set and now is not; invalidating makefile ({1})", SourceFile.AbsolutePath, UBTMakefileInfo.FullName); ReasonNotLoaded = string.Format("working set of source files changed"); return(null); } } } ReasonNotLoaded = null; return(LoadedUBTMakefile); }
/// <summary> /// Loads a makefile from disk /// </summary> /// <param name="MakefilePath">Path to the makefile to load</param> /// <param name="ProjectFile">Path to the project file</param> /// <param name="Platform">Platform for this makefile</param> /// <param name="Arguments">Command line arguments for this target</param> /// <param name="ReasonNotLoaded">If the function returns null, this string will contain the reason why</param> /// <returns>The loaded makefile, or null if it failed for some reason. On failure, the 'ReasonNotLoaded' variable will contain information about why</returns> public static TargetMakefile Load(FileReference MakefilePath, FileReference ProjectFile, UnrealTargetPlatform Platform, string[] Arguments, out string ReasonNotLoaded) { using (Timeline.ScopeEvent("Checking dependent timestamps")) { // Check the directory timestamp on the project files directory. If the user has generated project files more recently than the makefile, then we need to consider the file to be out of date FileInfo MakefileInfo = new FileInfo(MakefilePath.FullName); if (!MakefileInfo.Exists) { // Makefile doesn't even exist, so we won't bother loading it ReasonNotLoaded = "no existing makefile"; return(null); } // Check the build version FileInfo BuildVersionFileInfo = new FileInfo(BuildVersion.GetDefaultFileName().FullName); if (BuildVersionFileInfo.Exists && MakefileInfo.LastWriteTime.CompareTo(BuildVersionFileInfo.LastWriteTime) < 0) { Log.TraceLog("Existing makefile is older than Build.version, ignoring it"); ReasonNotLoaded = "Build.version is newer"; return(null); } // @todo ubtmake: This will only work if the directory timestamp actually changes with every single GPF. Force delete existing files before creating new ones? Eh... really we probably just want to delete + create a file in that folder // -> UPDATE: Seems to work OK right now though on Windows platform, maybe due to GUID changes // @todo ubtmake: Some platforms may not save any files into this folder. We should delete + generate a "touch" file to force the directory timestamp to be updated (or just check the timestamp file itself. We could put it ANYWHERE, actually) // Installed Build doesn't need to check engine projects for outdatedness if (!UnrealBuildTool.IsEngineInstalled()) { if (DirectoryReference.Exists(ProjectFileGenerator.IntermediateProjectFilesPath)) { DateTime EngineProjectFilesLastUpdateTime = new FileInfo(ProjectFileGenerator.ProjectTimestampFile).LastWriteTime; if (MakefileInfo.LastWriteTime.CompareTo(EngineProjectFilesLastUpdateTime) < 0) { // Engine project files are newer than makefile Log.TraceLog("Existing makefile is older than generated engine project files, ignoring it"); ReasonNotLoaded = "project files are newer"; return(null); } } } // Check the game project directory too if (ProjectFile != null) { string ProjectFilename = ProjectFile.FullName; FileInfo ProjectFileInfo = new FileInfo(ProjectFilename); if (!ProjectFileInfo.Exists || MakefileInfo.LastWriteTime.CompareTo(ProjectFileInfo.LastWriteTime) < 0) { // .uproject file is newer than makefile Log.TraceLog("Makefile is older than .uproject file, ignoring it"); ReasonNotLoaded = ".uproject file is newer"; return(null); } DirectoryReference MasterProjectRelativePath = ProjectFile.Directory; string GameIntermediateProjectFilesPath = Path.Combine(MasterProjectRelativePath.FullName, "Intermediate", "ProjectFiles"); if (Directory.Exists(GameIntermediateProjectFilesPath)) { DateTime GameProjectFilesLastUpdateTime = new DirectoryInfo(GameIntermediateProjectFilesPath).LastWriteTime; if (MakefileInfo.LastWriteTime.CompareTo(GameProjectFilesLastUpdateTime) < 0) { // Game project files are newer than makefile Log.TraceLog("Makefile is older than generated game project files, ignoring it"); ReasonNotLoaded = "game project files are newer"; return(null); } } } // Check to see if UnrealBuildTool.exe was compiled more recently than the makefile DateTime UnrealBuildToolTimestamp = new FileInfo(Assembly.GetExecutingAssembly().Location).LastWriteTime; if (MakefileInfo.LastWriteTime.CompareTo(UnrealBuildToolTimestamp) < 0) { // UnrealBuildTool.exe was compiled more recently than the makefile Log.TraceLog("Makefile is older than UnrealBuildTool.exe, ignoring it"); ReasonNotLoaded = "UnrealBuildTool.exe is newer"; return(null); } // Check to see if any BuildConfiguration files have changed since the last build List <XmlConfig.InputFile> InputFiles = XmlConfig.FindInputFiles(); foreach (XmlConfig.InputFile InputFile in InputFiles) { FileInfo InputFileInfo = new FileInfo(InputFile.Location.FullName); if (InputFileInfo.LastWriteTime > MakefileInfo.LastWriteTime) { Log.TraceLog("Makefile is older than BuildConfiguration.xml, ignoring it"); ReasonNotLoaded = "BuildConfiguration.xml is newer"; return(null); } } } TargetMakefile Makefile; using (Timeline.ScopeEvent("Loading makefile")) { try { using (BinaryArchiveReader Reader = new BinaryArchiveReader(MakefilePath)) { int Version = Reader.ReadInt(); if (Version != CurrentVersion) { ReasonNotLoaded = "makefile version does not match"; return(null); } Makefile = new TargetMakefile(Reader); } } catch (Exception Ex) { Log.TraceWarning("Failed to read makefile: {0}", Ex.Message); Log.TraceLog("Exception: {0}", Ex.ToString()); ReasonNotLoaded = "couldn't read existing makefile"; return(null); } } using (Timeline.ScopeEvent("Checking makefile validity")) { // Check if the arguments are different if (!Enumerable.SequenceEqual(Makefile.AdditionalArguments, Arguments)) { ReasonNotLoaded = "command line arguments changed"; return(null); } // Check if ini files are newer. Ini files contain build settings too. DirectoryReference ProjectDirectory = DirectoryReference.FromFile(ProjectFile); foreach (ConfigHierarchyType IniType in (ConfigHierarchyType[])Enum.GetValues(typeof(ConfigHierarchyType))) { foreach (FileReference IniFilename in ConfigHierarchy.EnumerateConfigFileLocations(IniType, ProjectDirectory, Platform)) { FileInfo IniFileInfo = new FileInfo(IniFilename.FullName); if (IniFileInfo.LastWriteTimeUtc > Makefile.CreateTimeUtc) { // Ini files are newer than makefile ReasonNotLoaded = "ini files are newer than makefile"; return(null); } } } // Get the current build metadata from the platform string CurrentExternalMetadata = UEBuildPlatform.GetBuildPlatform(Platform).GetExternalBuildMetadata(ProjectFile); if (String.Compare(CurrentExternalMetadata, Makefile.ExternalMetadata, StringComparison.Ordinal) != 0) { Log.TraceLog("Old metadata:\n", Makefile.ExternalMetadata); Log.TraceLog("New metadata:\n", CurrentExternalMetadata); ReasonNotLoaded = "build metadata has changed"; return(null); } } // The makefile is ok ReasonNotLoaded = null; return(Makefile); }
/// <summary> /// Execute the command /// </summary> /// <param name="Arguments">Command line arguments</param> /// <returns>Exit code</returns> public override int Execute(CommandLineArguments Arguments) { Arguments.ApplyTo(this); // Create the build configuration object, and read the settings BuildConfiguration BuildConfiguration = new BuildConfiguration(); XmlConfig.ApplyTo(BuildConfiguration); Arguments.ApplyTo(BuildConfiguration); // Parse the filter argument FileFilter FileFilter = null; if (FilterRules.Count > 0) { FileFilter = new FileFilter(FileFilterType.Exclude); foreach (string FilterRule in FilterRules) { FileFilter.AddRules(FilterRule.Split(';')); } } // Parse all the target descriptors List <TargetDescriptor> TargetDescriptors = TargetDescriptor.ParseCommandLine(Arguments, BuildConfiguration.bUsePrecompiled, BuildConfiguration.bSkipRulesCompile); // Generate the compile DB for each target using (ISourceFileWorkingSet WorkingSet = new EmptySourceFileWorkingSet()) { // Find the compile commands for each file in the target Dictionary <FileReference, string> FileToCommand = new Dictionary <FileReference, string>(); foreach (TargetDescriptor TargetDescriptor in TargetDescriptors) { // Disable PCHs and unity builds for the target TargetDescriptor.AdditionalArguments = TargetDescriptor.AdditionalArguments.Append(new string[] { "-NoPCH", "-DisableUnity" }); // Create a makefile for the target 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"); // Convince each module to output its generated code include path foreach (UEBuildBinary Binary in Target.Binaries) { foreach (UEBuildModuleCPP Module in Binary.Modules.OfType <UEBuildModuleCPP>()) { Module.bAddGeneratedCodeIncludePath = true; } } // Create all the binaries and modules CppCompileEnvironment GlobalCompileEnvironment = Target.CreateCompileEnvironmentForProjectFiles(); foreach (UEBuildBinary Binary in Target.Binaries) { CppCompileEnvironment BinaryCompileEnvironment = Binary.CreateBinaryCompileEnvironment(GlobalCompileEnvironment); foreach (UEBuildModuleCPP Module in Binary.Modules.OfType <UEBuildModuleCPP>()) { if (!Module.Rules.bUsePrecompiled) { UEBuildModuleCPP.InputFileCollection InputFileCollection = Module.FindInputFiles(Target.Platform, new Dictionary <DirectoryItem, FileItem[]>()); List <FileItem> InputFiles = new List <FileItem>(); InputFiles.AddRange(InputFileCollection.CPPFiles); InputFiles.AddRange(InputFileCollection.CCFiles); CppCompileEnvironment ModuleCompileEnvironment = Module.CreateModuleCompileEnvironment(Target.Rules, BinaryCompileEnvironment); StringBuilder CommandBuilder = new StringBuilder(); CommandBuilder.AppendFormat("\"{0}\"", ClangPath.FullName); foreach (FileItem ForceIncludeFile in ModuleCompileEnvironment.ForceIncludeFiles) { CommandBuilder.AppendFormat(" -include \"{0}\"", ForceIncludeFile.FullName); } foreach (string Definition in ModuleCompileEnvironment.Definitions) { CommandBuilder.AppendFormat(" -D\"{0}\"", Definition); } foreach (DirectoryReference IncludePath in ModuleCompileEnvironment.UserIncludePaths) { CommandBuilder.AppendFormat(" -I\"{0}\"", IncludePath); } foreach (DirectoryReference IncludePath in ModuleCompileEnvironment.SystemIncludePaths) { CommandBuilder.AppendFormat(" -I\"{0}\"", IncludePath); } foreach (FileItem InputFile in InputFiles) { if (FileFilter == null || FileFilter.Matches(InputFile.Location.MakeRelativeTo(UnrealBuildTool.RootDirectory))) { FileToCommand[InputFile.Location] = String.Format("{0} \"{1}\"", CommandBuilder, InputFile.FullName); } } } } } } // Write the compile database FileReference DatabaseFile = FileReference.Combine(UnrealBuildTool.RootDirectory, "compile_commands.json"); using (JsonWriter Writer = new JsonWriter(DatabaseFile)) { Writer.WriteArrayStart(); foreach (KeyValuePair <FileReference, string> FileCommandPair in FileToCommand.OrderBy(x => x.Key.FullName)) { Writer.WriteObjectStart(); Writer.WriteValue("file", FileCommandPair.Key.FullName); Writer.WriteValue("command", FileCommandPair.Value); Writer.WriteValue("directory", UnrealBuildTool.EngineSourceDirectory.ToString()); Writer.WriteObjectEnd(); } Writer.WriteArrayEnd(); } } return(0); }
/// <summary> /// Constructor /// </summary> public HTML5TargetRules() { XmlConfig.ApplyTo(this); }
public SNDBS() { XmlConfig.ApplyTo(this); }
/// <summary> /// Constructor /// </summary> public ParallelExecutor() { XmlConfig.ApplyTo(this); }
public XGE() { XmlConfig.ApplyTo(this); }
/// <summary> /// Main entry point. Parses any global options and initializes the logging system, then invokes the appropriate command. /// </summary> /// <param name="ArgumentsArray">Command line arguments</param> /// <returns>Zero on success, non-zero on error</returns> private static int Main(string[] ArgumentsArray) { SingleInstanceMutex Mutex = null; try { // Start capturing performance info Timeline.Start(); // Parse the command line arguments CommandLineArguments Arguments = new CommandLineArguments(ArgumentsArray); // Parse the global options GlobalOptions Options = new GlobalOptions(Arguments); // Configure the log system Log.OutputLevel = Options.LogOutputLevel; Log.IncludeTimestamps = Options.bLogTimestamps; Log.IncludeProgramNameWithSeverityPrefix = Options.bLogFromMsBuild; // Configure the progress writer ProgressWriter.bWriteMarkup = Options.bWriteProgressMarkup; // Add the log writer if requested. When building a target, we'll create the writer for the default log file later. if (Options.LogFileName != null) { Log.AddFileWriter("LogTraceListener", Options.LogFileName); } // Ensure we can resolve any external assemblies that are not in the same folder as our assembly. AssemblyUtils.InstallAssemblyResolver(Path.GetDirectoryName(Assembly.GetEntryAssembly().GetOriginalLocation())); // Change the working directory to be the Engine/Source folder. We are likely running from Engine/Binaries/DotNET // This is critical to be done early so any code that relies on the current directory being Engine/Source will work. DirectoryReference.SetCurrentDirectory(UnrealBuildTool.EngineSourceDirectory); // Get the type of the mode to execute, using a fast-path for the build mode. Type ModeType = typeof(BuildMode); if (Options.Mode != null) { // Find all the valid modes Dictionary <string, Type> ModeNameToType = new Dictionary <string, Type>(StringComparer.OrdinalIgnoreCase); foreach (Type Type in Assembly.GetExecutingAssembly().GetTypes()) { if (Type.IsClass && !Type.IsAbstract && Type.IsSubclassOf(typeof(ToolMode))) { ToolModeAttribute Attribute = Type.GetCustomAttribute <ToolModeAttribute>(); if (Attribute == null) { throw new BuildException("Class '{0}' should have a ToolModeAttribute", Type.Name); } ModeNameToType.Add(Attribute.Name, Type); } } // Try to get the correct mode if (!ModeNameToType.TryGetValue(Options.Mode, out ModeType)) { Log.TraceError("No mode named '{0}'. Available modes are:\n {1}", Options.Mode, String.Join("\n ", ModeNameToType.Keys)); return(1); } } // Get the options for which systems have to be initialized for this mode ToolModeOptions ModeOptions = ModeType.GetCustomAttribute <ToolModeAttribute>().Options; // Start prefetching the contents of the engine folder if ((ModeOptions & ToolModeOptions.StartPrefetchingEngine) != 0) { using (Timeline.ScopeEvent("FileMetadataPrefetch.QueueEngineDirectory()")) { FileMetadataPrefetch.QueueEngineDirectory(); } } // Read the XML configuration files if ((ModeOptions & ToolModeOptions.XmlConfig) != 0) { using (Timeline.ScopeEvent("XmlConfig.ReadConfigFiles()")) { string XmlConfigMutexName = SingleInstanceMutex.GetUniqueMutexForPath("UnrealBuildTool_Mutex_XmlConfig", Assembly.GetExecutingAssembly().CodeBase); using (SingleInstanceMutex XmlConfigMutex = new SingleInstanceMutex(XmlConfigMutexName, true)) { FileReference XmlConfigCache = Arguments.GetFileReferenceOrDefault("-XmlConfigCache=", null); XmlConfig.ReadConfigFiles(XmlConfigCache); } } } // Acquire a lock for this branch if ((ModeOptions & ToolModeOptions.SingleInstance) != 0 && !Options.bNoMutex) { using (Timeline.ScopeEvent("SingleInstanceMutex.Acquire()")) { string MutexName = SingleInstanceMutex.GetUniqueMutexForPath("UnrealBuildTool_Mutex", Assembly.GetExecutingAssembly().CodeBase); Mutex = new SingleInstanceMutex(MutexName, Options.bWaitMutex); } } // Register all the build platforms if ((ModeOptions & ToolModeOptions.BuildPlatforms) != 0) { using (Timeline.ScopeEvent("UEBuildPlatform.RegisterPlatforms()")) { UEBuildPlatform.RegisterPlatforms(false); } } if ((ModeOptions & ToolModeOptions.BuildPlatformsForValidation) != 0) { using (Timeline.ScopeEvent("UEBuildPlatform.RegisterPlatforms()")) { UEBuildPlatform.RegisterPlatforms(true); } } // Create the appropriate handler ToolMode Mode = (ToolMode)Activator.CreateInstance(ModeType); // Execute the mode int Result = Mode.Execute(Arguments); if ((ModeOptions & ToolModeOptions.ShowExecutionTime) != 0) { Log.TraceInformation("Total execution time: {0:0.00} seconds", Timeline.Elapsed.TotalSeconds); } return(Result); } catch (CompilationResultException Ex) { // Used to return a propagate a specific exit code after an error has occurred. Does not log any message. Log.TraceLog(ExceptionUtils.FormatExceptionDetails(Ex)); return((int)Ex.Result); } catch (BuildException Ex) { // BuildExceptions should have nicely formatted messages. We can log these directly. Log.TraceError(ExceptionUtils.FormatException(Ex)); Log.TraceLog(ExceptionUtils.FormatExceptionDetails(Ex)); return((int)CompilationResult.OtherCompilationError); } catch (Exception Ex) { // Unhandled exception. Log.TraceError("Unhandled exception: {0}", ExceptionUtils.FormatException(Ex)); Log.TraceLog(ExceptionUtils.FormatExceptionDetails(Ex)); return((int)CompilationResult.OtherCompilationError); } finally { // Cancel the prefetcher using (Timeline.ScopeEvent("FileMetadataPrefetch.Stop()")) { FileMetadataPrefetch.Stop(); } // Print out all the performance info Timeline.Print(TimeSpan.FromMilliseconds(20.0), LogEventType.Log); // Make sure we flush the logs however we exit Trace.Close(); // Dispose of the mutex. Must be done last to ensure that another process does not startup and start trying to write to the same log file. if (Mutex != null) { Mutex.Dispose(); } } }
/// <summary> /// Main entry point /// </summary> /// <param name="Arguments">Command-line arguments</param> /// <returns>One of the values of ECompilationResult</returns> public override int Execute(CommandLineArguments Arguments) { Arguments.ApplyTo(this); // Create the build configuration object, and read the settings BuildConfiguration BuildConfiguration = new BuildConfiguration(); XmlConfig.ApplyTo(BuildConfiguration); Arguments.ApplyTo(BuildConfiguration); // Parse all the targets being built List <TargetDescriptor> TargetDescriptors = TargetDescriptor.ParseCommandLine(Arguments, BuildConfiguration.bUsePrecompiled, bSkipRulesCompile); if (TargetDescriptors.Count == 0) { throw new BuildException("No targets specified to clean"); } // Also add implicit descriptors for cleaning UnrealBuildTool if (!BuildConfiguration.bDoNotBuildUHT) { const string UnrealHeaderToolTarget = "UnrealHeaderTool"; // Get a list of project files to clean UHT for List <FileReference> ProjectFiles = new List <FileReference>(); foreach (TargetDescriptor TargetDesc in TargetDescriptors) { if (TargetDesc.Name != UnrealHeaderToolTarget && !RemoteMac.HandlesTargetPlatform(TargetDesc.Platform)) { if (ProjectFiles.Count == 0) { ProjectFiles.Add(null); } if (TargetDesc.ProjectFile != null && !ProjectFiles.Contains(TargetDesc.ProjectFile)) { ProjectFiles.Add(TargetDesc.ProjectFile); } } } // Add descriptors for cleaning UHT with all these projects if (ProjectFiles.Count > 0) { UnrealTargetConfiguration Configuration = BuildConfiguration.bForceDebugUnrealHeaderTool ? UnrealTargetConfiguration.Debug : UnrealTargetConfiguration.Development; string Architecture = UEBuildPlatform.GetBuildPlatform(BuildHostPlatform.Current.Platform).GetDefaultArchitecture(null); foreach (FileReference ProjectFile in ProjectFiles) { TargetDescriptors.Add(new TargetDescriptor(ProjectFile, UnrealHeaderToolTarget, BuildHostPlatform.Current.Platform, Configuration, Architecture, null)); } } } // Output the list of targets that we're cleaning Log.TraceInformation("Cleaning {0} binaries...", StringUtils.FormatList(TargetDescriptors.Select(x => x.Name).Distinct())); // Loop through all the targets, and clean them all HashSet <FileReference> FilesToDelete = new HashSet <FileReference>(); HashSet <DirectoryReference> DirectoriesToDelete = new HashSet <DirectoryReference>(); foreach (TargetDescriptor TargetDescriptor in TargetDescriptors) { // Create the rules assembly RulesAssembly RulesAssembly = RulesCompiler.CreateTargetRulesAssembly(TargetDescriptor.ProjectFile, TargetDescriptor.Name, bSkipRulesCompile, BuildConfiguration.bUsePrecompiled, TargetDescriptor.ForeignPlugin); // Create the rules object ReadOnlyTargetRules Target = new ReadOnlyTargetRules(RulesAssembly.CreateTargetRules(TargetDescriptor.Name, TargetDescriptor.Platform, TargetDescriptor.Configuration, TargetDescriptor.Architecture, TargetDescriptor.ProjectFile, TargetDescriptor.AdditionalArguments)); // Find the base folders that can contain binaries List <DirectoryReference> BaseDirs = new List <DirectoryReference>(); BaseDirs.Add(UnrealBuildTool.EngineDirectory); BaseDirs.Add(UnrealBuildTool.EnterpriseDirectory); foreach (FileReference Plugin in Plugins.EnumeratePlugins(Target.ProjectFile)) { BaseDirs.Add(Plugin.Directory); } if (Target.ProjectFile != null) { BaseDirs.Add(Target.ProjectFile.Directory); } // If we're running a precompiled build, remove anything under the engine folder BaseDirs.RemoveAll(x => RulesAssembly.IsReadOnly(x)); // Get all the names which can prefix build products List <string> NamePrefixes = new List <string>(); if (Target.Type != TargetType.Program) { NamePrefixes.Add(UEBuildTarget.GetAppNameForTargetType(Target.Type)); } NamePrefixes.Add(Target.Name); // Get the suffixes for this configuration List <string> NameSuffixes = new List <string>(); if (Target.Configuration == Target.UndecoratedConfiguration) { NameSuffixes.Add(""); } NameSuffixes.Add(String.Format("-{0}-{1}", Target.Platform.ToString(), Target.Configuration.ToString())); if (!String.IsNullOrEmpty(Target.Architecture)) { NameSuffixes.AddRange(NameSuffixes.ToArray().Select(x => x + Target.Architecture)); } // Add all the makefiles and caches to be deleted FilesToDelete.Add(TargetMakefile.GetLocation(Target.ProjectFile, Target.Name, Target.Platform, Target.Configuration)); FilesToDelete.UnionWith(SourceFileMetadataCache.GetFilesToClean(Target.ProjectFile)); FilesToDelete.UnionWith(ActionHistory.GetFilesToClean(Target.ProjectFile, Target.Name, Target.Platform, Target.Type)); // Add all the intermediate folders to be deleted foreach (DirectoryReference BaseDir in BaseDirs) { foreach (string NamePrefix in NamePrefixes) { DirectoryReference GeneratedCodeDir = DirectoryReference.Combine(BaseDir, "Intermediate", "Build", Target.Platform.ToString(), NamePrefix, "Inc"); if (DirectoryReference.Exists(GeneratedCodeDir)) { DirectoriesToDelete.Add(GeneratedCodeDir); } DirectoryReference IntermediateDir = DirectoryReference.Combine(BaseDir, "Intermediate", "Build", Target.Platform.ToString(), NamePrefix, Target.Configuration.ToString()); if (DirectoryReference.Exists(IntermediateDir)) { DirectoriesToDelete.Add(IntermediateDir); } } } // List of additional files and directories to clean, specified by the target platform List <FileReference> AdditionalFilesToDelete = new List <FileReference>(); List <DirectoryReference> AdditionalDirectoriesToDelete = new List <DirectoryReference>(); // Add all the build products from this target string[] NamePrefixesArray = NamePrefixes.Distinct().ToArray(); string[] NameSuffixesArray = NameSuffixes.Distinct().ToArray(); foreach (DirectoryReference BaseDir in BaseDirs) { DirectoryReference BinariesDir = DirectoryReference.Combine(BaseDir, "Binaries", Target.Platform.ToString()); if (DirectoryReference.Exists(BinariesDir)) { UEBuildPlatform.GetBuildPlatform(Target.Platform).FindBuildProductsToClean(BinariesDir, NamePrefixesArray, NameSuffixesArray, AdditionalFilesToDelete, AdditionalDirectoriesToDelete); } } // Get all the additional intermediate folders created by this platform UEBuildPlatform.GetBuildPlatform(Target.Platform).FindAdditionalBuildProductsToClean(Target, AdditionalFilesToDelete, AdditionalDirectoriesToDelete); // Add the platform's files and directories to the main list FilesToDelete.UnionWith(AdditionalFilesToDelete); DirectoriesToDelete.UnionWith(AdditionalDirectoriesToDelete); } // Delete all the directories, then all the files. By sorting the list of directories before we delete them, we avoid spamming the log if a parent directory is deleted first. foreach (DirectoryReference DirectoryToDelete in DirectoriesToDelete.OrderBy(x => x.FullName)) { if (DirectoryReference.Exists(DirectoryToDelete)) { Log.TraceVerbose(" Deleting {0}{1}...", DirectoryToDelete, Path.DirectorySeparatorChar); try { DirectoryReference.Delete(DirectoryToDelete, true); } catch (Exception Ex) { throw new BuildException(Ex, "Unable to delete {0} ({1})", DirectoryToDelete, Ex.Message.TrimEnd()); } } } foreach (FileReference FileToDelete in FilesToDelete.OrderBy(x => x.FullName)) { if (FileReference.Exists(FileToDelete)) { Log.TraceVerbose(" Deleting " + FileToDelete); try { FileReference.Delete(FileToDelete); } catch (Exception Ex) { throw new BuildException(Ex, "Unable to delete {0} ({1})", FileToDelete, Ex.Message.TrimEnd()); } } } // Also clean all the remote targets for (int Idx = 0; Idx < TargetDescriptors.Count; Idx++) { TargetDescriptor TargetDescriptor = TargetDescriptors[Idx]; if (RemoteMac.HandlesTargetPlatform(TargetDescriptor.Platform)) { RemoteMac RemoteMac = new RemoteMac(TargetDescriptor.ProjectFile); RemoteMac.Clean(TargetDescriptor); } } return(0); }
/// <summary> /// /// </summary> /// <returns></returns> public static bool UseRPCUtil() { XmlConfig.ReadConfigFiles(); return(RemoteToolChain.bUseRPCUtil); }