public bool IsValidPlatformAndConfiguration(UnrealTargetConfiguration Configuration, UnrealTargetPlatform Platform, EProjectType ProjectType = EProjectType.Any)
        {
            if (UnrealBuildTool.IsEngineInstalled())
            {
                foreach (InstalledPlatformConfiguration PlatformConfiguration in InstalledPlatformConfigurations)
                {
                    if (PlatformConfiguration.Configuration == Configuration &&
                        PlatformConfiguration.Platform == Platform)
                    {
                        if (ProjectType == EProjectType.Any || PlatformConfiguration.ProjectType == EProjectType.Any ||
                            PlatformConfiguration.ProjectType == ProjectType)
                        {
                            if (string.IsNullOrEmpty(PlatformConfiguration.RequiredFile) ||
                                File.Exists(PlatformConfiguration.RequiredFile))
                            {
                                return(true);
                            }
                        }
                    }
                }

                return(false);
            }
            return(true);
        }
 /// <summary>
 /// Add the given Engine ThirdParty modules as static private dependencies
 ///	Statically linked to this module, meaning they utilize exports from the other module
 ///	Private, meaning the include paths for the included modules will not be exposed when giving this modules include paths
 ///	NOTE: There is no AddThirdPartyPublicStaticDependencies function.
 /// </summary>
 /// <param name="ModuleNames">The names of the modules to add</param>
 public void AddEngineThirdPartyPrivateStaticDependencies(TargetInfo Target, params string[] InModuleNames)
 {
     if (!UnrealBuildTool.IsEngineInstalled() || Target.IsMonolithic)
     {
         PrivateDependencyModuleNames.AddRange(InModuleNames);
     }
 }
        /// <summary>
        /// Creates a cache hierarchy for a particular target
        /// </summary>
        /// <param name="ProjectFile">Project file for the target being built</param>
        /// <param name="TargetName">Name of the target</param>
        /// <param name="Platform">Platform being built</param>
        /// <param name="Configuration">Configuration being built</param>
        /// <param name="TargetType">The target type</param>
        /// <param name="Architecture">The target architecture</param>
        /// <returns>Dependency cache hierarchy for the given project</returns>
        public static CppDependencyCache CreateHierarchy(FileReference ProjectFile, string TargetName, UnrealTargetPlatform Platform, UnrealTargetConfiguration Configuration, TargetType TargetType, string Architecture)
        {
            CppDependencyCache Cache = null;

            if (ProjectFile == null || !UnrealBuildTool.IsEngineInstalled())
            {
                string AppName;
                if (TargetType == TargetType.Program)
                {
                    AppName = TargetName;
                }
                else
                {
                    AppName = UEBuildTarget.GetAppNameForTargetType(TargetType);
                }

                FileReference EngineCacheLocation = FileReference.Combine(UnrealBuildTool.EngineDirectory, UEBuildTarget.GetPlatformIntermediateFolder(Platform, Architecture), AppName, Configuration.ToString(), "DependencyCache.bin");
                Cache = FindOrAddCache(EngineCacheLocation, UnrealBuildTool.EngineDirectory, Cache);
            }

            if (ProjectFile != null)
            {
                FileReference ProjectCacheLocation = FileReference.Combine(ProjectFile.Directory, UEBuildTarget.GetPlatformIntermediateFolder(Platform, Architecture), TargetName, Configuration.ToString(), "DependencyCache.bin");
                Cache = FindOrAddCache(ProjectCacheLocation, ProjectFile.Directory, Cache);
            }

            return(Cache);
        }
Exemple #4
0
        /// <summary>
        /// Generates a full path to action history file for the specified target.
        /// </summary>
        public static FileReference GeneratePathForTarget(UEBuildTarget Target)
        {
            DirectoryReference 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
                DirectoryReference RootDirectory;
                if (Target.ProjectFile != null)
                {
                    RootDirectory = Target.ProjectFile.Directory;
                }
                else
                {
                    RootDirectory = UnrealBuildTool.EngineDirectory;
                }
                Folder = DirectoryReference.Combine(RootDirectory, BuildConfiguration.PlatformIntermediateFolder, Target.GetTargetName());
            }
            else
            {
                // Shared action history (unless this is an installed build target)
                Folder = (UnrealBuildTool.IsEngineInstalled() && Target.ProjectFile != null) ?
                         DirectoryReference.Combine(Target.ProjectFile.Directory, BuildConfiguration.BaseIntermediateFolder) :
                         DirectoryReference.Combine(UnrealBuildTool.EngineDirectory, BuildConfiguration.BaseIntermediateFolder);
            }
            return(FileReference.Combine(Folder, "ActionHistory.bin"));
        }
Exemple #5
0
 /// <summary>
 /// Add the given Engine ThirdParty modules as static private dependencies
 ///	Statically linked to this module, meaning they utilize exports from the other module
 ///	Private, meaning the include paths for the included modules will not be exposed when giving this modules include paths
 ///	NOTE: There is no AddThirdPartyPublicStaticDependencies function.
 /// </summary>
 /// <param name="Target">The target this module belongs to</param>
 /// <param name="ModuleNames">The names of the modules to add</param>
 public void AddEngineThirdPartyPrivateStaticDependencies(ReadOnlyTargetRules Target, params string[] ModuleNames)
 {
     if (!UnrealBuildTool.IsEngineInstalled() || Target.LinkType == TargetLinkType.Monolithic)
     {
         PrivateDependencyModuleNames.AddRange(ModuleNames);
     }
 }
