Exemplo n.º 1
0
        public override void FinalizeOutput(ReadOnlyTargetRules Target, TargetMakefile Makefile)
        {
            FileReference OutputFile;

            if (Target.ProjectFile == null)
            {
                OutputFile = FileReference.Combine(UnrealBuildTool.EngineDirectory, "Saved", "PVS-Studio", String.Format("{0}.pvslog", Target.Name));
            }
            else
            {
                OutputFile = FileReference.Combine(Target.ProjectFile.Directory, "Saved", "PVS-Studio", String.Format("{0}.pvslog", Target.Name));
            }

            List <FileReference> InputFiles = Makefile.OutputItems.Select(x => x.Location).Where(x => x.HasExtension(".pvslog")).ToList();

            // Collect the prerequisite items off of the Compile action added in CompileCPPFiles so that in SingleFileCompile mode the PVSGather step is also not filtered out
            List <FileItem> AnalyzeActionPrerequisiteItems = Makefile.Actions.Where(x => x.ActionType == ActionType.Compile).SelectMany(x => x.PrerequisiteItems).ToList();

            FileItem InputFileListItem = Makefile.CreateIntermediateTextFile(OutputFile.ChangeExtension(".input"), InputFiles.Select(x => x.FullName));

            Action AnalyzeAction = Makefile.CreateAction(ActionType.Compile);

            AnalyzeAction.CommandPath      = UnrealBuildTool.GetUBTPath();
            AnalyzeAction.CommandArguments = String.Format("-Mode=PVSGather -Input=\"{0}\" -Output=\"{1}\"", InputFileListItem.Location, OutputFile);
            AnalyzeAction.WorkingDirectory = UnrealBuildTool.EngineSourceDirectory;
            AnalyzeAction.PrerequisiteItems.Add(InputFileListItem);
            AnalyzeAction.PrerequisiteItems.AddRange(Makefile.OutputItems);
            AnalyzeAction.PrerequisiteItems.AddRange(AnalyzeActionPrerequisiteItems);
            AnalyzeAction.ProducedItems.Add(FileItem.GetItemByFileReference(OutputFile));
            AnalyzeAction.DeleteItems.AddRange(AnalyzeAction.ProducedItems);

            Makefile.OutputItems.AddRange(AnalyzeAction.ProducedItems);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Creates an action which calls UBT recursively
        /// </summary>
        /// <param name="Type">Type of the action</param>
        /// <param name="Arguments">Arguments for the action</param>
        /// <returns>New action instance</returns>
        public static Action CreateRecursiveAction <T>(ActionType Type, string Arguments) where T : ToolMode
        {
            ToolModeAttribute Attribute = typeof(T).GetCustomAttribute <ToolModeAttribute>();

            if (Attribute == null)
            {
                throw new BuildException("Missing ToolModeAttribute on {0}", typeof(T).Name);
            }

            Action NewAction = new Action(Type);

            NewAction.CommandPath      = UnrealBuildTool.GetUBTPath();
            NewAction.CommandArguments = String.Format("-Mode={0} {1}", Attribute.Name, Arguments);
            return(NewAction);
        }
Exemplo n.º 3
0
        public static string EmscriptenSDKPath()
        {
            var ConfigCache = new ConfigCacheIni(UnrealTargetPlatform.HTML5, "Engine", UnrealBuildTool.GetUProjectPath());
            // always pick from the Engine the root directory and NOT the staged engine directory.
            string IniFile = Path.GetFullPath(Path.GetDirectoryName(UnrealBuildTool.GetUBTPath()) + "/../../") + "Config/HTML5/HTML5Engine.ini";

            ConfigCache.ParseIniFile(IniFile);

            string PlatformName = "";

            if (!Utils.IsRunningOnMono)
            {
                PlatformName = "Windows";
            }
            else
            {
                PlatformName = "Mac";
            }
            string EMCCPath;
            bool   ok = ConfigCache.GetString("HTML5SDKPaths", PlatformName, out EMCCPath);

            if (ok && System.IO.Directory.Exists(EMCCPath))
            {
                return(EMCCPath);
            }

            // try to find SDK Location from env.
            if (Environment.GetEnvironmentVariable("EMSCRIPTEN") != null &&
                System.IO.Directory.Exists(Environment.GetEnvironmentVariable("EMSCRIPTEN"))
                )
            {
                return(Environment.GetEnvironmentVariable("EMSCRIPTEN"));
            }

            return("");
        }
Exemplo n.º 4
0
        public override bool WriteProjectFile(List <UnrealTargetPlatform> InPlatforms, List <UnrealTargetConfiguration> InConfigurations)
        {
            bool bSuccess = false;

            string ProjectPath             = ProjectFilePath;
            string ProjectExtension        = Path.GetExtension(ProjectFilePath);
            string ProjectPlatformName     = BuildHostPlatform.Current.Platform.ToString();
            string ProjectRelativeFilePath = this.RelativeProjectFilePath;

            // Get the output directory
            string EngineRootDirectory = Path.GetFullPath(ProjectFileGenerator.EngineRelativePath);

            //
            // Build the working directory of the Game executable.
            //

            string GameWorkingDirectory = "";

            if (UnrealBuildTool.HasUProjectFile())
            {
                GameWorkingDirectory = Path.Combine(Path.GetDirectoryName(UnrealBuildTool.GetUProjectFile()), "Binaries", ProjectPlatformName);
            }
            //
            // Build the working directory of the UE4Editor executable.
            //
            string UE4EditorWorkingDirectory = Path.Combine(EngineRootDirectory, "Binaries", ProjectPlatformName);

            //
            // Create the folder where the project files goes if it does not exist
            //
            String FilePath = Path.GetDirectoryName(ProjectFilePath);

            if ((FilePath.Length > 0) && !Directory.Exists(FilePath))
            {
                Directory.CreateDirectory(FilePath);
            }

            string GameProjectFile = UnrealBuildTool.GetUProjectFile();

            //
            // Write all targets which will be separate projects.
            //
            foreach (ProjectTarget target in ProjectTargets)
            {
                string[] tmp = target.ToString().Split('.');
                string   ProjectTargetFileName = Path.GetDirectoryName(ProjectFilePath) + "/" + tmp [0] + ProjectExtension;
                String   ProjectName           = tmp [0];
                var      ProjectTargetType     = target.TargetRules.Type;

                //
                // Create the CodeLites root element.
                //
                XElement   CodeLiteProject = new XElement("CodeLite_Project");
                XAttribute CodeLiteProjectAttributeName = new XAttribute("Name", ProjectName);
                CodeLiteProject.Add(CodeLiteProjectAttributeName);

                //
                // Select only files we want to add.
                // TODO Maybe skipping those files directly in the following foreach loop is faster?
                //
                List <SourceFile> FilterSourceFile = SourceFiles.FindAll(s => (
                                                                             Path.GetExtension(s.FilePath).Equals(".h") ||
                                                                             Path.GetExtension(s.FilePath).Equals(".cpp") ||
                                                                             Path.GetExtension(s.FilePath).Equals(".cs") ||
                                                                             Path.GetExtension(s.FilePath).Equals(".uproject") ||
                                                                             Path.GetExtension(s.FilePath).Equals(".ini") ||
                                                                             Path.GetExtension(s.FilePath).Equals(".usf")
                                                                             ));

                //
                // Find/Create the correct virtual folder and place the file into it.
                //
                foreach (var CurrentFile in FilterSourceFile)
                {
                    //
                    // Try to get the correct relative folder representation for the project.
                    //
                    String CurrentFilePath = "";
                    // TODO It seems that the full pathname doesn't work for some files like .ini, .usf
                    if ((ProjectTargetType == TargetRules.TargetType.Client) ||
                        (ProjectTargetType == TargetRules.TargetType.Editor) ||
                        (ProjectTargetType == TargetRules.TargetType.Server))
                    {
                        if (ProjectName.Contains("UE4"))
                        {
                            int Idx = Path.GetFullPath(ProjectFileGenerator.EngineRelativePath).Length;
                            CurrentFilePath = Path.GetDirectoryName(Path.GetFullPath(CurrentFile.FilePath)).Substring(Idx);
                        }
                        else
                        {
                            int    IdxProjectName = ProjectName.IndexOf("Editor");
                            string ProjectNameRaw = ProjectName;
                            if (IdxProjectName > 0)
                            {
                                ProjectNameRaw = ProjectName.Substring(0, IdxProjectName);
                            }
                            int Idx = Path.GetDirectoryName(Path.GetFullPath(CurrentFile.FilePath)).IndexOf(ProjectNameRaw) + ProjectNameRaw.Length;
                            CurrentFilePath = Path.GetDirectoryName(Path.GetFullPath(CurrentFile.FilePath)).Substring(Idx);
                        }
                    }
                    else if (ProjectTargetType == TargetRules.TargetType.Program)
                    {
                        //
                        // We do not need all the editors subfolders to show the content. Find the correct programs subfolder.
                        //
                        int Idx = Path.GetDirectoryName(Path.GetFullPath(CurrentFile.FilePath)).IndexOf(ProjectName) + ProjectName.Length;
                        CurrentFilePath = Path.GetFullPath(Path.GetDirectoryName(CurrentFile.FilePath)).Substring(Idx);
                    }
                    else if (ProjectTargetType == TargetRules.TargetType.Game)
                    {
//						int lengthOfProjectRootPath = Path.GetFullPath(ProjectFileGenerator.MasterProjectRelativePath).Length;
//						CurrentFilePath = Path.GetDirectoryName(Path.GetFullPath(CurrentFile.FilePath)).Substring(lengthOfProjectRootPath);
                        //	int lengthOfProjectRootPath = EngineRootDirectory.Length;
                        int Idx = Path.GetDirectoryName(Path.GetFullPath(CurrentFile.FilePath)).IndexOf(ProjectName) + ProjectName.Length;
                        CurrentFilePath = Path.GetDirectoryName(Path.GetFullPath(CurrentFile.FilePath)).Substring(Idx);
                    }

                    string [] SplitFolders = CurrentFilePath.Split('/');
                    //
                    // Set the CodeLite root folder again.
                    //
                    XElement root = CodeLiteProject;

                    //
                    // Iterate through all XElement virtual folders until we find the right place to put the file.
                    // TODO this looks more like a hack to me.
                    //
                    foreach (var FolderName in SplitFolders)
                    {
                        if (FolderName.Equals(""))
                        {
                            continue;
                        }

                        //
                        // Let's look if there is a virtual folder withint the current XElement.
                        //
                        IEnumerable <XElement> tests = root.Elements("VirtualDirectory");
                        if (IsEmpty(tests))
                        {
                            //
                            // No, then we have to create.
                            //
                            XElement   vf  = new XElement("VirtualDirectory");
                            XAttribute vfn = new XAttribute("Name", FolderName);
                            vf.Add(vfn);
                            root.Add(vf);
                            root = vf;
                        }
                        else
                        {
                            //
                            // Yes, then let's find the correct sub XElement.
                            //
                            bool notfound = true;

                            //
                            // We have some virtual directories let's find the correct one.
                            //
                            foreach (var element in tests)
                            {
                                //
                                // Look the the following folder
                                XAttribute attribute = element.Attribute("Name");
                                if (attribute.Value == FolderName)
                                {
                                    // Ok, we found the folder as subfolder, let's use it.
                                    root     = element;
                                    notfound = false;
                                    break;
                                }
                            }
                            //
                            // If we are here we didn't find any XElement with that subfolder, then we have to create.
                            //
                            if (notfound)
                            {
                                XElement   vf  = new XElement("VirtualDirectory");
                                XAttribute vfn = new XAttribute("Name", FolderName);
                                vf.Add(vfn);
                                root.Add(vf);
                                root = vf;
                            }
                        }
                    }

                    //
                    // If we are at this point we found the correct XElement folder
                    //
                    XElement   file          = new XElement("File");
                    XAttribute fileAttribute = new XAttribute("Name", Path.GetFullPath(CurrentFile.FilePath));
                    file.Add(fileAttribute);
                    root.Add(file);
                }

                XElement CodeLiteSettings = new XElement("Settings");
                CodeLiteProject.Add(CodeLiteSettings);

                XElement CodeLiteGlobalSettings = new XElement("GlobalSettings");
                CodeLiteSettings.Add(CodeLiteSettings);


                foreach (var CurConf in InConfigurations)
                {
                    XElement   CodeLiteConfiguration     = new XElement("Configuration");
                    XAttribute CodeLiteConfigurationName = new XAttribute("Name", CurConf.ToString());
                    CodeLiteConfiguration.Add(CodeLiteConfigurationName);

                    //
                    // Create Configuration General part.
                    //
                    XElement CodeLiteConfigurationGeneral = new XElement("General");

                    //
                    // Create the executable filename.
                    //
                    string ExecutableToRun       = "";
                    string PlatformConfiguration = "-" + ProjectPlatformName + "-" + CurConf.ToString();
                    switch (BuildHostPlatform.Current.Platform)
                    {
                    case UnrealTargetPlatform.Linux:
                    {
                        ExecutableToRun = "./" + ProjectName;
                        if ((ProjectTargetType == TargetRules.TargetType.Game) || (ProjectTargetType == TargetRules.TargetType.Program))
                        {
                            if (CurConf != UnrealTargetConfiguration.Development)
                            {
                                ExecutableToRun += PlatformConfiguration;
                            }
                        }
                        else if (ProjectTargetType == TargetRules.TargetType.Editor)
                        {
                            ExecutableToRun = "./UE4Editor";
                        }
                    }
                    break;

                    case UnrealTargetPlatform.Mac:
                    {
                        ExecutableToRun = "./" + ProjectName;
                        if ((ProjectTargetType == TargetRules.TargetType.Game) || (ProjectTargetType == TargetRules.TargetType.Program))
                        {
                            if (CurConf != UnrealTargetConfiguration.Development)
                            {
                                ExecutableToRun += PlatformConfiguration;
                            }
                            ExecutableToRun += ".app/Contents/MacOS/" + ProjectName;
                            if (CurConf != UnrealTargetConfiguration.Development)
                            {
                                ExecutableToRun += PlatformConfiguration;
                            }
                        }
                        else if (ProjectTargetType == TargetRules.TargetType.Editor)
                        {
                            ExecutableToRun = "./UE4Editor";
                            if (CurConf != UnrealTargetConfiguration.Development)
                            {
                                ExecutableToRun += PlatformConfiguration;
                            }
                            ExecutableToRun += ".app/Contents/MacOS/UE4Editor";
                            if (CurConf != UnrealTargetConfiguration.Development)
                            {
                                ExecutableToRun += PlatformConfiguration;
                            }
                        }
                    }
                    break;

                    case UnrealTargetPlatform.Win64:
                    case UnrealTargetPlatform.Win32:
                    {
                        ExecutableToRun = ProjectName;
                        if ((ProjectTargetType == TargetRules.TargetType.Game) || (ProjectTargetType == TargetRules.TargetType.Program))
                        {
                            if (CurConf != UnrealTargetConfiguration.Development)
                            {
                                ExecutableToRun += PlatformConfiguration;
                            }
                        }
                        else if (ProjectTargetType == TargetRules.TargetType.Editor)
                        {
                            ExecutableToRun = "UE4Editor";
                        }

                        ExecutableToRun += ".exe";
                    }
                    break;

                    default:
                        throw new BuildException("Unsupported platform.");
                    }


                    // Is this project a Game type?
                    XAttribute GeneralExecutableToRun = new XAttribute("Command", ExecutableToRun);
                    if (ProjectTargetType == TargetRules.TargetType.Game)
                    {
                        if (CurConf.ToString().Contains("Debug"))
                        {
                            string     commandArguments = " -debug";
                            XAttribute GeneralExecutableToRunArguments = new XAttribute("CommandArguments", commandArguments);
                            CodeLiteConfigurationGeneral.Add(GeneralExecutableToRunArguments);
                        }
                        if (ProjectName.Equals("UE4Game"))
                        {
                            XAttribute GeneralExecutableWorkingDirectory = new XAttribute("WorkingDirectory", UE4EditorWorkingDirectory);
                            CodeLiteConfigurationGeneral.Add(GeneralExecutableWorkingDirectory);
                        }
                        else
                        {
                            XAttribute GeneralExecutableWorkingDirectory = new XAttribute("WorkingDirectory", GameWorkingDirectory);
                            CodeLiteConfigurationGeneral.Add(GeneralExecutableWorkingDirectory);
                        }
                    }
                    else if (ProjectTargetType == TargetRules.TargetType.Editor)
                    {
                        if (ProjectName != "UE4Editor")
                        {
                            string     commandArguments = "\"" + GameProjectFile + "\"" + " -game";
                            XAttribute CommandArguments = new XAttribute("CommandArguments", commandArguments);
                            CodeLiteConfigurationGeneral.Add(CommandArguments);
                        }
                        XAttribute WorkingDirectory = new XAttribute("WorkingDirectory", UE4EditorWorkingDirectory);
                        CodeLiteConfigurationGeneral.Add(WorkingDirectory);
                    }
                    else if (ProjectTargetType == TargetRules.TargetType.Program)
                    {
                        XAttribute WorkingDirectory = new XAttribute("WorkingDirectory", UE4EditorWorkingDirectory);
                        CodeLiteConfigurationGeneral.Add(WorkingDirectory);
                    }
                    else if (ProjectTargetType == TargetRules.TargetType.Client)
                    {
                        XAttribute WorkingDirectory = new XAttribute("WorkingDirectory", UE4EditorWorkingDirectory);
                        CodeLiteConfigurationGeneral.Add(WorkingDirectory);
                    }
                    else if (ProjectTargetType == TargetRules.TargetType.Server)
                    {
                        XAttribute WorkingDirectory = new XAttribute("WorkingDirectory", UE4EditorWorkingDirectory);
                        CodeLiteConfigurationGeneral.Add(WorkingDirectory);
                    }
                    CodeLiteConfigurationGeneral.Add(GeneralExecutableToRun);

                    CodeLiteConfiguration.Add(CodeLiteConfigurationGeneral);

                    //
                    // End of Create Configuration General part.
                    //

                    //
                    // Create Configuration Custom Build part.
                    //
                    XElement CodeLiteConfigurationCustomBuild = new XElement("CustomBuild");
                    CodeLiteConfiguration.Add(CodeLiteConfigurationGeneral);
                    XAttribute CodeLiteConfigurationCustomBuildEnabled = new XAttribute("Enabled", "yes");
                    CodeLiteConfigurationCustomBuild.Add(CodeLiteConfigurationCustomBuildEnabled);

                    //
                    // Add the working directory for the custom build commands.
                    //
                    XElement CustomBuildWorkingDirectory  = new XElement("WorkingDirectory");
                    XText    CustuomBuildWorkingDirectory = new XText(Path.GetDirectoryName(UnrealBuildTool.GetUBTPath()));
                    CustomBuildWorkingDirectory.Add(CustuomBuildWorkingDirectory);
                    CodeLiteConfigurationCustomBuild.Add(CustomBuildWorkingDirectory);

                    //
                    // End of Add the working directory for the custom build commands.
                    //



                    //
                    // Make Build Target.
                    //
                    XElement CustomBuildCommand = new XElement("BuildCommand");
                    CodeLiteConfigurationCustomBuild.Add(CustomBuildCommand);

                    string BuildTarget = Path.GetFileName(UnrealBuildTool.GetUBTPath()) + " " + ProjectName + " " + ProjectPlatformName + " " + CurConf.ToString();
                    if ((BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Win64) &&
                        (BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Win32))
                    {
                        BuildTarget = "mono " + BuildTarget;
                    }

                    if (GameProjectFile.Length > 0)
                    {
                        BuildTarget += " -project=" + "\"" + GameProjectFile + "\"";
                    }

                    XText commandLine = new XText(BuildTarget);
                    CustomBuildCommand.Add(commandLine);

                    //
                    // End of Make Build Target
                    //

                    //
                    // Clean Build Target.
                    //
                    XElement CustomCleanCommand = new XElement("CleanCommand");
                    CodeLiteConfigurationCustomBuild.Add(CustomCleanCommand);

                    string CleanTarget      = BuildTarget + " -clean";
                    XText  CleanCommandLine = new XText(CleanTarget);

                    CustomCleanCommand.Add(CleanCommandLine);


                    //
                    // End of Clean Build Target.
                    //

                    //
                    // Rebuild Build Target.
                    //
                    XElement CustomRebuildCommand = new XElement("RebuildCommand");
                    CodeLiteConfigurationCustomBuild.Add(CustomRebuildCommand);

                    string RebuildTarget      = CleanTarget + "\n" + BuildTarget;
                    XText  RebuildCommandLine = new XText(RebuildTarget);

                    CustomRebuildCommand.Add(RebuildCommandLine);

                    //
                    // End of Clean Build Target.
                    //


                    //
                    // Some other fun Custom Targets.
                    //
                    if (ProjectTargetType == TargetRules.TargetType.Game)
                    {
                        string CookGameCommandLine = "mono AutomationTool.exe BuildCookRun ";

                        // Projects filename
                        CookGameCommandLine += "-project=\"" + UnrealBuildTool.GetUProjectFile() + "\" ";

                        // Disables Perforce functionality
                        CookGameCommandLine += "-noP4 ";

                        // Do not kill any spawned processes on exit
                        CookGameCommandLine += "-nokill ";
                        CookGameCommandLine += "-clientconfig=" + CurConf.ToString() + " ";
                        CookGameCommandLine += "-serverconfig=" + CurConf.ToString() + " ";
                        CookGameCommandLine += "-platform=" + ProjectPlatformName + " ";
                        CookGameCommandLine += "-targetplatform=" + ProjectPlatformName + " ";                                 // TODO Maybe I can add all the supported one.
                        CookGameCommandLine += "-nocompile ";
                        CookGameCommandLine += "-compressed -stage -deploy";

                        //
                        // Cook Game.
                        //
                        XElement   CookGame        = new XElement("Target");
                        XAttribute CookGameName    = new XAttribute("Name", "Cook Game");
                        XText      CookGameCommand = new XText(CookGameCommandLine + " -cook");
                        CookGame.Add(CookGameName);
                        CookGame.Add(CookGameCommand);
                        CodeLiteConfigurationCustomBuild.Add(CookGame);

                        XElement   CookGameOnTheFly         = new XElement("Target");
                        XAttribute CookGameNameOnTheFlyName = new XAttribute("Name", "Cook Game on the fly");
                        XText      CookGameOnTheFlyCommand  = new XText(CookGameCommandLine + " -cookonthefly");
                        CookGameOnTheFly.Add(CookGameNameOnTheFlyName);
                        CookGameOnTheFly.Add(CookGameOnTheFlyCommand);
                        CodeLiteConfigurationCustomBuild.Add(CookGameOnTheFly);

                        XElement   SkipCook        = new XElement("Target");
                        XAttribute SkipCookName    = new XAttribute("Name", "Skip Cook Game");
                        XText      SkipCookCommand = new XText(CookGameCommandLine + " -skipcook");
                        SkipCook.Add(SkipCookName);
                        SkipCook.Add(SkipCookCommand);
                        CodeLiteConfigurationCustomBuild.Add(SkipCook);
                    }
                    //
                    // End of Some other fun Custom Targets.
                    //
                    CodeLiteConfiguration.Add(CodeLiteConfigurationCustomBuild);

                    //
                    // End of Create Configuration Custom Build part.
                    //

                    CodeLiteSettings.Add(CodeLiteConfiguration);
                }

                CodeLiteSettings.Add(CodeLiteGlobalSettings);

                //
                // Save the XML file.
                //
                CodeLiteProject.Save(ProjectTargetFileName);

                bSuccess = true;
            }
            return(bSuccess);
        }
Exemplo n.º 5
0
        /// <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);
        }
