/// <summary> /// Reads a config hierarchy (or retrieve it from the cache) /// </summary> /// <param name="Type">The type of hierarchy to read</param> /// <param name="ProjectDir">The project directory to read the hierarchy for</param> /// <param name="Platform">Which platform to read platform-specific config files for</param> /// <returns>The requested config hierarchy</returns> public static ConfigHierarchy ReadHierarchy(ConfigHierarchyType Type, DirectoryReference ProjectDir, UnrealTargetPlatform Platform) { // Get the key to use for the cache. It cannot be null, so we use the engine directory if a project directory is not given. ConfigHierarchyKey Key = new ConfigHierarchyKey(Type, ProjectDir, Platform); // Try to get the cached hierarchy with this key ConfigHierarchy Hierarchy; if (!HierarchyKeyToHierarchy.TryGetValue(Key, out Hierarchy)) { List <ConfigFile> Files = new List <ConfigFile>(); foreach (FileReference IniFileName in ConfigHierarchy.EnumerateConfigFileLocations(Type, ProjectDir, Platform)) { ConfigFile File; if (TryReadFile(IniFileName, out File)) { Files.Add(File); } } Hierarchy = new ConfigHierarchy(Files); HierarchyKeyToHierarchy.Add(Key, Hierarchy); } return(Hierarchy); }
/// <summary> /// Reads a config hierarchy (or retrieve it from the cache) /// </summary> /// <param name="Type">The type of hierarchy to read</param> /// <param name="ProjectDir">The project directory to read the hierarchy for</param> /// <param name="Platform">Which platform to read platform-specific config files for</param> /// <param name="GeneratedConfigDir">Base directory for generated configs</param> /// <returns>The requested config hierarchy</returns> public static ConfigHierarchy ReadHierarchy(ConfigHierarchyType Type, DirectoryReference ProjectDir, UnrealTargetPlatform Platform, DirectoryReference GeneratedConfigDir = null) { // Get the key to use for the cache. It cannot be null, so we use the engine directory if a project directory is not given. ConfigHierarchyKey Key = new ConfigHierarchyKey(Type, ProjectDir, Platform); // Try to get the cached hierarchy with this key ConfigHierarchy Hierarchy; if (!HierarchyKeyToHierarchy.TryGetValue(Key, out Hierarchy)) { List <ConfigFile> Files = new List <ConfigFile>(); foreach (FileReference IniFileName in ConfigHierarchy.EnumerateConfigFileLocations(Type, ProjectDir, Platform)) { ConfigFile File; if (TryReadFile(IniFileName, out File)) { Files.Add(File); } } // If we haven't been given a generated project dir, but we do have a project then the generated configs // should go into ProjectDir/Saved if (GeneratedConfigDir == null && ProjectDir != null) { GeneratedConfigDir = DirectoryReference.Combine(ProjectDir, "Saved"); } if (GeneratedConfigDir != null) { // We know where the generated version of this config file lives, so we can read it back in // and include any user settings from there in our hierarchy string BaseIniName = Enum.GetName(typeof(ConfigHierarchyType), Type); string PlatformName = ConfigHierarchy.GetIniPlatformName(Platform); FileReference DestinationIniFilename = FileReference.Combine(GeneratedConfigDir, "Config", PlatformName, BaseIniName + ".ini"); ConfigFile File; if (TryReadFile(DestinationIniFilename, out File)) { Files.Add(File); } } // Handle command line overrides string[] CmdLine = Environment.GetCommandLineArgs(); string IniConfigArgPrefix = "-ini:" + Enum.GetName(typeof(ConfigHierarchyType), Type) + ":"; foreach (string CmdLineArg in CmdLine) { if (CmdLineArg.StartsWith(IniConfigArgPrefix)) { ConfigFile OverrideFile = new ConfigFile(CmdLineArg.Substring(IniConfigArgPrefix.Length)); Files.Add(OverrideFile); } } Hierarchy = new ConfigHierarchy(Files); HierarchyKeyToHierarchy.Add(Key, Hierarchy); } return(Hierarchy); }
/// <summary> /// Reads a config hierarchy (or retrieve it from the cache) /// </summary> /// <param name="Type">The type of hierarchy to read</param> /// <param name="ProjectDir">The project directory to read the hierarchy for</param> /// <param name="Platform">Which platform to read platform-specific config files for</param> /// <returns>The requested config hierarchy</returns> public static ConfigHierarchy ReadHierarchy(ConfigHierarchyType Type, DirectoryReference ProjectDir, UnrealTargetPlatform Platform) { // Get the key to use for the cache. It cannot be null, so we use the engine directory if a project directory is not given. ConfigHierarchyKey Key = new ConfigHierarchyKey(Type, ProjectDir, Platform); // Try to get the cached hierarchy with this key ConfigHierarchy Hierarchy; lock (HierarchyKeyToHierarchy) { if (!HierarchyKeyToHierarchy.TryGetValue(Key, out Hierarchy)) { // Find all the input files List <ConfigFile> Files = new List <ConfigFile>(); foreach (FileReference IniFileName in ConfigHierarchy.EnumerateConfigFileLocations(Type, ProjectDir, Platform)) { ConfigFile File; if (TryReadFile(IniFileName, out File)) { Files.Add(File); } } // Handle command line overrides string[] CmdLine = Environment.GetCommandLineArgs(); string IniConfigArgPrefix = "-ini:" + Enum.GetName(typeof(ConfigHierarchyType), Type) + ":"; foreach (string CmdLineArg in CmdLine) { if (CmdLineArg.StartsWith(IniConfigArgPrefix)) { ConfigFile OverrideFile = new ConfigFile(CmdLineArg.Substring(IniConfigArgPrefix.Length)); Files.Add(OverrideFile); } } // Create the hierarchy Hierarchy = new ConfigHierarchy(Files); HierarchyKeyToHierarchy.Add(Key, Hierarchy); } } return(Hierarchy); }
/// <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); }