/// <summary> /// Creates the makefile for a target. If an existing, valid makefile already exists on disk, loads that instead. /// </summary> /// <param name="BuildConfiguration">The build configuration</param> /// <param name="TargetDescriptor">Target being built</param> /// <param name="WorkingSet">Set of source files which are part of the working set</param> /// <returns>Makefile for the given target</returns> static TargetMakefile CreateMakefile(BuildConfiguration BuildConfiguration, TargetDescriptor TargetDescriptor, ISourceFileWorkingSet WorkingSet) { // Get the path to the makefile for this target FileReference MakefileLocation = null; if (BuildConfiguration.bUseUBTMakefiles && TargetDescriptor.SpecificFilesToCompile.Count == 0) { MakefileLocation = TargetMakefile.GetLocation(TargetDescriptor.ProjectFile, TargetDescriptor.Name, TargetDescriptor.Platform, TargetDescriptor.Architecture, TargetDescriptor.Configuration); } // Try to load an existing makefile TargetMakefile Makefile = null; if (MakefileLocation != null) { using (Timeline.ScopeEvent("TargetMakefile.Load()")) { string ReasonNotLoaded; Makefile = TargetMakefile.Load(MakefileLocation, TargetDescriptor.ProjectFile, TargetDescriptor.Platform, TargetDescriptor.AdditionalArguments.GetRawArray(), out ReasonNotLoaded); if (Makefile == null) { Log.TraceInformation("Creating makefile for {0} ({1})", TargetDescriptor.Name, ReasonNotLoaded); } } } // If we have a makefile, execute the pre-build steps and check it's still valid bool bHasRunPreBuildScripts = false; if (Makefile != null) { // Execute the scripts. We have to invalidate all cached file info after doing so, because we don't know what may have changed. if (Makefile.PreBuildScripts.Length > 0) { Utils.ExecuteCustomBuildSteps(Makefile.PreBuildScripts); DirectoryItem.ResetAllCachedInfo_SLOW(); } // Don't run the pre-build steps again, even if we invalidate the makefile. bHasRunPreBuildScripts = true; // Check that the makefile is still valid string Reason; if (!TargetMakefile.IsValidForSourceFiles(Makefile, TargetDescriptor.ProjectFile, TargetDescriptor.Platform, WorkingSet, out Reason)) { Log.TraceInformation("Invalidating makefile for {0} ({1})", TargetDescriptor.Name, Reason); Makefile = null; } } // If we couldn't load a makefile, create a new one if (Makefile == null) { // Create the target UEBuildTarget Target; using (Timeline.ScopeEvent("UEBuildTarget.Create()")) { Target = UEBuildTarget.Create(TargetDescriptor, BuildConfiguration.bSkipRulesCompile, BuildConfiguration.bUsePrecompiled); } // Create the pre-build scripts FileReference[] PreBuildScripts = Target.CreatePreBuildScripts(); // Execute the pre-build scripts if (!bHasRunPreBuildScripts) { Utils.ExecuteCustomBuildSteps(PreBuildScripts); bHasRunPreBuildScripts = true; } // Build the target using (Timeline.ScopeEvent("UEBuildTarget.Build()")) { const bool bIsAssemblingBuild = true; Makefile = Target.Build(BuildConfiguration, WorkingSet, bIsAssemblingBuild, TargetDescriptor.SpecificFilesToCompile); } // Save the pre-build scripts onto the makefile Makefile.PreBuildScripts = PreBuildScripts; // Save the additional command line arguments Makefile.AdditionalArguments = TargetDescriptor.AdditionalArguments.GetRawArray(); // Save the environment variables foreach (System.Collections.DictionaryEntry EnvironmentVariable in Environment.GetEnvironmentVariables()) { Makefile.EnvironmentVariables.Add(Tuple.Create((string)EnvironmentVariable.Key, (string)EnvironmentVariable.Value)); } // Save the makefile for next time if (MakefileLocation != null) { using (Timeline.ScopeEvent("TargetMakefile.Save()")) { Makefile.Save(MakefileLocation); } } } else { // Restore the environment variables foreach (Tuple <string, string> EnvironmentVariable in Makefile.EnvironmentVariables) { Environment.SetEnvironmentVariable(EnvironmentVariable.Item1, EnvironmentVariable.Item2); } // If the target needs UHT to be run, we'll go ahead and do that now if (Makefile.UObjectModules.Count > 0) { const bool bIsGatheringBuild = false; const bool bIsAssemblingBuild = true; FileReference ModuleInfoFileName = FileReference.Combine(Makefile.ProjectIntermediateDirectory, TargetDescriptor.Name + ".uhtmanifest"); ExternalExecution.ExecuteHeaderToolIfNecessary(BuildConfiguration, TargetDescriptor.ProjectFile, TargetDescriptor.Name, Makefile.TargetType, Makefile.bHasProjectScriptPlugin, UObjectModules: Makefile.UObjectModules, ModuleInfoFileName: ModuleInfoFileName, bIsGatheringBuild: bIsGatheringBuild, bIsAssemblingBuild: bIsAssemblingBuild, WorkingSet: WorkingSet); } } return(Makefile); }