/// <summary> /// Gets the dependency cache path and filename for the specified target. /// </summary> /// <param name="Target">Current build target</param> /// <returns>Cache Path</returns> public static string GetDependencyCachePathForTarget(UEBuildTarget Target) { string PlatformIntermediatePath = BuildConfiguration.PlatformIntermediatePath; if (UnrealBuildTool.HasUProjectFile()) { PlatformIntermediatePath = Path.Combine(UnrealBuildTool.GetUProjectPath(), BuildConfiguration.PlatformIntermediateFolder); } string CachePath = Path.Combine(PlatformIntermediatePath, Target.GetTargetName(), "DependencyCache.bin"); return(CachePath); }
/// <summary> /// Collects all header files included in a CPPFile /// </summary> /// <param name="CPPFile"></param> /// <param name="Result"></param> /// <param name="FileToRead"></param> /// <param name="FileContents"></param> /// <param name="InstalledFolder"></param> /// <param name="StartIndex"></param> /// <param name="EndIndex"></param> private static void CollectHeaders(FileItem CPPFile, List <DependencyInclude> Result, string FileToRead, string FileContents, string InstalledFolder, int StartIndex, int EndIndex) { Match M = CPPHeaderRegex.Match(FileContents, StartIndex, EndIndex - StartIndex); CaptureCollection CC = M.Groups["HeaderFile"].Captures; Result.Capacity = Math.Max(Result.Count + CC.Count, Result.Capacity); foreach (Capture C in CC) { string HeaderValue = C.Value; if (HeaderValue.IndexOfAny(Path.GetInvalidPathChars()) != -1) { throw new BuildException("In {0}: An #include statement contains invalid characters. You might be missing a double-quote character. (\"{1}\")", FileToRead, C.Value); } //@TODO: The intermediate exclusion is to work around autogenerated absolute paths in Module.SomeGame.cpp style files bool bIsIntermediateOrThirdParty = FileToRead.Contains("Intermediate") || FileToRead.Contains("ThirdParty"); bool bCheckForBackwardSlashes = FileToRead.StartsWith(InstalledFolder); if (UnrealBuildTool.HasUProjectFile()) { bCheckForBackwardSlashes |= Utils.IsFileUnderDirectory(FileToRead, UnrealBuildTool.GetUProjectPath()); } if (bCheckForBackwardSlashes && !bIsIntermediateOrThirdParty) { if (HeaderValue.IndexOf('\\', 0) >= 0) { throw new BuildException("In {0}: #include \"{1}\" contains backslashes ('\\'), please use forward slashes ('/') instead.", FileToRead, C.Value); } } HeaderValue = Utils.CleanDirectorySeparators(HeaderValue); Result.Add(new DependencyInclude(HeaderValue)); } // also look for #import in objective C files string Ext = Path.GetExtension(CPPFile.AbsolutePath).ToUpperInvariant(); if (Ext == ".MM" || Ext == ".M") { M = MMHeaderRegex.Match(FileContents, StartIndex, EndIndex - StartIndex); CC = M.Groups["HeaderFile"].Captures; Result.Capacity += CC.Count; foreach (Capture C in CC) { Result.Add(new DependencyInclude(C.Value)); } } }
/// <summary> /// Get the name of the response file for the current linker environment and output file /// </summary> /// <param name="LinkEnvironment"></param> /// <param name="OutputFile"></param> /// <returns></returns> public static string GetResponseFileName(LinkEnvironment LinkEnvironment, FileItem OutputFile) { // Construct a relative path for the intermediate response file string ResponseFileName = Path.Combine(LinkEnvironment.Config.IntermediateDirectory, Path.GetFileName(OutputFile.AbsolutePath) + ".response"); if (UnrealBuildTool.HasUProjectFile()) { // If this is the uproject being built, redirect the intermediate if (Utils.IsFileUnderDirectory(OutputFile.AbsolutePath, UnrealBuildTool.GetUProjectPath())) { ResponseFileName = Path.Combine( UnrealBuildTool.GetUProjectPath(), BuildConfiguration.PlatformIntermediateFolder, Path.GetFileNameWithoutExtension(UnrealBuildTool.GetUProjectFile()), LinkEnvironment.Config.Target.Configuration.ToString(), Path.GetFileName(OutputFile.AbsolutePath) + ".response"); } } // Convert the relative path to an absolute path ResponseFileName = Path.GetFullPath(ResponseFileName); return(ResponseFileName); }
/// <summary> /// Generates a full path to action history file for the specified target. /// </summary> public static string GeneratePathForTarget(UEBuildTarget Target) { string Folder = null; if (Target.ShouldCompileMonolithic() || Target.TargetType == TargetRules.TargetType.Program) { // Monolithic configs and programs have their Action History stored in their respective project folders // or under engine intermediate folder + program name folder string RootDirectory = UnrealBuildTool.GetUProjectPath(); if (String.IsNullOrEmpty(RootDirectory)) { RootDirectory = Path.GetFullPath(BuildConfiguration.RelativeEnginePath); } Folder = Path.Combine(RootDirectory, BuildConfiguration.PlatformIntermediateFolder, Target.GetTargetName()); } else { // Shared action history (unless this is a rocket target) Folder = (UnrealBuildTool.RunningRocket() && UnrealBuildTool.HasUProjectFile()) ? Path.Combine(UnrealBuildTool.GetUProjectPath(), BuildConfiguration.BaseIntermediateFolder) : BuildConfiguration.BaseIntermediatePath; } return(Path.Combine(Folder, "ActionHistory.bin").Replace("\\", "/")); }
public override bool WriteProjectFile(List <UnrealTargetPlatform> InPlatforms, List <UnrealTargetConfiguration> InConfigurations) { bool bSuccess = false; string ProjectPath = ProjectFilePath; string ProjectExtension = Path.GetExtension(ProjectFilePath); string ProjectPlatformName = BuildHostPlatform.Current.Platform.ToString(); string ProjectRelativeFilePath = this.RelativeProjectFilePath; // Get the output directory string EngineRootDirectory = Path.GetFullPath(ProjectFileGenerator.EngineRelativePath); // // Build the working directory of the Game executable. // string GameWorkingDirectory = ""; if (UnrealBuildTool.HasUProjectFile()) { GameWorkingDirectory = Path.Combine(Path.GetDirectoryName(UnrealBuildTool.GetUProjectFile()), "Binaries", ProjectPlatformName); } // // Build the working directory of the UE4Editor executable. // string UE4EditorWorkingDirectory = Path.Combine(EngineRootDirectory, "Binaries", ProjectPlatformName); // // Create the folder where the project files goes if it does not exist // String FilePath = Path.GetDirectoryName(ProjectFilePath); if ((FilePath.Length > 0) && !Directory.Exists(FilePath)) { Directory.CreateDirectory(FilePath); } string GameProjectFile = UnrealBuildTool.GetUProjectFile(); // // Write all targets which will be separate projects. // foreach (ProjectTarget target in ProjectTargets) { string[] tmp = target.ToString().Split('.'); string ProjectTargetFileName = Path.GetDirectoryName(ProjectFilePath) + "/" + tmp [0] + ProjectExtension; String ProjectName = tmp [0]; var ProjectTargetType = target.TargetRules.Type; // // Create the CodeLites root element. // XElement CodeLiteProject = new XElement("CodeLite_Project"); XAttribute CodeLiteProjectAttributeName = new XAttribute("Name", ProjectName); CodeLiteProject.Add(CodeLiteProjectAttributeName); // // Select only files we want to add. // TODO Maybe skipping those files directly in the following foreach loop is faster? // List <SourceFile> FilterSourceFile = SourceFiles.FindAll(s => ( Path.GetExtension(s.FilePath).Equals(".h") || Path.GetExtension(s.FilePath).Equals(".cpp") || Path.GetExtension(s.FilePath).Equals(".cs") || Path.GetExtension(s.FilePath).Equals(".uproject") || Path.GetExtension(s.FilePath).Equals(".ini") || Path.GetExtension(s.FilePath).Equals(".usf") )); // // Find/Create the correct virtual folder and place the file into it. // foreach (var CurrentFile in FilterSourceFile) { // // Try to get the correct relative folder representation for the project. // String CurrentFilePath = ""; // TODO It seems that the full pathname doesn't work for some files like .ini, .usf if ((ProjectTargetType == TargetRules.TargetType.Client) || (ProjectTargetType == TargetRules.TargetType.Editor) || (ProjectTargetType == TargetRules.TargetType.Server)) { if (ProjectName.Contains("UE4")) { int Idx = Path.GetFullPath(ProjectFileGenerator.EngineRelativePath).Length; CurrentFilePath = Path.GetDirectoryName(Path.GetFullPath(CurrentFile.FilePath)).Substring(Idx); } else { int IdxProjectName = ProjectName.IndexOf("Editor"); string ProjectNameRaw = ProjectName; if (IdxProjectName > 0) { ProjectNameRaw = ProjectName.Substring(0, IdxProjectName); } int Idx = Path.GetDirectoryName(Path.GetFullPath(CurrentFile.FilePath)).IndexOf(ProjectNameRaw) + ProjectNameRaw.Length; CurrentFilePath = Path.GetDirectoryName(Path.GetFullPath(CurrentFile.FilePath)).Substring(Idx); } } else if (ProjectTargetType == TargetRules.TargetType.Program) { // // We do not need all the editors subfolders to show the content. Find the correct programs subfolder. // int Idx = Path.GetDirectoryName(Path.GetFullPath(CurrentFile.FilePath)).IndexOf(ProjectName) + ProjectName.Length; CurrentFilePath = Path.GetFullPath(Path.GetDirectoryName(CurrentFile.FilePath)).Substring(Idx); } else if (ProjectTargetType == TargetRules.TargetType.Game) { // int lengthOfProjectRootPath = Path.GetFullPath(ProjectFileGenerator.MasterProjectRelativePath).Length; // CurrentFilePath = Path.GetDirectoryName(Path.GetFullPath(CurrentFile.FilePath)).Substring(lengthOfProjectRootPath); // int lengthOfProjectRootPath = EngineRootDirectory.Length; int Idx = Path.GetDirectoryName(Path.GetFullPath(CurrentFile.FilePath)).IndexOf(ProjectName) + ProjectName.Length; CurrentFilePath = Path.GetDirectoryName(Path.GetFullPath(CurrentFile.FilePath)).Substring(Idx); } string [] SplitFolders = CurrentFilePath.Split('/'); // // Set the CodeLite root folder again. // XElement root = CodeLiteProject; // // Iterate through all XElement virtual folders until we find the right place to put the file. // TODO this looks more like a hack to me. // foreach (var FolderName in SplitFolders) { if (FolderName.Equals("")) { continue; } // // Let's look if there is a virtual folder withint the current XElement. // IEnumerable <XElement> tests = root.Elements("VirtualDirectory"); if (IsEmpty(tests)) { // // No, then we have to create. // XElement vf = new XElement("VirtualDirectory"); XAttribute vfn = new XAttribute("Name", FolderName); vf.Add(vfn); root.Add(vf); root = vf; } else { // // Yes, then let's find the correct sub XElement. // bool notfound = true; // // We have some virtual directories let's find the correct one. // foreach (var element in tests) { // // Look the the following folder XAttribute attribute = element.Attribute("Name"); if (attribute.Value == FolderName) { // Ok, we found the folder as subfolder, let's use it. root = element; notfound = false; break; } } // // If we are here we didn't find any XElement with that subfolder, then we have to create. // if (notfound) { XElement vf = new XElement("VirtualDirectory"); XAttribute vfn = new XAttribute("Name", FolderName); vf.Add(vfn); root.Add(vf); root = vf; } } } // // If we are at this point we found the correct XElement folder // XElement file = new XElement("File"); XAttribute fileAttribute = new XAttribute("Name", Path.GetFullPath(CurrentFile.FilePath)); file.Add(fileAttribute); root.Add(file); } XElement CodeLiteSettings = new XElement("Settings"); CodeLiteProject.Add(CodeLiteSettings); XElement CodeLiteGlobalSettings = new XElement("GlobalSettings"); CodeLiteSettings.Add(CodeLiteSettings); foreach (var CurConf in InConfigurations) { XElement CodeLiteConfiguration = new XElement("Configuration"); XAttribute CodeLiteConfigurationName = new XAttribute("Name", CurConf.ToString()); CodeLiteConfiguration.Add(CodeLiteConfigurationName); // // Create Configuration General part. // XElement CodeLiteConfigurationGeneral = new XElement("General"); // // Create the executable filename. // string ExecutableToRun = ""; string PlatformConfiguration = "-" + ProjectPlatformName + "-" + CurConf.ToString(); switch (BuildHostPlatform.Current.Platform) { case UnrealTargetPlatform.Linux: { ExecutableToRun = "./" + ProjectName; if ((ProjectTargetType == TargetRules.TargetType.Game) || (ProjectTargetType == TargetRules.TargetType.Program)) { if (CurConf != UnrealTargetConfiguration.Development) { ExecutableToRun += PlatformConfiguration; } } else if (ProjectTargetType == TargetRules.TargetType.Editor) { ExecutableToRun = "./UE4Editor"; } } break; case UnrealTargetPlatform.Mac: { ExecutableToRun = "./" + ProjectName; if ((ProjectTargetType == TargetRules.TargetType.Game) || (ProjectTargetType == TargetRules.TargetType.Program)) { if (CurConf != UnrealTargetConfiguration.Development) { ExecutableToRun += PlatformConfiguration; } ExecutableToRun += ".app/Contents/MacOS/" + ProjectName; if (CurConf != UnrealTargetConfiguration.Development) { ExecutableToRun += PlatformConfiguration; } } else if (ProjectTargetType == TargetRules.TargetType.Editor) { ExecutableToRun = "./UE4Editor"; if (CurConf != UnrealTargetConfiguration.Development) { ExecutableToRun += PlatformConfiguration; } ExecutableToRun += ".app/Contents/MacOS/UE4Editor"; if (CurConf != UnrealTargetConfiguration.Development) { ExecutableToRun += PlatformConfiguration; } } } break; case UnrealTargetPlatform.Win64: case UnrealTargetPlatform.Win32: { ExecutableToRun = ProjectName; if ((ProjectTargetType == TargetRules.TargetType.Game) || (ProjectTargetType == TargetRules.TargetType.Program)) { if (CurConf != UnrealTargetConfiguration.Development) { ExecutableToRun += PlatformConfiguration; } } else if (ProjectTargetType == TargetRules.TargetType.Editor) { ExecutableToRun = "UE4Editor"; } ExecutableToRun += ".exe"; } break; default: throw new BuildException("Unsupported platform."); } // Is this project a Game type? XAttribute GeneralExecutableToRun = new XAttribute("Command", ExecutableToRun); if (ProjectTargetType == TargetRules.TargetType.Game) { if (CurConf.ToString().Contains("Debug")) { string commandArguments = " -debug"; XAttribute GeneralExecutableToRunArguments = new XAttribute("CommandArguments", commandArguments); CodeLiteConfigurationGeneral.Add(GeneralExecutableToRunArguments); } if (ProjectName.Equals("UE4Game")) { XAttribute GeneralExecutableWorkingDirectory = new XAttribute("WorkingDirectory", UE4EditorWorkingDirectory); CodeLiteConfigurationGeneral.Add(GeneralExecutableWorkingDirectory); } else { XAttribute GeneralExecutableWorkingDirectory = new XAttribute("WorkingDirectory", GameWorkingDirectory); CodeLiteConfigurationGeneral.Add(GeneralExecutableWorkingDirectory); } } else if (ProjectTargetType == TargetRules.TargetType.Editor) { if (ProjectName != "UE4Editor") { string commandArguments = "\"" + GameProjectFile + "\"" + " -game"; XAttribute CommandArguments = new XAttribute("CommandArguments", commandArguments); CodeLiteConfigurationGeneral.Add(CommandArguments); } XAttribute WorkingDirectory = new XAttribute("WorkingDirectory", UE4EditorWorkingDirectory); CodeLiteConfigurationGeneral.Add(WorkingDirectory); } else if (ProjectTargetType == TargetRules.TargetType.Program) { XAttribute WorkingDirectory = new XAttribute("WorkingDirectory", UE4EditorWorkingDirectory); CodeLiteConfigurationGeneral.Add(WorkingDirectory); } else if (ProjectTargetType == TargetRules.TargetType.Client) { XAttribute WorkingDirectory = new XAttribute("WorkingDirectory", UE4EditorWorkingDirectory); CodeLiteConfigurationGeneral.Add(WorkingDirectory); } else if (ProjectTargetType == TargetRules.TargetType.Server) { XAttribute WorkingDirectory = new XAttribute("WorkingDirectory", UE4EditorWorkingDirectory); CodeLiteConfigurationGeneral.Add(WorkingDirectory); } CodeLiteConfigurationGeneral.Add(GeneralExecutableToRun); CodeLiteConfiguration.Add(CodeLiteConfigurationGeneral); // // End of Create Configuration General part. // // // Create Configuration Custom Build part. // XElement CodeLiteConfigurationCustomBuild = new XElement("CustomBuild"); CodeLiteConfiguration.Add(CodeLiteConfigurationGeneral); XAttribute CodeLiteConfigurationCustomBuildEnabled = new XAttribute("Enabled", "yes"); CodeLiteConfigurationCustomBuild.Add(CodeLiteConfigurationCustomBuildEnabled); // // Add the working directory for the custom build commands. // XElement CustomBuildWorkingDirectory = new XElement("WorkingDirectory"); XText CustuomBuildWorkingDirectory = new XText(Path.GetDirectoryName(UnrealBuildTool.GetUBTPath())); CustomBuildWorkingDirectory.Add(CustuomBuildWorkingDirectory); CodeLiteConfigurationCustomBuild.Add(CustomBuildWorkingDirectory); // // End of Add the working directory for the custom build commands. // // // Make Build Target. // XElement CustomBuildCommand = new XElement("BuildCommand"); CodeLiteConfigurationCustomBuild.Add(CustomBuildCommand); string BuildTarget = Path.GetFileName(UnrealBuildTool.GetUBTPath()) + " " + ProjectName + " " + ProjectPlatformName + " " + CurConf.ToString(); if ((BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Win64) && (BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Win32)) { BuildTarget = "mono " + BuildTarget; } if (GameProjectFile.Length > 0) { BuildTarget += " -project=" + "\"" + GameProjectFile + "\""; } XText commandLine = new XText(BuildTarget); CustomBuildCommand.Add(commandLine); // // End of Make Build Target // // // Clean Build Target. // XElement CustomCleanCommand = new XElement("CleanCommand"); CodeLiteConfigurationCustomBuild.Add(CustomCleanCommand); string CleanTarget = BuildTarget + " -clean"; XText CleanCommandLine = new XText(CleanTarget); CustomCleanCommand.Add(CleanCommandLine); // // End of Clean Build Target. // // // Rebuild Build Target. // XElement CustomRebuildCommand = new XElement("RebuildCommand"); CodeLiteConfigurationCustomBuild.Add(CustomRebuildCommand); string RebuildTarget = CleanTarget + "\n" + BuildTarget; XText RebuildCommandLine = new XText(RebuildTarget); CustomRebuildCommand.Add(RebuildCommandLine); // // End of Clean Build Target. // // // Some other fun Custom Targets. // if (ProjectTargetType == TargetRules.TargetType.Game) { string CookGameCommandLine = "mono AutomationTool.exe BuildCookRun "; // Projects filename CookGameCommandLine += "-project=\"" + UnrealBuildTool.GetUProjectFile() + "\" "; // Disables Perforce functionality CookGameCommandLine += "-noP4 "; // Do not kill any spawned processes on exit CookGameCommandLine += "-nokill "; CookGameCommandLine += "-clientconfig=" + CurConf.ToString() + " "; CookGameCommandLine += "-serverconfig=" + CurConf.ToString() + " "; CookGameCommandLine += "-platform=" + ProjectPlatformName + " "; CookGameCommandLine += "-targetplatform=" + ProjectPlatformName + " "; // TODO Maybe I can add all the supported one. CookGameCommandLine += "-nocompile "; CookGameCommandLine += "-compressed -stage -deploy"; // // Cook Game. // XElement CookGame = new XElement("Target"); XAttribute CookGameName = new XAttribute("Name", "Cook Game"); XText CookGameCommand = new XText(CookGameCommandLine + " -cook"); CookGame.Add(CookGameName); CookGame.Add(CookGameCommand); CodeLiteConfigurationCustomBuild.Add(CookGame); XElement CookGameOnTheFly = new XElement("Target"); XAttribute CookGameNameOnTheFlyName = new XAttribute("Name", "Cook Game on the fly"); XText CookGameOnTheFlyCommand = new XText(CookGameCommandLine + " -cookonthefly"); CookGameOnTheFly.Add(CookGameNameOnTheFlyName); CookGameOnTheFly.Add(CookGameOnTheFlyCommand); CodeLiteConfigurationCustomBuild.Add(CookGameOnTheFly); XElement SkipCook = new XElement("Target"); XAttribute SkipCookName = new XAttribute("Name", "Skip Cook Game"); XText SkipCookCommand = new XText(CookGameCommandLine + " -skipcook"); SkipCook.Add(SkipCookName); SkipCook.Add(SkipCookCommand); CodeLiteConfigurationCustomBuild.Add(SkipCook); } // // End of Some other fun Custom Targets. // CodeLiteConfiguration.Add(CodeLiteConfigurationCustomBuild); // // End of Create Configuration Custom Build part. // CodeLiteSettings.Add(CodeLiteConfiguration); } CodeLiteSettings.Add(CodeLiteGlobalSettings); // // Save the XML file. // CodeLiteProject.Save(ProjectTargetFileName); bSuccess = true; } return(bSuccess); }
/** * Builds and runs the header tool and touches the header directories. * Performs any early outs if headers need no changes, given the UObject modules, tool path, game name, and configuration */ public static bool ExecuteHeaderToolIfNecessary(UEBuildTarget Target, CPPEnvironment GlobalCompileEnvironment, List <UHTModuleInfo> UObjectModules, string ModuleInfoFileName, ref ECompilationResult UHTResult) { if (ProgressWriter.bWriteMarkup) { Log.WriteLine(TraceEventType.Information, "@progress push 5%"); } using (ProgressWriter Progress = new ProgressWriter("Generating code...", false)) { // We never want to try to execute the header tool when we're already trying to build it! var bIsBuildingUHT = Target.GetTargetName().Equals("UnrealHeaderTool", StringComparison.InvariantCultureIgnoreCase); var BuildPlatform = UEBuildPlatform.GetBuildPlatform(Target.Platform); var CppPlatform = BuildPlatform.GetCPPTargetPlatform(Target.Platform); var ToolChain = UEToolChain.GetPlatformToolChain(CppPlatform); var RootLocalPath = Path.GetFullPath(ProjectFileGenerator.RootRelativePath); // check if UHT is out of date DateTime HeaderToolTimestamp = DateTime.MaxValue; bool bHaveHeaderTool = !bIsBuildingUHT && GetHeaderToolTimestamp(out HeaderToolTimestamp); // ensure the headers are up to date bool bUHTNeedsToRun = (UEBuildConfiguration.bForceHeaderGeneration == true || !bHaveHeaderTool || AreGeneratedCodeFilesOutOfDate(UObjectModules, HeaderToolTimestamp)); if (bUHTNeedsToRun || UnrealBuildTool.IsGatheringBuild) { // Since code files are definitely out of date, we'll now finish computing information about the UObject modules for UHT. We // want to save this work until we know that UHT actually needs to be run to speed up best-case iteration times. if (UnrealBuildTool.IsGatheringBuild) // In assembler-only mode, PCH info is loaded from our UBTMakefile! { foreach (var UHTModuleInfo in UObjectModules) { // Only cache the PCH name if we don't already have one. When running in 'gather only' mode, this will have already been cached if (string.IsNullOrEmpty(UHTModuleInfo.PCH)) { UHTModuleInfo.PCH = ""; // We need to figure out which PCH header this module is including, so that UHT can inject an include statement for it into any .cpp files it is synthesizing var DependencyModuleCPP = (UEBuildModuleCPP)Target.GetModuleByName(UHTModuleInfo.ModuleName); var ModuleCompileEnvironment = DependencyModuleCPP.CreateModuleCompileEnvironment(GlobalCompileEnvironment); DependencyModuleCPP.CachePCHUsageForModuleSourceFiles(ModuleCompileEnvironment); if (DependencyModuleCPP.ProcessedDependencies.UniquePCHHeaderFile != null) { UHTModuleInfo.PCH = DependencyModuleCPP.ProcessedDependencies.UniquePCHHeaderFile.AbsolutePath; } } } } } // @todo ubtmake: Optimization: Ideally we could avoid having to generate this data in the case where UHT doesn't even need to run! Can't we use the existing copy? (see below use of Manifest) UHTManifest Manifest = new UHTManifest(Target, RootLocalPath, ToolChain.ConvertPath(RootLocalPath + '\\'), UObjectModules); if (!bIsBuildingUHT && bUHTNeedsToRun) { // Always build UnrealHeaderTool if header regeneration is required, unless we're running within a Rocket ecosystem or hot-reloading if (UnrealBuildTool.RunningRocket() == false && UEBuildConfiguration.bDoNotBuildUHT == false && UEBuildConfiguration.bHotReloadFromIDE == false && !(bHaveHeaderTool && !UnrealBuildTool.IsGatheringBuild && UnrealBuildTool.IsAssemblingBuild)) // If running in "assembler only" mode, we assume UHT is already up to date for much faster iteration! { // If it is out of date or not there it will be built. // If it is there and up to date, it will add 0.8 seconds to the build time. Log.TraceInformation("Building UnrealHeaderTool..."); var UBTArguments = new StringBuilder(); UBTArguments.Append("UnrealHeaderTool"); // Which desktop platform do we need to compile UHT for? UBTArguments.Append(" " + BuildHostPlatform.Current.Platform.ToString()); // NOTE: We force Development configuration for UHT so that it runs quickly, even when compiling debug UBTArguments.Append(" " + UnrealTargetConfiguration.Development.ToString()); // NOTE: We disable mutex when launching UBT from within UBT to compile UHT UBTArguments.Append(" -NoMutex"); if (UnrealBuildTool.CommandLineContains("-noxge")) { UBTArguments.Append(" -noxge"); } // Propagate command-line option to switch back to old 2013 toolchain if (UnrealBuildTool.CommandLineContains("-2013")) { UBTArguments.Append(" -2013"); } if (RunExternalExecutable(UnrealBuildTool.GetUBTPath(), UBTArguments.ToString()) != 0) { return(false); } } Progress.Write(1, 3); var ActualTargetName = String.IsNullOrEmpty(Target.GetTargetName()) ? "UE4" : Target.GetTargetName(); Log.TraceInformation("Parsing headers for {0}", ActualTargetName); string HeaderToolPath = GetHeaderToolPath(); if (!File.Exists(HeaderToolPath)) { throw new BuildException("Unable to generate headers because UnrealHeaderTool binary was not found ({0}).", Path.GetFullPath(HeaderToolPath)); } // Disable extensions when serializing to remove the $type fields Directory.CreateDirectory(Path.GetDirectoryName(ModuleInfoFileName)); System.IO.File.WriteAllText(ModuleInfoFileName, fastJSON.JSON.Instance.ToJSON(Manifest, new fastJSON.JSONParameters { UseExtensions = false })); string CmdLine = (UnrealBuildTool.HasUProjectFile()) ? "\"" + UnrealBuildTool.GetUProjectFile() + "\"" : Target.GetTargetName(); CmdLine += " \"" + ModuleInfoFileName + "\" -LogCmds=\"loginit warning, logexit warning, logdatabase error\""; if (UnrealBuildTool.RunningRocket()) { CmdLine += " -rocket -installed"; } if (UEBuildConfiguration.bFailIfGeneratedCodeChanges) { CmdLine += " -FailIfGeneratedCodeChanges"; } Log.TraceInformation(" Running UnrealHeaderTool {0}", CmdLine); Stopwatch s = new Stopwatch(); s.Start(); UHTResult = (ECompilationResult)RunExternalExecutable(ExternalExecution.GetHeaderToolPath(), CmdLine); s.Stop(); if (UHTResult != ECompilationResult.Succeeded) { // On Linux and Mac, the shell will return 128+signal number exit codes if UHT gets a signal (e.g. crashes or is interrupted) if ((BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Linux || BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac) && (int)(UHTResult) >= 128 ) { // SIGINT is 2, so 128 + SIGINT is 130 UHTResult = ((int)(UHTResult) == 130) ? ECompilationResult.Canceled : ECompilationResult.CrashOrAssert; } Log.TraceInformation("Error: Failed to generate code for {0} - error code: {2} ({1})", ActualTargetName, (int)UHTResult, UHTResult.ToString()); return(false); } Log.TraceInformation("Reflection code generated for {0} in {1} seconds", ActualTargetName, s.Elapsed.TotalSeconds); if (BuildConfiguration.bPrintPerformanceInfo) { Log.TraceInformation("UnrealHeaderTool took {1}", ActualTargetName, (double)s.ElapsedMilliseconds / 1000.0); } // Now that UHT has successfully finished generating code, we need to update all cached FileItems in case their last write time has changed. // Otherwise UBT might not detect changes UHT made. DateTime StartTime = DateTime.UtcNow; FileItem.ResetInfos(); double ResetDuration = (DateTime.UtcNow - StartTime).TotalSeconds; Log.TraceVerbose("FileItem.ResetInfos() duration: {0}s", ResetDuration); } else { Log.TraceVerbose("Generated code is up to date."); } Progress.Write(2, 3); // There will never be generated code if we're building UHT, so this should never be called. if (!bIsBuildingUHT) { // Allow generated code to be sync'd to remote machines if needed. This needs to be done even if UHT did not run because // generated headers include other generated headers using absolute paths which in case of building remotely are already // the remote machine absolute paths. Because of that parsing headers will not result in finding all includes properly. // @todo ubtmake: Need to figure out what this does in the assembler case, and whether we need to run it ToolChain.PostCodeGeneration(Manifest); } // touch the directories UpdateDirectoryTimestamps(UObjectModules); Progress.Write(3, 3); } if (ProgressWriter.bWriteMarkup) { Log.WriteLine(TraceEventType.Information, "@progress pop"); } return(true); }
private static string ResolveString(string Input, bool bIsPath) { string Result = Input; // these assume entire string is a path, and will do file operations on the whole string if (bIsPath) { if (Result.Contains("${PROGRAM_FILES}")) { // first look in real ProgramFiles string Temp = Result.Replace("${PROGRAM_FILES}", Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles, Environment.SpecialFolderOption.DoNotVerify)); if (File.Exists(Temp) || Directory.Exists(Temp)) { Result = Temp; } else { // fallback to ProgramFilesX86 Temp = Result.Replace("${PROGRAM_FILES}", Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86, Environment.SpecialFolderOption.DoNotVerify)); if (File.Exists(Temp) || Directory.Exists(Temp)) { Result = Temp; } } } if (Result.Contains("${ENGINE_ROOT}")) { string Temp = Result.Replace("${ENGINE_ROOT}", Path.GetFullPath(BuildConfiguration.RelativeEnginePath + "\\..")); // get the best version Result = LookForSpecialFile(Temp); } if (Result.Contains("${PROJECT_ROOT}")) { if (!UnrealBuildTool.HasUProjectFile()) { throw new BuildException("Configuration setting was using ${PROJECT_ROOT}, but there was no project specified"); } string Temp = Result.Replace("${PROJECT_ROOT}", Path.GetFullPath(UnrealBuildTool.GetUProjectPath())); // get the best version Result = LookForSpecialFile(Temp); } } // non path variables Result = Result.Replace("${CURRENT_USER}", Environment.UserName); // needs a resolved key (which isn't required if user is using alternate authentication) if (Result.Contains("${SSH_PRIVATE_KEY}") || Result.Contains("${CYGWIN_SSH_PRIVATE_KEY}")) { // if it needs the key, then make sure we have it! if (ResolvedSSHPrivateKey != null) { Result = Result.Replace("${SSH_PRIVATE_KEY}", ResolvedSSHPrivateKey); Result = Result.Replace("${CYGWIN_SSH_PRIVATE_KEY}", ConvertPathToCygwin(ResolvedSSHPrivateKey)); } else { Result = null; } } return(Result); }