Exemplo n.º 6
0
        /// <summary>
        /// Checks to see if the assembly needs compilation
        /// </summary>
        /// <param name="SourceFiles">Set of source files</param>
        /// <param name="AssemblyManifestFilePath">File containing information about this assembly, like which source files it was built with and engine version</param>
        /// <param name="OutputAssemblyPath">Output path for the assembly</param>
        /// <returns>True if the assembly needs to be built</returns>
        private static bool RequiresCompilation(HashSet <FileReference> SourceFiles, FileReference AssemblyManifestFilePath, FileReference OutputAssemblyPath)
        {
            // Check to see if we already have a compiled assembly file on disk
            FileItem OutputAssemblyInfo = FileItem.GetItemByFileReference(OutputAssemblyPath);

            if (!OutputAssemblyInfo.Exists)
            {
                Log.TraceLog("Compiling {0}: Assembly does not exist", OutputAssemblyPath);
                return(true);
            }

            // Check the time stamp of the UnrealBuildTool.exe file.  If Unreal Build Tool was compiled more
            // recently than the dynamically-compiled assembly, then we'll always recompile it.  This is
            // because Unreal Build Tool's code may have changed in such a way that invalidate these
            // previously-compiled assembly files.
            FileItem ExecutableItem = FileItem.GetItemByFileReference(UnrealBuildTool.GetUBTPath());

            if (ExecutableItem.LastWriteTimeUtc > OutputAssemblyInfo.LastWriteTimeUtc)
            {
                Log.TraceLog("Compiling {0}: {1} is newer", OutputAssemblyPath, ExecutableItem.Name);
                return(true);
            }


            // Make sure we have a manifest of source files used to compile the output assembly.  If it doesn't exist
            // for some reason (not an expected case) then we'll need to recompile.
            FileItem AssemblySourceListFile = FileItem.GetItemByFileReference(AssemblyManifestFilePath);

            if (!AssemblySourceListFile.Exists)
            {
                Log.TraceLog("Compiling {0}: Missing source file list ({1})", OutputAssemblyPath, AssemblyManifestFilePath);
                return(true);
            }

            JsonObject Manifest = JsonObject.Read(AssemblyManifestFilePath);

            // check if the engine version is different
            string EngineVersionManifest = Manifest.GetStringField("EngineVersion");
            string EngineVersionCurrent  = FormatVersionNumber(ReadOnlyBuildVersion.Current);

            if (EngineVersionManifest != EngineVersionCurrent)
            {
                Log.TraceLog("Compiling {0}: Engine Version changed from {1} to {2}", OutputAssemblyPath, EngineVersionManifest, EngineVersionCurrent);
                return(true);
            }


            // Make sure the source files we're compiling are the same as the source files that were compiled
            // for the assembly that we want to load
            HashSet <FileItem> CurrentSourceFileItems = new HashSet <FileItem>();

            foreach (string Line in Manifest.GetStringArrayField("SourceFiles"))
            {
                CurrentSourceFileItems.Add(FileItem.GetItemByPath(Line));
            }

            // Get the new source files
            HashSet <FileItem> SourceFileItems = new HashSet <FileItem>();

            foreach (FileReference SourceFile in SourceFiles)
            {
                SourceFileItems.Add(FileItem.GetItemByFileReference(SourceFile));
            }

            // Check if there are any differences between the sets
            foreach (FileItem CurrentSourceFileItem in CurrentSourceFileItems)
            {
                if (!SourceFileItems.Contains(CurrentSourceFileItem))
                {
                    Log.TraceLog("Compiling {0}: Removed source file ({1})", OutputAssemblyPath, CurrentSourceFileItem);
                    return(true);
                }
            }
            foreach (FileItem SourceFileItem in SourceFileItems)
            {
                if (!CurrentSourceFileItems.Contains(SourceFileItem))
                {
                    Log.TraceLog("Compiling {0}: Added source file ({1})", OutputAssemblyPath, SourceFileItem);
                    return(true);
                }
            }

            // Check if any of the timestamps are newer
            foreach (FileItem SourceFileItem in SourceFileItems)
            {
                if (SourceFileItem.LastWriteTimeUtc > OutputAssemblyInfo.LastWriteTimeUtc)
                {
                    Log.TraceLog("Compiling {0}: {1} is newer", OutputAssemblyPath, SourceFileItem);
                    return(true);
                }
            }

            return(false);
        }