Exemple #6
0
        /// <summary>
        /// Initialize the list of input files
        /// </summary>
        public static List <InputFile> FindInputFiles()
        {
            // Find all the input file locations
            List <InputFile> InputFiles = new List <InputFile>();

            // Skip all the config files under the Engine folder if it's an installed build
            if (!UnrealBuildTool.IsEngineInstalled())
            {
                // Check for the config file under /Engine/Programs/NotForLicensees/UnrealBuildTool
                FileReference NotForLicenseesConfigLocation = FileReference.Combine(UnrealBuildTool.EngineDirectory, "Programs", "NotForLicensees", "UnrealBuildTool", "BuildConfiguration.xml");
                if (FileReference.Exists(NotForLicenseesConfigLocation))
                {
                    InputFiles.Add(new InputFile {
                        Location = NotForLicenseesConfigLocation, FolderName = "NotForLicensees"
                    });
                }

                // Check for the user config file under /Engine/Programs/NotForLicensees/UnrealBuildTool
                FileReference UserConfigLocation = FileReference.Combine(UnrealBuildTool.EngineDirectory, "Saved", "UnrealBuildTool", "BuildConfiguration.xml");
                if (!FileReference.Exists(UserConfigLocation))
                {
                    CreateDefaultConfigFile(UserConfigLocation);
                }
                InputFiles.Add(new InputFile {
                    Location = UserConfigLocation, FolderName = "User"
                });
            }

            // Check for the global config file under AppData/Unreal Engine/UnrealBuildTool
            string AppDataFolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);

            if (!String.IsNullOrEmpty(AppDataFolder))
            {
                FileReference AppDataConfigLocation = FileReference.Combine(new DirectoryReference(AppDataFolder), "Unreal Engine", "UnrealBuildTool", "BuildConfiguration.xml");
                if (!FileReference.Exists(AppDataConfigLocation))
                {
                    CreateDefaultConfigFile(AppDataConfigLocation);
                }
                InputFiles.Add(new InputFile {
                    Location = AppDataConfigLocation, FolderName = "Global (AppData)"
                });
            }

            // Check for the global config file under My Documents/Unreal Engine/UnrealBuildTool
            string PersonalFolder = Environment.GetFolderPath(Environment.SpecialFolder.Personal);

            if (!String.IsNullOrEmpty(PersonalFolder))
            {
                FileReference PersonalConfigLocation = FileReference.Combine(new DirectoryReference(PersonalFolder), "Unreal Engine", "UnrealBuildTool", "BuildConfiguration.xml");
                if (FileReference.Exists(PersonalConfigLocation))
                {
                    InputFiles.Add(new InputFile {
                        Location = PersonalConfigLocation, FolderName = "Global (Documents)"
                    });
                }
            }

            return(InputFiles);
        }
 /// <summary>
 /// Add the given Engine ThirdParty modules as dynamic private dependencies
 ///	Dynamically linked to this module, meaning they do not utilize exports from the other module
 ///	Private, meaning the include paths for the included modules will not be exposed when giving this modules include paths
 ///	NOTE: There is no AddThirdPartyPublicDynamicDependencies function.
 /// </summary>
 /// <param name="ModuleNames">The names of the modules to add</param>
 public void AddEngineThirdPartyPrivateDynamicDependencies(TargetInfo Target, params string[] InModuleNames)
 {
     if (!UnrealBuildTool.IsEngineInstalled() || Target.IsMonolithic)
     {
         PrivateIncludePathModuleNames.AddRange(InModuleNames);
         DynamicallyLoadedModuleNames.AddRange(InModuleNames);
     }
 }
 /// <summary>
 /// Enumerates all the locations of metadata caches for the given target
 /// </summary>
 /// <param name="ProjectFile">Project file for the target being built</param>
 /// <returns>Dependency cache hierarchy for the given project</returns>
 public static IEnumerable <FileReference> GetFilesToClean(FileReference ProjectFile)
 {
     if (ProjectFile == null || !UnrealBuildTool.IsEngineInstalled())
     {
         yield return(FileReference.Combine(UnrealBuildTool.EngineDirectory, "Intermediate", "Build", "SourceFileCache.bin"));
     }
     if (ProjectFile != null)
     {
         yield return(FileReference.Combine(ProjectFile.Directory, "Intermediate", "Build", "SourceFileCache.bin"));
     }
 }
Exemple #9
0
 /// <summary>
 /// Enumerates all the locations of action history files for the given target
 /// </summary>
 /// <param name="ProjectFile">Project file for the target being built</param>
 /// <param name="TargetName">Name of the target</param>
 /// <param name="Platform">Platform being built</param>
 /// <param name="TargetType">The target type</param>
 /// <param name="Architecture">The target architecture</param>
 /// <returns>Dependency cache hierarchy for the given project</returns>
 public static IEnumerable <FileReference> GetFilesToClean(FileReference ProjectFile, string TargetName, UnrealTargetPlatform Platform, TargetType TargetType, string Architecture)
 {
     if (ProjectFile == null || !UnrealBuildTool.IsEngineInstalled())
     {
         yield return(GetEngineLocation(TargetName, Platform, TargetType, Architecture));
     }
     if (ProjectFile != null)
     {
         yield return(GetProjectLocation(ProjectFile, TargetName, Platform, Architecture));
     }
 }
        private static void SelectXcode(ref string DeveloperDir, bool bVerbose)
        {
            string Reason = "hardcoded";

            if (DeveloperDir == "xcode-select")
            {
                Reason = "xcode-select";

                // on the Mac, run xcode-select directly
                DeveloperDir = Utils.RunLocalProcessAndReturnStdOut("xcode-select", "--print-path");

                // make sure we get a full path
                if (Directory.Exists(DeveloperDir) == false)
                {
                    throw new BuildException("Selected Xcode ('{0}') doesn't exist, cannot continue.", DeveloperDir);
                }

                if (DeveloperDir.EndsWith("/") == false)
                {
                    // we expect this to end with a slash
                    DeveloperDir += "/";
                }
            }

            if (bVerbose && !DeveloperDir.StartsWith("/Applications/Xcode.app"))
            {
                Log.TraceInformationOnce("Compiling with non-standard Xcode ({0}): {1}", Reason, DeveloperDir);
            }

            // Installed engine requires Xcode 11
            if (UnrealBuildTool.IsEngineInstalled())
            {
                string XcodeBuilderVersionOutput = Utils.RunLocalProcessAndReturnStdOut("xcodebuild", "-version");
                if (XcodeBuilderVersionOutput.Length > 10)
                {
                    string[] Version = XcodeBuilderVersionOutput.Substring(6, 4).Split('.');
                    if (Version.Length == 2)
                    {
                        if (int.Parse(Version[0]) < 11)
                        {
                            throw new BuildException("Building for macOS, iOS and tvOS requires Xcode 11 or newer, Xcode " + Version[0] + "." + Version[1] + " detected");
                        }
                    }
                    else
                    {
                        Log.TraceWarning("Failed to query Xcode version");
                    }
                }
                else
                {
                    Log.TraceWarning("Failed to query Xcode version");
                }
            }
        }
 /// <summary>
 /// Determes the path to the game-agnostic saved directory (same as FPaths::GameAgnosticSavedDir())
 /// </summary>
 /// <returns></returns>
 public static DirectoryReference GetGameAgnosticSavedDir()
 {
     if (UnrealBuildTool.IsEngineInstalled())
     {
         return(DirectoryReference.Combine(Utils.GetUserSettingDirectory(), "UnrealEngine", String.Format("{0}.{1}", ReadOnlyBuildVersion.Current.MajorVersion, ReadOnlyBuildVersion.Current.MinorVersion), "Saved"));
     }
     else
     {
         return(DirectoryReference.Combine(UnrealBuildTool.EngineDirectory, "Saved"));
     }
 }
Exemple #12
0
        /// <summary>
        /// Loads JunkManifest.txt file and removes all junk files/folders defined in it.
        /// </summary>
        static public void DeleteJunk()
        {
            DateTime JunkStartTime = DateTime.UtcNow;

            if (UnrealBuildTool.IsEngineInstalled() == false)
            {
                List <string> JunkManifest = LoadJunkManifest();
                DeleteAllJunk(JunkManifest);
            }

            if (BuildConfiguration.bPrintPerformanceInfo)
            {
                double JunkTime = (DateTime.UtcNow - JunkStartTime).TotalSeconds;
                Log.TraceInformation("DeleteJunk took " + JunkTime + "s");
            }
        }
        /// <summary>
        /// Updates the intermediate include directory timestamps of all the passed in UObject modules
        /// </summary>
        private static void UpdateDirectoryTimestamps(List <UHTModuleInfo> UObjectModules)
        {
            foreach (var Module in UObjectModules)
            {
                string GeneratedCodeDirectory     = Path.GetDirectoryName(Module.GeneratedCPPFilenameBase);
                var    GeneratedCodeDirectoryInfo = new DirectoryInfo(GeneratedCodeDirectory);

                try
                {
                    if (GeneratedCodeDirectoryInfo.Exists)
                    {
                        // Don't write anything to the engine directory if we're running an installed build
                        if (UnrealBuildTool.IsEngineInstalled() && new DirectoryReference(Module.ModuleDirectory).IsUnderDirectory(UnrealBuildTool.EngineDirectory))
                        {
                            continue;
                        }

                        // Touch the include directory since we have technically 'generated' the headers
                        // However, the headers might not be touched at all since that would cause the compiler to recompile everything
                        // We can't alter the directory timestamp directly, because this may throw exceptions when the directory is
                        // open in visual studio or windows explorer, so instead we create a blank file that will change the timestamp for us
                        FileReference TimestampFile = FileReference.Combine(new DirectoryReference(GeneratedCodeDirectoryInfo.FullName), "Timestamp");

                        if (!GeneratedCodeDirectoryInfo.Exists)
                        {
                            GeneratedCodeDirectoryInfo.Create();
                        }

                        // Save all of the UObject files to a timestamp file.  We'll load these on the next run to see if any new
                        // files with UObject classes were deleted, so that we'll know to run UHT even if the timestamps of all
                        // of the other source files were unchanged
                        {
                            var AllUObjectFiles = new List <string>();
                            AllUObjectFiles.AddRange(Module.PublicUObjectClassesHeaders.ConvertAll(Item => Item.AbsolutePath));
                            AllUObjectFiles.AddRange(Module.PublicUObjectHeaders.ConvertAll(Item => Item.AbsolutePath));
                            AllUObjectFiles.AddRange(Module.PrivateUObjectHeaders.ConvertAll(Item => Item.AbsolutePath));
                            ResponseFile.Create(TimestampFile, AllUObjectFiles);
                        }
                    }
                }
                catch (Exception Exception)
                {
                    throw new BuildException(Exception, "Couldn't touch header directories: " + Exception.Message);
                }
            }
        }
        public override bool GenerateProjectFiles(PlatformProjectGeneratorCollection PlatformProjectGenerators,
                                                  String[] arguments)
        {
            ConfigureProjectFileGeneration();

            if (bGeneratingGameProjectFiles || UnrealBuildTool.IsEngineInstalled())
            {
                MasterProjectPath = OnlyGameProject.Directory;
                MasterProjectName = OnlyGameProject.GetFileNameWithoutExtension();

                if (!DirectoryReference.Exists(DirectoryReference.Combine(MasterProjectPath, "Source")))
                {
                    if (!DirectoryReference.Exists(DirectoryReference.Combine(MasterProjectPath, "Intermediate",
                                                                              "Source")))
                    {
                        if (BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac)
                        {
                            MasterProjectPath = UnrealBuildTool.EngineDirectory;
                            GameProjectName   = "UE4Game";
                        }

                        if (!DirectoryReference.Exists(DirectoryReference.Combine(MasterProjectPath, "Source")))
                        {
                            throw new BuildException("Directory '{0}' is missing 'Source' folder.", MasterProjectPath);
                        }
                    }
                }

                IntermediateProjectFilesPath =
                    DirectoryReference.Combine(MasterProjectPath, "Intermediate", "ProjectFiles");
            }

            SetupSupportedPlatformsAndConfigurations();

            Log.TraceVerbose("Detected supported platforms: " + SupportedPlatforms);

            List <FileReference> AllGameProjects = FindGameProjects();

            GatherProjects(PlatformProjectGenerators, AllGameProjects);

            WriteProjectFiles(PlatformProjectGenerators);
            Log.TraceVerbose("Project generation complete ({0} generated, {1} imported)", GeneratedProjectFiles.Count,
                             OtherProjectFiles.Count);

            return(true);
        }
Exemple #15
0
        /// <summary>
        /// Creates a hierarchy of action history stores for a particular target
        /// </summary>
        /// <param name="ProjectFile">Project file for the target being built</param>
        /// <param name="TargetName">Name of the target</param>
        /// <param name="Platform">Platform being built</param>
        /// <param name="TargetType">The target type</param>
        /// <param name="Architecture">The target architecture</param>
        /// <returns>Dependency cache hierarchy for the given project</returns>
        public static ActionHistory CreateHierarchy(FileReference ProjectFile, string TargetName, UnrealTargetPlatform Platform, TargetType TargetType, string Architecture)
        {
            ActionHistory History = null;

            if (ProjectFile == null || !UnrealBuildTool.IsEngineInstalled())
            {
                FileReference EngineCacheLocation = GetEngineLocation(TargetName, Platform, TargetType, Architecture);
                History = FindOrAddHistory(EngineCacheLocation, UnrealBuildTool.EngineDirectory, History);
            }

            if (ProjectFile != null)
            {
                FileReference ProjectCacheLocation = GetProjectLocation(ProjectFile, TargetName, Platform, Architecture);
                History = FindOrAddHistory(ProjectCacheLocation, ProjectFile.Directory, History);
            }

            return(History);
        }
        /// <summary>
        /// Creates a cache hierarchy for a particular target
        /// </summary>
        /// <param name="ProjectFile">Project file for the target being built</param>
        /// <returns>Dependency cache hierarchy for the given project</returns>
        public static SourceFileMetadataCache CreateHierarchy(FileReference ProjectFile)
        {
            SourceFileMetadataCache Cache = null;

            if (ProjectFile == null || !UnrealBuildTool.IsEngineInstalled())
            {
                FileReference EngineCacheLocation = FileReference.Combine(UnrealBuildTool.EngineDirectory, "Intermediate", "Build", "SourceFileCache.bin");
                Cache = FindOrAddCache(EngineCacheLocation, UnrealBuildTool.EngineDirectory, Cache);
            }

            if (ProjectFile != null)
            {
                FileReference ProjectCacheLocation = FileReference.Combine(ProjectFile.Directory, "Intermediate", "Build", "SourceFileCache.bin");
                Cache = FindOrAddCache(ProjectCacheLocation, ProjectFile.Directory, Cache);
            }

            return(Cache);
        }
Exemple #17
0
        /** Updates the intermediate include directory timestamps of all the passed in UObject modules */
        private static void UpdateDirectoryTimestamps(List <UHTModuleInfo> UObjectModules)
        {
            foreach (var Module in UObjectModules)
            {
                string GeneratedCodeDirectory     = Path.GetDirectoryName(Module.GeneratedCPPFilenameBase);
                var    GeneratedCodeDirectoryInfo = new DirectoryInfo(GeneratedCodeDirectory);

                try
                {
                    if (GeneratedCodeDirectoryInfo.Exists)
                    {
                        // Don't write anything to the engine directory if we're running an installed build
                        if (UnrealBuildTool.IsEngineInstalled() && Utils.IsFileUnderDirectory(Module.ModuleDirectory, BuildConfiguration.RelativeEnginePath))
                        {
                            continue;
                        }

                        // Touch the include directory since we have technically 'generated' the headers
                        // However, the headers might not be touched at all since that would cause the compiler to recompile everything
                        // We can't alter the directory timestamp directly, because this may throw exceptions when the directory is
                        // open in visual studio or windows explorer, so instead we create a blank file that will change the timestamp for us
                        string TimestampFile = GeneratedCodeDirectoryInfo.FullName + Path.DirectorySeparatorChar + @"Timestamp";

                        if (!GeneratedCodeDirectoryInfo.Exists)
                        {
                            GeneratedCodeDirectoryInfo.Create();
                        }

                        if (File.Exists(TimestampFile))
                        {
                            File.Delete(TimestampFile);
                        }
                        using (File.Create(TimestampFile))
                        {
                        }
                    }
                }
                catch (Exception Exception)
                {
                    throw new BuildException(Exception, "Couldn't touch header directories: " + Exception.Message);
                }
            }
        }
        private bool ContainsValidConfiguration(Predicate <InstalledPlatformConfiguration> ConfigFilter)
        {
            if (UnrealBuildTool.IsEngineInstalled())
            {
                foreach (InstalledPlatformConfiguration PlatformConfiguration in InstalledPlatformConfigurations)
                {
                    // Check whether filter accepts this configuration and it has required file
                    if (ConfigFilter(PlatformConfiguration) &&
                        (string.IsNullOrEmpty(PlatformConfiguration.RequiredFile) ||
                         File.Exists(PlatformConfiguration.RequiredFile)))
                    {
                        return(true);
                    }
                }

                return(false);
            }
            return(true);
        }
        public UHTManifest(UEBuildTarget Target, string InRootLocalPath, string InRootBuildPath, IEnumerable <UHTModuleInfo> ModuleInfo)
        {
            IsGameTarget  = TargetRules.IsGameType(Target.TargetType);
            RootLocalPath = InRootLocalPath;
            RootBuildPath = InRootBuildPath;
            TargetName    = Target.GetTargetName();

            Modules = ModuleInfo.Select(Info => new Module
            {
                Name                     = Info.ModuleName,
                ModuleType               = Info.ModuleType,
                BaseDirectory            = Info.ModuleDirectory,
                IncludeBase              = Info.ModuleDirectory,
                OutputDirectory          = Path.GetDirectoryName(Info.GeneratedCPPFilenameBase),
                ClassesHeaders           = Info.PublicUObjectClassesHeaders.Select((Header) => Header.AbsolutePath).ToList(),
                PublicHeaders            = Info.PublicUObjectHeaders.Select((Header) => Header.AbsolutePath).ToList(),
                PrivateHeaders           = Info.PrivateUObjectHeaders.Select((Header) => Header.AbsolutePath).ToList(),
                PCH                      = Info.PCH,
                GeneratedCPPFilenameBase = Info.GeneratedCPPFilenameBase,
                SaveExportedHeaders      = !UnrealBuildTool.IsEngineInstalled() || !new DirectoryReference(Info.ModuleDirectory).IsUnderDirectory(UnrealBuildTool.EngineDirectory),
                UHTGeneratedCodeVersion  = Info.GeneratedCodeVersion,
            }).ToList();
        }
Exemple #20
0
        /// <summary>
        /// Determines whether the given target type is supported
        /// </summary>
        /// <param name="TargetType">The target type being built</param>
        /// <param name="Platform">The platform being built</param>
        /// <param name="Configuration">The configuration being built</param>
        /// <param name="ProjectType">The project type required</param>
        /// <param name="State">State of the given platform support</param>
        /// <returns>True if the target can be built</returns>
        public static bool IsValid(TargetType?TargetType, UnrealTargetPlatform?Platform, UnrealTargetConfiguration?Configuration, EProjectType ProjectType, InstalledPlatformState State)
        {
            if (!UnrealBuildTool.IsEngineInstalled() || InstalledPlatformConfigurations == null)
            {
                return(true);
            }

            foreach (InstalledPlatformConfiguration Config in InstalledPlatformConfigurations)
            {
                // Check whether this configuration matches all the criteria
                if (TargetType.HasValue && Config.PlatformType != TargetType.Value)
                {
                    continue;
                }
                if (Platform.HasValue && Config.Platform != Platform.Value)
                {
                    continue;
                }
                if (Configuration.HasValue && Config.Configuration != Configuration.Value)
                {
                    continue;
                }
                if (ProjectType != EProjectType.Any && Config.ProjectType != EProjectType.Any && Config.ProjectType != ProjectType)
                {
                    continue;
                }
                if (State == InstalledPlatformState.Downloaded && !String.IsNullOrEmpty(Config.RequiredFile) && !File.Exists(Config.RequiredFile))
                {
                    continue;
                }

                // Success!
                return(true);
            }

            return(false);
        }
        /// <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);
        }
Exemple #22
0
 /// <summary>
 /// Creates the engine rules assembly
 /// </summary>
 /// <param name="bUsePrecompiled">Whether to use a precompiled engine</param>
 /// <param name="bSkipCompile">Whether to skip compilation for this assembly</param>
 /// <returns>New rules assembly</returns>
 public static RulesAssembly CreateEngineRulesAssembly(bool bUsePrecompiled, bool bSkipCompile)
 {
     if (EngineRulesAssembly == null)
     {
         IReadOnlyList <PluginInfo> IncludedPlugins = Plugins.ReadEnginePlugins(UnrealBuildTool.EngineDirectory);
         EngineRulesAssembly = CreateEngineOrEnterpriseRulesAssembly(UnrealBuildTool.EngineDirectory, ProjectFileGenerator.EngineProjectFileNameBase, IncludedPlugins, UnrealBuildTool.IsEngineInstalled() || bUsePrecompiled, bSkipCompile, null);
     }
     return(EngineRulesAssembly);
 }
Exemple #23
0
 /// <summary>
 /// Allows a target to choose whether to use the shared build environment for a given configuration. Using
 /// the shared build environment allows binaries to be reused between targets, but prevents customizing the
 /// compile environment through SetupGlobalEnvironment().
 /// </summary>
 /// <param name="Target">Information about the target</param>
 /// <returns>True if the target should use the shared build environment</returns>
 public virtual bool ShouldUseSharedBuildEnvironment(TargetInfo Target)
 {
     return(UnrealBuildTool.IsEngineInstalled() || (Target.Type != TargetType.Program && !Target.IsMonolithic));
 }
Exemple #24
0
        /// <summary>
        /// Creates the engine rules assembly
        /// </summary>
        /// <param name="bUsePrecompiled">Whether to use a precompiled engine</param>
        /// <param name="bSkipCompile">Whether to skip compilation for this assembly</param>
        /// <returns>New rules assembly</returns>
        public static RulesAssembly CreateEngineRulesAssembly(bool bUsePrecompiled, bool bSkipCompile)
        {
            if (EngineRulesAssembly == null)
            {
                List <PluginInfo> IncludedPlugins = new List <PluginInfo>();

                // search for all engine plugins
                IncludedPlugins.AddRange(Plugins.ReadEnginePlugins(UnrealBuildTool.EngineDirectory));

                RulesScope EngineScope = new RulesScope("Engine", null);

                EngineRulesAssembly = CreateEngineOrEnterpriseRulesAssembly(EngineScope, UnrealBuildTool.GetAllEngineDirectories().ToList(), ProjectFileGenerator.EngineProjectFileNameBase, IncludedPlugins, UnrealBuildTool.IsEngineInstalled() || bUsePrecompiled, bSkipCompile, null);
            }
            return(EngineRulesAssembly);
        }
Exemple #25
0
        /// <summary>
        /// Construct an instance of the given target rules
        /// </summary>
        /// <param name="TypeName">Type name of the target rules</param>
        /// <param name="TargetInfo">Target configuration information to pass to the constructor</param>
        /// <param name="Arguments">Command line arguments for this target</param>
        /// <returns>Instance of the corresponding TargetRules</returns>
        protected TargetRules CreateTargetRulesInstance(string TypeName, TargetInfo TargetInfo, string[] Arguments)
        {
            // The build module must define a type named '<TargetName>Target' that derives from our 'TargetRules' type.
            Type RulesType = CompiledAssembly.GetType(TypeName);

            if (RulesType == null)
            {
                throw new BuildException("Expecting to find a type to be declared in a target rules named '{0}'.  This type must derive from the 'TargetRules' type defined by Unreal Build Tool.", TypeName);
            }

            // Create an instance of the module's rules object, and set some defaults before calling the constructor.
            TargetRules Rules = (TargetRules)FormatterServices.GetUninitializedObject(RulesType);

            Rules.bUseBackwardsCompatibleDefaults = bUseBackwardsCompatibleDefaults;

            // Find the constructor
            ConstructorInfo Constructor = RulesType.GetConstructor(new Type[] { typeof(TargetInfo) });

            if (Constructor == null)
            {
                throw new BuildException("No constructor found on {0} which takes an argument of type TargetInfo.", RulesType.Name);
            }

            // Invoke the regular constructor
            try
            {
                Constructor.Invoke(Rules, new object[] { TargetInfo });
            }
            catch (Exception Ex)
            {
                throw new BuildException(Ex, "Unable to instantiate instance of '{0}' object type from compiled assembly '{1}'.  Unreal Build Tool creates an instance of your module's 'Rules' object in order to find out about your module's requirements.  The CLR exception details may provide more information:  {2}", TypeName, Path.GetFileNameWithoutExtension(CompiledAssembly.Location), Ex.ToString());
            }

            // Set the default overriddes for the configured target type
            Rules.SetOverridesForTargetType();

            // Parse any additional command-line arguments. These override default settings specified in config files or the .target.cs files.
            if (Arguments != null)
            {
                foreach (object ConfigurableObject in Rules.GetConfigurableObjects())
                {
                    CommandLine.ParseArguments(Arguments, ConfigurableObject);
                }
            }

            // Set the final value for the link type in the target rules
            if (Rules.LinkType == TargetLinkType.Default)
            {
                throw new BuildException("TargetRules.LinkType should be inferred from TargetType");
            }

            // Set the default value for whether to use the shared build environment
            if (Rules.BuildEnvironment == TargetBuildEnvironment.Default)
            {
                if (Rules.Type == TargetType.Program && TargetInfo.ProjectFile != null && TargetNameToTargetFile[Rules.Name].IsUnderDirectory(TargetInfo.ProjectFile.Directory))
                {
                    Rules.BuildEnvironment = TargetBuildEnvironment.Unique;
                }
                else if (UnrealBuildTool.IsEngineInstalled() || Rules.LinkType != TargetLinkType.Monolithic)
                {
                    Rules.BuildEnvironment = TargetBuildEnvironment.Shared;
                }
                else
                {
                    Rules.BuildEnvironment = TargetBuildEnvironment.Unique;
                }
            }

            // Lean and mean means no Editor and other frills.
            if (Rules.bCompileLeanAndMeanUE)
            {
                Rules.bBuildEditor         = false;
                Rules.bBuildDeveloperTools = Rules.bBuildDeveloperTools ?? false;
                Rules.bCompileSimplygon    = false;
                Rules.bCompileSimplygonSSF = false;
                Rules.bCompileSpeedTree    = false;
            }

            // if the bBuildDeveloperTools switch hasn't been defined, default it to the bCompileAgainstEngine switch.
            if (!Rules.bBuildDeveloperTools.HasValue)
            {
                Rules.bBuildDeveloperTools = Rules.bCompileAgainstEngine;
            }

            // Automatically include CoreUObject
            if (Rules.bCompileAgainstEngine)
            {
                Rules.bCompileAgainstCoreUObject = true;
            }

            // Must have editor only data if building the editor.
            if (Rules.bBuildEditor)
            {
                Rules.bBuildWithEditorOnlyData = true;
            }

            // Apply the override to force debug info to be enabled
            if (Rules.bForceDebugInfo)
            {
                Rules.bDisableDebugInfo             = false;
                Rules.bOmitPCDebugInfoInDevelopment = false;
            }

            // Setup the malloc profiler
            if (Rules.bUseMallocProfiler)
            {
                Rules.bOmitFramePointers = false;
                Rules.GlobalDefinitions.Add("USE_MALLOC_PROFILER=1");
            }

            // Set a macro if we allow using generated inis
            if (!Rules.bAllowGeneratedIniWhenCooked)
            {
                Rules.GlobalDefinitions.Add("DISABLE_GENERATED_INI_WHEN_COOKED=1");
            }

            return(Rules);
        }
        /// <summary>
        /// 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
        /// </summary>
        public static bool ExecuteHeaderToolIfNecessary(UEToolChain ToolChain, UEBuildTarget Target, CPPEnvironment GlobalCompileEnvironment, List <UHTModuleInfo> UObjectModules, FileReference ModuleInfoFileName, ref ECompilationResult UHTResult)
        {
            if (ProgressWriter.bWriteMarkup)
            {
                Log.WriteLine(LogEventType.Console, "@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 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
                        if (UnrealBuildTool.CommandLineContains("-2015"))
                        {
                            UBTArguments.Append(" -2015");
                        }
                        if (UnrealBuildTool.CommandLineContains("-2013"))
                        {
                            UBTArguments.Append(" -2013");
                        }

                        // Add UHT plugins to UBT command line as external plugins
                        if (Target.UnrealHeaderToolPlugins != null && Target.UnrealHeaderToolPlugins.Count > 0)
                        {
                            foreach (PluginInfo Plugin in Target.UnrealHeaderToolPlugins)
                            {
                                UBTArguments.Append(" -PLUGIN \"" + Plugin.File + "\"");
                            }
                        }

                        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(ModuleInfoFileName.Directory.FullName);
                    System.IO.File.WriteAllText(ModuleInfoFileName.FullName, fastJSON.JSON.Instance.ToJSON(Manifest, new fastJSON.JSONParameters {
                        UseExtensions = false
                    }));

                    string CmdLine = (Target.ProjectFile != null) ? "\"" + Target.ProjectFile.FullName + "\"" : Target.GetTargetName();
                    CmdLine += " \"" + ModuleInfoFileName + "\" -LogCmds=\"loginit warning, logexit warning, logdatabase error\" -Unattended -WarningsAsErrors";
                    if (UnrealBuildTool.IsEngineInstalled())
                    {
                        CmdLine += " -installed";
                    }

                    if (UEBuildConfiguration.bFailIfGeneratedCodeChanges)
                    {
                        CmdLine += " -FailIfGeneratedCodeChanges";
                    }

                    if (!bInvalidateUHTMakefile && BuildConfiguration.bUseUHTMakefiles)
                    {
                        CmdLine += " -UseMakefiles";
                    }

                    if (!UEBuildConfiguration.bCompileAgainstEngine)
                    {
                        CmdLine += " -NoEnginePlugins";
                    }

                    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(LogEventType.Console, "@progress pop");
            }
            return(true);
        }
Exemple #27
0
        /// <summary>
        /// Initialize the config system with the given types
        /// </summary>
        /// <param name="OverrideCacheFile">Force use of the cached XML config without checking if it's valid (useful for remote builds)</param>
        public static void ReadConfigFiles(FileReference OverrideCacheFile)
        {
            // Find all the configurable types
            List <Type> ConfigTypes = FindConfigurableTypes();

            // Update the cache if necessary
            if (OverrideCacheFile != null)
            {
                // Set the cache file to the overriden value
                CacheFile = OverrideCacheFile;

                // Never rebuild the cache; just try to load it.
                if (!XmlConfigData.TryRead(CacheFile, ConfigTypes, out Values))
                {
                    throw new BuildException("Unable to load XML config cache ({0})", CacheFile);
                }
            }
            else
            {
                // Get the default cache file
                CacheFile = FileReference.Combine(UnrealBuildTool.EngineDirectory, "Intermediate", "Build", "XmlConfigCache.bin");
                if (UnrealBuildTool.IsEngineInstalled())
                {
                    DirectoryReference UserSettingsDir = Utils.GetUserSettingDirectory();
                    if (UserSettingsDir != null)
                    {
                        CacheFile = FileReference.Combine(UserSettingsDir, "UnrealEngine", String.Format("XmlConfigCache-{0}.bin", UnrealBuildTool.RootDirectory.FullName.Replace(":", "").Replace(Path.DirectorySeparatorChar, '+')));
                    }
                }

                // Find all the input files
                FileReference[] InputFiles = FindInputFiles().Select(x => x.Location).ToArray();

                // Get the path to the schema
                FileReference SchemaFile = GetSchemaLocation();

                // Try to read the existing cache from disk
                XmlConfigData CachedValues;
                if (IsCacheUpToDate(CacheFile, InputFiles) && FileReference.Exists(SchemaFile))
                {
                    if (XmlConfigData.TryRead(CacheFile, ConfigTypes, out CachedValues) && Enumerable.SequenceEqual(InputFiles, CachedValues.InputFiles))
                    {
                        Values = CachedValues;
                    }
                }

                // If that failed, regenerate it
                if (Values == null)
                {
                    // Find all the configurable fields from the given types
                    Dictionary <string, Dictionary <string, FieldInfo> > CategoryToFields = new Dictionary <string, Dictionary <string, FieldInfo> >();
                    FindConfigurableFields(ConfigTypes, CategoryToFields);

                    // Create a schema for the config files
                    XmlSchema Schema = CreateSchema(CategoryToFields);
                    if (!UnrealBuildTool.IsEngineInstalled())
                    {
                        WriteSchema(Schema, SchemaFile);
                    }

                    // Read all the XML files and validate them against the schema
                    Dictionary <Type, Dictionary <FieldInfo, object> > TypeToValues = new Dictionary <Type, Dictionary <FieldInfo, object> >();
                    foreach (FileReference InputFile in InputFiles)
                    {
                        if (!TryReadFile(InputFile, CategoryToFields, TypeToValues, Schema))
                        {
                            throw new BuildException("Failed to properly read XML file : {0}", InputFile.FullName);
                        }
                    }

                    // Make sure the cache directory exists
                    DirectoryReference.CreateDirectory(CacheFile.Directory);

                    // Create the new cache
                    Values = new XmlConfigData(InputFiles, TypeToValues.ToDictionary(x => x.Key, x => x.Value.ToArray()));
                    Values.Write(CacheFile);
                }
            }

            // Apply all the static field values
            foreach (KeyValuePair <Type, KeyValuePair <FieldInfo, object>[]> TypeValuesPair in Values.TypeToValues)
            {
                foreach (KeyValuePair <FieldInfo, object> FieldValuePair in TypeValuesPair.Value)
                {
                    if (FieldValuePair.Key.IsStatic)
                    {
                        object Value = InstanceValue(FieldValuePair.Value, FieldValuePair.Key.FieldType);
                        FieldValuePair.Key.SetValue(null, Value);
                    }
                }
            }
        }
        /// <summary>
        /// Checks the class header files and determines if generated UObject code files are out of date in comparison.
        /// </summary>
        /// <param name="UObjectModules">Modules that we generate headers for</param>
        /// <returns>    True if the code files are out of date</returns>
        private static bool AreGeneratedCodeFilesOutOfDate(List <UHTModuleInfo> UObjectModules, DateTime HeaderToolTimestamp)
        {
            // Get CoreUObject.generated.cpp timestamp.  If the source files are older than the CoreUObject generated code, we'll
            // need to regenerate code for the module
            DateTime?CoreGeneratedTimestamp = null;

            {
                // Find the CoreUObject module
                foreach (var Module in UObjectModules)
                {
                    if (Module.ModuleName.Equals("CoreUObject", StringComparison.InvariantCultureIgnoreCase))
                    {
                        CoreGeneratedTimestamp = GetCoreGeneratedTimestamp(Module.ModuleName, Path.GetDirectoryName(Module.GeneratedCPPFilenameBase));
                        break;
                    }
                }
                if (CoreGeneratedTimestamp == null)
                {
                    throw new BuildException("Could not find CoreUObject in list of all UObjectModules");
                }
            }


            foreach (var Module in UObjectModules)
            {
                // If the engine is installed, skip skip checking timestamps for modules that are under the engine directory
                if (UnrealBuildTool.IsEngineInstalled() && new DirectoryReference(Module.ModuleDirectory).IsUnderDirectory(UnrealBuildTool.EngineDirectory))
                {
                    continue;
                }

                // Make sure we have an existing folder for generated code.  If not, then we definitely need to generate code!
                var GeneratedCodeDirectory = Path.GetDirectoryName(Module.GeneratedCPPFilenameBase);
                var TestDirectory          = (FileSystemInfo) new DirectoryInfo(GeneratedCodeDirectory);
                if (!TestDirectory.Exists)
                {
                    // Generated code directory is missing entirely!
                    Log.TraceVerbose("UnrealHeaderTool needs to run because no generated code directory was found for module {0}", Module.ModuleName);
                    return(true);
                }

                // Grab our special "Timestamp" file that we saved after the last set of headers were generated.  This file
                // actually contains the list of source files which contained UObjects, so that we can compare to see if any
                // UObject source files were deleted (or no longer contain UObjects), which means we need to run UHT even
                // if no other source files were outdated
                string TimestampFile          = Path.Combine(GeneratedCodeDirectory, @"Timestamp");
                var    SavedTimestampFileInfo = (FileSystemInfo) new FileInfo(TimestampFile);
                if (!SavedTimestampFileInfo.Exists)
                {
                    // Timestamp file was missing (possibly deleted/cleaned), so headers are out of date
                    Log.TraceVerbose("UnrealHeaderTool needs to run because UHT Timestamp file did not exist for module {0}", Module.ModuleName);
                    return(true);
                }

                // Make sure the last UHT run completed after UnrealHeaderTool.exe was compiled last, and after the CoreUObject headers were touched last.
                var SavedTimestamp = SavedTimestampFileInfo.LastWriteTime;
                if (HeaderToolTimestamp > SavedTimestamp || CoreGeneratedTimestamp > SavedTimestamp)
                {
                    // Generated code is older than UnrealHeaderTool.exe or CoreUObject headers.  Out of date!
                    Log.TraceVerbose("UnrealHeaderTool needs to run because UnrealHeaderTool.exe or CoreUObject headers are newer than SavedTimestamp for module {0}", Module.ModuleName);
                    return(true);
                }

                // Iterate over our UObjects headers and figure out if any of them have changed
                var AllUObjectHeaders = new List <FileItem>();
                AllUObjectHeaders.AddRange(Module.PublicUObjectClassesHeaders);
                AllUObjectHeaders.AddRange(Module.PublicUObjectHeaders);
                AllUObjectHeaders.AddRange(Module.PrivateUObjectHeaders);

                // Load up the old timestamp file and check to see if anything has changed
                {
                    var UObjectFilesFromPreviousRun = File.ReadAllLines(TimestampFile);
                    if (AllUObjectHeaders.Count != UObjectFilesFromPreviousRun.Length)
                    {
                        Log.TraceVerbose("UnrealHeaderTool needs to run because there are a different number of UObject source files in module {0}", Module.ModuleName);
                        return(true);
                    }
                    for (int FileIndex = 0; FileIndex < AllUObjectHeaders.Count; ++FileIndex)
                    {
                        if (!UObjectFilesFromPreviousRun[FileIndex].Equals(AllUObjectHeaders[FileIndex].AbsolutePath, StringComparison.InvariantCultureIgnoreCase))
                        {
                            Log.TraceVerbose("UnrealHeaderTool needs to run because the set of UObject source files in module {0} has changed", Module.ModuleName);
                            return(true);
                        }
                    }
                }

                foreach (var HeaderFile in AllUObjectHeaders)
                {
                    var HeaderFileTimestamp = HeaderFile.Info.LastWriteTime;

                    // Has the source header changed since we last generated headers successfully?
                    if (HeaderFileTimestamp > SavedTimestamp)
                    {
                        Log.TraceVerbose("UnrealHeaderTool needs to run because SavedTimestamp is older than HeaderFileTimestamp ({0}) for module {1}", HeaderFile.AbsolutePath, Module.ModuleName);
                        return(true);
                    }

                    // When we're running in assembler mode, outdatedness cannot be inferred by checking the directory timestamp
                    // of the source headers.  We don't care if source files were added or removed in this mode, because we're only
                    // able to process the known UObject headers that are in the Makefile.  If UObject header files are added/removed,
                    // we expect the user to re-run GenerateProjectFiles which will force UBTMakefile outdatedness.
                    // @todo ubtmake: Possibly, we should never be doing this check these days.
                    if (UnrealBuildTool.IsGatheringBuild || !UnrealBuildTool.IsAssemblingBuild)
                    {
                        // Also check the timestamp on the directory the source file is in.  If the directory timestamp has
                        // changed, new source files may have been added or deleted.  We don't know whether the new/deleted
                        // files were actually UObject headers, but because we don't know all of the files we processed
                        // in the previous run, we need to assume our generated code is out of date if the directory timestamp
                        // is newer.
                        var HeaderDirectoryTimestamp = new DirectoryInfo(Path.GetDirectoryName(HeaderFile.AbsolutePath)).LastWriteTime;
                        if (HeaderDirectoryTimestamp > SavedTimestamp)
                        {
                            Log.TraceVerbose("UnrealHeaderTool needs to run because the directory containing an existing header ({0}) has changed, and headers may have been added to or deleted from module {1}", HeaderFile.AbsolutePath, Module.ModuleName);
                            return(true);
                        }
                    }
                }
            }

            return(false);
        }
        /// <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);
        }
Exemple #30
0
        /// <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);
        }