Example #1
0
	/// <summary>
	/// Builds UnrealHeaderTool for the specified platform.
	/// </summary>
	/// <param name="Command"></param>
	/// <param name="InPlatform"></param>
	public static void BuildUnrealHeaderTool(BuildCommand Command, UnrealBuildTool.UnrealTargetPlatform InPlatform)
	{
		BuildProduct(Command, new UE4Build.BuildTarget()
		{
			ProjectName = "",
			TargetName = "UnrealHeaderTool",
			Platform = InPlatform,
			Config = UnrealBuildTool.UnrealTargetConfiguration.Development,
		});
	}
	/// <summary>
	/// Builds BuildPatchTool for the specified platform.
	/// </summary>
	/// <param name="Command"></param>
	/// <param name="InPlatform"></param>
	public static void BuildBuildPatchTool(BuildCommand Command, UnrealBuildTool.UnrealTargetPlatform InPlatform)
	{
		BuildProduct(Command, new UE4Build.BuildTarget()
			{
				UprojectPath = null,
				TargetName = "BuildPatchTool",
				Platform = InPlatform,
				Config = UnrealBuildTool.UnrealTargetConfiguration.Shipping,
			});
	}
    /// <summary>
    /// Builds BuildPatchTool for the specified platform.
    /// </summary>
    /// <param name="Command"></param>
    /// <param name="InPlatform"></param>
    public static void BuildBuildPatchTool(BuildCommand Command, UnrealBuildTool.UnrealTargetPlatform InPlatform)
    {
        Log("Building BuildPatchTool");

        var UE4Build = new UE4Build(Command);

        var Agenda = new UE4Build.BuildAgenda();
        Agenda.Targets.Add(new UE4Build.BuildTarget()
        {
            ProjectName = "",
            TargetName = "BuildPatchTool",
            Platform = InPlatform,
            Config = UnrealBuildTool.UnrealTargetConfiguration.Development,
        });

        UE4Build.Build(Agenda, InDeleteBuildProducts: true, InUpdateVersionFiles: true);
        UE4Build.CheckBuildProducts(UE4Build.BuildProductFiles);
    }
Example #4
0
        /**
         * Builds and runs the header tool and touches the header directories.
         * Performs any early outs if headers need no changes, given the UObject modules, tool path, game name, and configuration
         */
        public static bool ExecuteHeaderToolIfNecessary(UEBuildTarget Target, CPPEnvironment GlobalCompileEnvironment, List <UHTModuleInfo> UObjectModules, string ModuleInfoFileName, ref ECompilationResult UHTResult)
        {
            using (ProgressWriter Progress = new ProgressWriter("Generating code...", false))
            {
                // We never want to try to execute the header tool when we're already trying to build it!
                var bIsBuildingUHT = Target.GetTargetName().Equals("UnrealHeaderTool", StringComparison.InvariantCultureIgnoreCase);

                var BuildPlatform = UEBuildPlatform.GetBuildPlatform(Target.Platform);
                var CppPlatform   = BuildPlatform.GetCPPTargetPlatform(Target.Platform);
                var ToolChain     = UEToolChain.GetPlatformToolChain(CppPlatform);
                var RootLocalPath = Path.GetFullPath(ProjectFileGenerator.RootRelativePath);


                // ensure the headers are up to date
                bool bUHTNeedsToRun = (UEBuildConfiguration.bForceHeaderGeneration == true || AreGeneratedCodeFilesOutOfDate(UObjectModules));
                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 &&
                        !(!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");
                        }

                        if (RunExternalExecutable(UnrealBuildTool.GetUBTPath(), UBTArguments.ToString()) != 0)
                        {
                            return(false);
                        }
                    }

                    Progress.Write(1, 3);

                    var ActualTargetName = String.IsNullOrEmpty(Target.GetTargetName()) ? "UE4" : Target.GetTargetName();
                    Log.TraceInformation("Parsing headers for {0}", ActualTargetName);

                    string HeaderToolPath = GetHeaderToolPath();
                    if (!File.Exists(HeaderToolPath))
                    {
                        throw new BuildException("Unable to generate headers because UnrealHeaderTool binary was not found ({0}).", Path.GetFullPath(HeaderToolPath));
                    }

                    // Disable extensions when serializing to remove the $type fields
                    Directory.CreateDirectory(Path.GetDirectoryName(ModuleInfoFileName));
                    System.IO.File.WriteAllText(ModuleInfoFileName, fastJSON.JSON.Instance.ToJSON(Manifest, new fastJSON.JSONParameters {
                        UseExtensions = false
                    }));

                    string CmdLine = (UnrealBuildTool.HasUProjectFile()) ? "\"" + UnrealBuildTool.GetUProjectFile() + "\"" : Target.GetTargetName();
                    CmdLine += " \"" + ModuleInfoFileName + "\" -LogCmds=\"loginit warning, logexit warning, logdatabase error\"";
                    if (UnrealBuildTool.RunningRocket())
                    {
                        CmdLine += " -rocket -installed";
                    }

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

                    Stopwatch s = new Stopwatch();
                    s.Start();
                    UHTResult = (ECompilationResult)RunExternalExecutable(ExternalExecution.GetHeaderToolPath(), CmdLine);
                    s.Stop();

                    if (UHTResult != ECompilationResult.Succeeded)
                    {
                        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}", ActualTargetName);
                    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);
            }
            return(true);
        }
        /// <summary>
        /// Determines whether the given module name is a game module (as opposed to an engine module)
        /// </summary>
        public bool IsGameModule(string InModuleName)
        {
            FileReference ModuleFileName = GetModuleFileName(InModuleName);

            return(ModuleFileName != null && !UnrealBuildTool.IsUnderAnEngineDirectory(ModuleFileName.Directory));
        }
        /// <summary>
        /// Return all data driven infos found
        /// </summary>
        /// <returns></returns>
        public static Dictionary <string, ConfigDataDrivenPlatformInfo> GetAllPlatformInfos()
        {
            // need to init?
            if (PlatformInfos == null)
            {
                PlatformInfos = new Dictionary <string, ConfigDataDrivenPlatformInfo>();
                Dictionary <string, string> IniParents = new Dictionary <string, string>();

                // find all platform directories (skipping NFL/NoRedist)
                foreach (DirectoryReference EngineConfigDir in UnrealBuildTool.GetExtensionDirs(UnrealBuildTool.EngineDirectory, "Config", bIncludeRestrictedDirectories:false))
                {
                    // look through all config dirs looking for the data driven ini file
                    foreach (string FilePath in Directory.EnumerateFiles(EngineConfigDir.FullName, "DataDrivenPlatformInfo.ini", SearchOption.AllDirectories))
                    {
                        FileReference FileRef = new FileReference(FilePath);

                        // get the platform name from the path
                        string IniPlatformName;
                        if (FileRef.IsUnderDirectory(DirectoryReference.Combine(UnrealBuildTool.EngineDirectory, "Config")))
                        {
                            // Foo/Engine/Config/<Platform>/DataDrivenPlatformInfo.ini
                            IniPlatformName = Path.GetFileName(Path.GetDirectoryName(FilePath));
                        }
                        else
                        {
                            // Foo/Engine/Platforms/<Platform>/Config/DataDrivenPlatformInfo.ini
                            IniPlatformName = Path.GetFileName(Path.GetDirectoryName(Path.GetDirectoryName(FilePath)));
                        }

                        // load the DataDrivenPlatformInfo from the path (with Add support in a file that doesn't use +'s in the arrays for C++ usage)
                        ConfigFile Config = new ConfigFile(FileRef, ConfigLineAction.Add);
                        ConfigDataDrivenPlatformInfo NewInfo = new ConfigDataDrivenPlatformInfo();


                        // we must have the key section
                        ConfigFileSection Section = null;
                        if (Config.TryGetSection("DataDrivenPlatformInfo", out Section))
                        {
                            ConfigHierarchySection ParsedSection = new ConfigHierarchySection(new List <ConfigFileSection>()
                            {
                                Section
                            });

                            // get string values
                            string IniParent;
                            if (ParsedSection.TryGetValue("IniParent", out IniParent))
                            {
                                IniParents[IniPlatformName] = IniParent;
                            }

                            // slightly nasty bool parsing for bool values
                            string Temp;
                            if (ParsedSection.TryGetValue("bIsConfidential", out Temp) == false || ConfigHierarchy.TryParse(Temp, out NewInfo.bIsConfidential) == false)
                            {
                                NewInfo.bIsConfidential = false;
                            }

                            // get a list of additional restricted folders
                            IReadOnlyList <string> AdditionalRestrictedFolders;
                            if (ParsedSection.TryGetValues("AdditionalRestrictedFolders", out AdditionalRestrictedFolders) && AdditionalRestrictedFolders.Count > 0)
                            {
                                NewInfo.AdditionalRestrictedFolders = AdditionalRestrictedFolders.Select(x => x.Trim()).Where(x => x.Length > 0).ToArray();
                            }

                            // create cache it
                            PlatformInfos[IniPlatformName] = NewInfo;
                        }
                    }
                }

                // now that all are read in, calculate the ini parent chain, starting with parent-most
                foreach (KeyValuePair <string, ConfigDataDrivenPlatformInfo> Pair in PlatformInfos)
                {
                    string CurrentPlatform;

                    // walk up the chain and build up the ini chain
                    List <string> Chain = new List <string>();
                    if (IniParents.TryGetValue(Pair.Key, out CurrentPlatform))
                    {
                        while (!string.IsNullOrEmpty(CurrentPlatform))
                        {
                            // insert at 0 to reverse the order
                            Chain.Insert(0, CurrentPlatform);
                            if (IniParents.TryGetValue(CurrentPlatform, out CurrentPlatform) == false)
                            {
                                break;
                            }
                        }
                    }

                    // bake it into the info
                    if (Chain.Count > 0)
                    {
                        Pair.Value.IniParentChain = Chain.ToArray();
                    }
                }
            }

            return(PlatformInfos);
        }
        /** 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)
                    {
                        if (UnrealBuildTool.RunningRocket())
                        {
                            // If it is an Engine folder and we are building a rocket project do NOT update the timestamp!
                            // @todo Rocket: This contains check is hacky/fragile
                            string FullGeneratedCodeDirectory = GeneratedCodeDirectoryInfo.FullName;
                            FullGeneratedCodeDirectory = FullGeneratedCodeDirectory.Replace("\\", "/");
                            if (FullGeneratedCodeDirectory.Contains("Engine/Intermediate/Build"))
                            {
                                continue;
                            }

                            // Skip checking timestamps for engine plugin intermediate headers in Rocket
                            PluginInfo Info = Plugins.GetPluginInfoForModule(Module.ModuleName);
                            if (Info != null)
                            {
                                if (Info.LoadedFrom == PluginInfo.LoadedFromType.Engine)
                                {
                                    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();
                        }

                        // 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);
                }
            }
        }
Example #8
0
        /// <summary>
        /// Determine if the given platform is available
        /// </summary>
        /// <param name="Platform">Platform to check</param>
        /// <param name="ProjectType">The type of project</param>
        /// <returns>True if supported</returns>
        public static bool IsValidPlatform(UnrealTargetPlatform Platform, EProjectType ProjectType = EProjectType.Any)
        {
            // HACK: For installed builds, we always need to treat Mac as a valid platform for generating project files. When remote building from PC, we won't have all the libraries to do this, so we need to fake it.
            if (Platform == UnrealTargetPlatform.Mac && ProjectType == EProjectType.Any && BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac && UnrealBuildTool.IsEngineInstalled())
            {
                return(true);
            }

            return(ContainsValidConfiguration(
                       (InstalledPlatformConfiguration CurConfig) =>
            {
                return CurConfig.Platform == Platform &&
                (ProjectType == EProjectType.Any || CurConfig.ProjectType == EProjectType.Any ||
                 CurConfig.ProjectType == ProjectType);
            }
                       ));
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="RulesFileType"></param>
        /// <param name="GameFolders"></param>
        /// <param name="ForeignPlugins"></param>
        /// <param name="AdditionalSearchPaths"></param>
        /// <param name="bIncludeEngine"></param>
        /// <param name="bIncludeEnterprise"></param>
        /// <param name="bIncludeTempTargets">Whether to include targets generated by UAT to accomodate content-only projects that need to be compiled to include plugins</param>
        /// <param name="bIncludePlatformExtensions"></param>
        /// <returns></returns>
        public static List <FileReference> FindAllRulesSourceFiles(RulesFileType RulesFileType, List <DirectoryReference> GameFolders, List <FileReference> ForeignPlugins, List <DirectoryReference> AdditionalSearchPaths, bool bIncludeEngine = true, bool bIncludeEnterprise = true, bool bIncludeTempTargets = true, bool bIncludePlatformExtensions = true)
        {
            List <DirectoryReference> Folders = new List <DirectoryReference>();

            // Add all engine source (including third party source)
            if (bIncludeEngine)
            {
                Folders.Add(UnrealBuildTool.EngineSourceDirectory);
            }
            if (bIncludeEnterprise)
            {
                Folders.Add(UnrealBuildTool.EnterpriseSourceDirectory);
            }
            if (bIncludePlatformExtensions)
            {
                Folders.Add(UnrealBuildTool.EnginePlatformExtensionsDirectory);
            }

            // @todo plugin: Disallow modules from including plugin modules as dependency modules? (except when the module is part of that plugin)

            // Get all the root folders for plugins
            List <DirectoryReference> RootFolders = new List <DirectoryReference>();

            if (bIncludeEngine)
            {
                RootFolders.AddRange(UnrealBuildTool.GetAllEngineDirectories());
            }
            if (bIncludeEnterprise)
            {
                RootFolders.Add(UnrealBuildTool.EnterpriseDirectory);
            }
            if (GameFolders != null)
            {
                if (bIncludePlatformExtensions)
                {
                    foreach (DirectoryReference GameFolder in GameFolders)
                    {
                        RootFolders.AddRange(UnrealBuildTool.GetAllProjectDirectories(GameFolder));
                    }
                }
                else
                {
                    RootFolders.AddRange(GameFolders);
                }
            }

            // Find all the plugin source directories
            foreach (DirectoryReference RootFolder in RootFolders)
            {
                DirectoryReference PluginsFolder = DirectoryReference.Combine(RootFolder, "Plugins");
                foreach (FileReference PluginFile in Plugins.EnumeratePlugins(PluginsFolder))
                {
                    Folders.Add(DirectoryReference.Combine(PluginFile.Directory, "Source"));
                }
            }

            // Add all the extra plugin folders
            if (ForeignPlugins != null)
            {
                foreach (FileReference ForeignPlugin in ForeignPlugins)
                {
                    Folders.Add(DirectoryReference.Combine(ForeignPlugin.Directory, "Source"));
                }
            }

            // Add in the game folders to search
            if (GameFolders != null)
            {
                foreach (DirectoryReference GameFolder in GameFolders)
                {
                    if (bIncludePlatformExtensions)
                    {
                        Folders.AddRange(UnrealBuildTool.GetAllProjectDirectories(GameFolder, "Source"));
                    }
                    else
                    {
                        Folders.Add(DirectoryReference.Combine(GameFolder, "Source"));
                    }

                    if (bIncludeTempTargets)
                    {
                        DirectoryReference GameIntermediateSourceFolder = DirectoryReference.Combine(GameFolder, "Intermediate", "Source");
                        Folders.Add(GameIntermediateSourceFolder);
                    }
                }
            }

            // Process the additional search path, if sent in
            if (AdditionalSearchPaths != null)
            {
                foreach (DirectoryReference AdditionalSearchPath in AdditionalSearchPaths)
                {
                    if (AdditionalSearchPath != null)
                    {
                        if (DirectoryReference.Exists(AdditionalSearchPath))
                        {
                            Folders.Add(AdditionalSearchPath);
                        }
                        else
                        {
                            throw new BuildException("Couldn't find AdditionalSearchPath for rules source files '{0}'", AdditionalSearchPath);
                        }
                    }
                }
            }

            // Iterate over all the folders to check
            List <FileReference>    SourceFiles       = new List <FileReference>();
            HashSet <FileReference> UniqueSourceFiles = new HashSet <FileReference>();

            foreach (DirectoryReference Folder in Folders)
            {
                IReadOnlyList <FileReference> SourceFilesForFolder = FindAllRulesFiles(Folder, RulesFileType);
                foreach (FileReference SourceFile in SourceFilesForFolder)
                {
                    if (UniqueSourceFiles.Add(SourceFile))
                    {
                        SourceFiles.Add(SourceFile);
                    }
                }
            }
            return(SourceFiles);
        }
Example #10
0
		void CleanWithUBT(string TargetName, UnrealBuildTool.UnrealTargetPlatform Platform, string Config, FileReference UprojectPath, bool ForceMonolithic = false, bool ForceNonUnity = false, bool ForceDebugInfo = false, string InAddArgs = "", bool ForceUnity = false, Dictionary<string, string> EnvVars = null)
		{
			string AddArgs = "";
			if (UprojectPath != null)
			{
				AddArgs += " " + CommandUtils.MakePathSafeToUseWithCommandLine(UprojectPath.FullName);
			}
			AddArgs += " " + InAddArgs;
			if (ForceMonolithic)
			{
				AddArgs += " -monolithic";
			}
			if (ForceNonUnity)
			{
				AddArgs += " -disableunity";
			}
			if (ForceUnity)
			{
				AddArgs += " -forceunity";
			}
			if (ForceDebugInfo)
			{
				AddArgs += " -forcedebuginfo";
			}
			if (!TargetName.Equals("UnrealHeaderTool", StringComparison.InvariantCultureIgnoreCase))
			{
				AddArgs += " -nobuilduht";
			}

			PrepareUBT();
			using(TelemetryStopwatch CleanStopwatch = new TelemetryStopwatch("CleanWithUBT.{0}.{1}.{2}", TargetName, Platform.ToString(), Config))
			{
				RunUBT(CmdEnv, UBTExecutable: UBTExecutable, Project: UprojectPath, Target: TargetName, Platform: Platform.ToString(), Config: Config, AdditionalArgs: "-clean" + AddArgs, EnvVars: EnvVars);
			}
        }
Example #11
0
        private static string ResolveString(string Input, bool bIsPath)
        {
            string Result = Input;

            // these assume entire string is a path, and will do file operations on the whole string
            if (bIsPath)
            {
                if (Result.Contains("${PROGRAM_FILES}"))
                {
                    // first look in real ProgramFiles
                    string Temp = Result.Replace("${PROGRAM_FILES}", Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles, Environment.SpecialFolderOption.DoNotVerify));
                    if (File.Exists(Temp) || Directory.Exists(Temp))
                    {
                        Result = Temp;
                    }
                    else
                    {
                        // fallback to ProgramFilesX86
                        Temp = Result.Replace("${PROGRAM_FILES}", Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86, Environment.SpecialFolderOption.DoNotVerify));
                        if (File.Exists(Temp) || Directory.Exists(Temp))
                        {
                            Result = Temp;
                        }
                    }
                }

                if (Result.Contains("${ENGINE_ROOT}"))
                {
                    string Temp = Result.Replace("${ENGINE_ROOT}", Path.GetFullPath(BuildConfiguration.RelativeEnginePath + "\\.."));

                    // get the best version
                    Result = LookForSpecialFile(Temp);
                }

                if (Result.Contains("${PROJECT_ROOT}"))
                {
                    if (!UnrealBuildTool.HasUProjectFile())
                    {
                        throw new BuildException("Configuration setting was using ${PROJECT_ROOT}, but there was no project specified");
                    }

                    string Temp = Result.Replace("${PROJECT_ROOT}", Path.GetFullPath(UnrealBuildTool.GetUProjectPath()));

                    // get the best version
                    Result = LookForSpecialFile(Temp);
                }
            }

            // non path variables
            Result = Result.Replace("${CURRENT_USER}", Environment.UserName);

            // needs a resolved key (which isn't required if user is using alternate authentication)
            if (Result.Contains("${SSH_PRIVATE_KEY}") || Result.Contains("${CYGWIN_SSH_PRIVATE_KEY}"))
            {
                // if it needs the key, then make sure we have it!
                if (ResolvedSSHPrivateKey != null)
                {
                    Result = Result.Replace("${SSH_PRIVATE_KEY}", ResolvedSSHPrivateKey);
                    Result = Result.Replace("${CYGWIN_SSH_PRIVATE_KEY}", ConvertPathToCygwin(ResolvedSSHPrivateKey));
                }
                else
                {
                    Result = null;
                }
            }

            return(Result);
        }
Example #12
0
        /// <summary>
        /// Initialize the config system with the given types
        /// </summary>
        /// <param name="bForceLoadCache">Force use of the cached XML config without checking if it's valid (useful for remote builds)</param>
        public static bool ReadConfigFiles(bool bForceLoadCache)
        {
            // Find all the configurable types
            List <Type> ConfigTypes = FindConfigurableTypes();

            // Get the path to the cache file
            FileReference 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, '+')));
                }
            }

            // Update the cache if necessary
            if (bForceLoadCache)
            {
                // 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
            {
                // 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))
                        {
                            Log.TraceError("Failed to properly read XML file : {0}", InputFile.FullName);
                            return(false);
                        }
                    }

                    // 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);
                    }
                }
            }
            return(true);
        }
        private bool WriteCMakeLists()
        {
            string       BuildCommand;
            const string CMakeSectionEnd  = " )\n\n";
            var          CMakefileContent = new StringBuilder();

            // Create Engine/Project specific lists
            StringBuilder CMakeEngineSourceFilesList  = new StringBuilder("set(ENGINE_SOURCE_FILES \n");
            StringBuilder CMakeProjectSourceFilesList = new StringBuilder("set(PROJECT_SOURCE_FILES \n");
            StringBuilder CMakeEngineHeaderFilesList  = new StringBuilder("set(ENGINE_HEADER_FILES \n");
            StringBuilder CMakeProjectHeaderFilesList = new StringBuilder("set(PROJECT_HEADER_FILES \n");
            StringBuilder CMakeEngineCSFilesList      = new StringBuilder("set(ENGINE_CSHARP_FILES \n");
            StringBuilder CMakeProjectCSFilesList     = new StringBuilder("set(PROJECT_CSHARP_FILES \n");
            StringBuilder CMakeEngineConfigFilesList  = new StringBuilder("set(ENGINE_CONFIG_FILES \n");
            StringBuilder CMakeProjectConfigFilesList = new StringBuilder("set(PROJECT_CONFIG_FILES \n");
            StringBuilder CMakeEngineShaderFilesList  = new StringBuilder("set(ENGINE_SHADER_FILES \n");
            StringBuilder CMakeProjectShaderFilesList = new StringBuilder("set(PROJECT_SHADER_FILES \n");

            StringBuilder IncludeDirectoriesList      = new StringBuilder("include_directories( \n");
            StringBuilder PreprocessorDefinitionsList = new StringBuilder("add_definitions( \n");

            string UE4RootPath          = Utils.CleanDirectorySeparators(UnrealBuildTool.RootDirectory.FullName, '/');
            var    CMakeGameRootPath    = "";
            string GameProjectPath      = "";
            string CMakeGameProjectFile = "";

            string HostArchitecture;

            switch (BuildHostPlatform.Current.Platform)
            {
            case UnrealTargetPlatform.Win64:
            {
                HostArchitecture = "Win64";
                BuildCommand     = "call \"" + UE4RootPath + "/Engine/Build/BatchFiles/Build.bat\"";
                break;
            }

            case UnrealTargetPlatform.Mac:
            {
                HostArchitecture    = "Mac";
                BuildCommand        = "cd \"" + UE4RootPath + "\" && bash \"" + UE4RootPath + "/Engine/Build/BatchFiles/" + HostArchitecture + "/Build.sh\"";
                bIncludeIOSTargets  = true;
                bIncludeTVOSTargets = true;
                break;
            }

            case UnrealTargetPlatform.Linux:
            {
                HostArchitecture = "Linux";
                BuildCommand     = "cd \"" + UE4RootPath + "\" && bash \"" + UE4RootPath + "/Engine/Build/BatchFiles/" + HostArchitecture + "/Build.sh\"";
                break;
            }

            default:
            {
                throw new BuildException("ERROR: CMakefileGenerator does not support this platform");
            }
            }

            if (IsProjectBuild)
            {
                GameProjectPath      = OnlyGameProject.Directory.FullName;
                CMakeGameRootPath    = Utils.CleanDirectorySeparators(OnlyGameProject.Directory.FullName, '/');
                CMakeGameProjectFile = Utils.CleanDirectorySeparators(OnlyGameProject.FullName, '/');
            }

            // Additional CMake file definitions
            string EngineHeadersFilePath  = FileReference.Combine(IntermediateProjectFilesPath, CMakeEngineHeadersFileName).ToString();
            string ProjectHeadersFilePath = FileReference.Combine(IntermediateProjectFilesPath, CMakeProjectHeadersFileName).ToString();
            string EngineSourcesFilePath  = FileReference.Combine(IntermediateProjectFilesPath, CMakeEngineSourcesFileName).ToString();
            string ProjectSourcesFilePath = FileReference.Combine(IntermediateProjectFilesPath, CMakeProjectSourcesFileName).ToString();
            string ProjectFilePath        = FileReference.Combine(IntermediateProjectFilesPath, CMakeProjectSourcesFileName).ToString();
            string IncludeFilePath        = FileReference.Combine(IntermediateProjectFilesPath, CMakeIncludesFileName).ToString();
            string EngineConfigsFilePath  = FileReference.Combine(IntermediateProjectFilesPath, CMakeEngineConfigsFileName).ToString();
            string ProjectConfigsFilePath = FileReference.Combine(IntermediateProjectFilesPath, CMakeProjectConfigsFileName).ToString();
            string EngineCSFilePath       = FileReference.Combine(IntermediateProjectFilesPath, CMakeEngineCSFileName).ToString();
            string ProjectCSFilePath      = FileReference.Combine(IntermediateProjectFilesPath, CMakeProjectCSFileName).ToString();
            string EngineShadersFilePath  = FileReference.Combine(IntermediateProjectFilesPath, CMakeEngineShadersFileName).ToString();
            string ProjectShadersFilePath = FileReference.Combine(IntermediateProjectFilesPath, CMakeProjectShadersFileName).ToString();
            string DefinitionsFilePath    = FileReference.Combine(IntermediateProjectFilesPath, CMakeDefinitionsFileName).ToString();

            CMakefileContent.Append(
                "# Makefile generated by CMakefileGenerator.cs (v1.2)\n" +
                "# *DO NOT EDIT*\n\n" +
                "cmake_minimum_required (VERSION 2.6)\n" +
                "project (UE4)\n\n" +
                "# CMake Flags\n" +
                "set(CMAKE_CXX_STANDARD 14)\n" +                 // Need to keep this updated
                "set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_OBJECTS 1 CACHE BOOL \"\" FORCE)\n" +
                "set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_INCLUDES 1 CACHE BOOL \"\" FORCE)\n\n" +
                "# Standard Includes\n" +
                "include(\"" + IncludeFilePath + "\")\n" +
                "include(\"" + DefinitionsFilePath + "\")\n" +
                "include(\"" + EngineHeadersFilePath + "\")\n" +
                "include(\"" + ProjectHeadersFilePath + "\")\n" +
                "include(\"" + EngineSourcesFilePath + "\")\n" +
                "include(\"" + ProjectSourcesFilePath + "\")\n" +
                "include(\"" + EngineCSFilePath + "\")\n" +
                "include(\"" + ProjectCSFilePath + "\")\n\n"
                );

            List <string> IncludeDirectories      = new List <string>();
            List <string> PreprocessorDefinitions = new List <string>();

            foreach (var CurProject in GeneratedProjectFiles)
            {
                foreach (var IncludeSearchPath in CurProject.IntelliSenseIncludeSearchPaths)
                {
                    string IncludeDirectory = GetIncludeDirectory(IncludeSearchPath, Path.GetDirectoryName(CurProject.ProjectFilePath.FullName));
                    if (IncludeDirectory != null && !IncludeDirectories.Contains(IncludeDirectory))
                    {
                        if (IncludeDirectory.Contains(UnrealBuildTool.RootDirectory.FullName))
                        {
                            IncludeDirectories.Add(IncludeDirectory.Replace(UnrealBuildTool.RootDirectory.FullName, UE4RootPath));
                        }
                        else
                        {
                            // If the path isn't rooted, then it is relative to the game root
                            if (!Path.IsPathRooted(IncludeDirectory))
                            {
                                IncludeDirectories.Add(CMakeGameRootPath + "/" + IncludeDirectory);
                            }
                            else
                            {
                                // This is a rooted path like /usr/local/sometool/include
                                IncludeDirectories.Add(IncludeDirectory);
                            }
                        }
                    }
                }

                foreach (var PreProcessorDefinition in CurProject.IntelliSensePreprocessorDefinitions)
                {
                    string Definition          = PreProcessorDefinition;
                    string AlternateDefinition = Definition.Contains("=0") ? Definition.Replace("=0", "=1") : Definition.Replace("=1", "=0");

                    if (Definition.Equals("WITH_EDITORONLY_DATA=0") || Definition.Equals("WITH_DATABASE_SUPPORT=1"))
                    {
                        Definition = AlternateDefinition;
                    }

                    if (!PreprocessorDefinitions.Contains(Definition) &&
                        !PreprocessorDefinitions.Contains(AlternateDefinition) &&
                        !Definition.StartsWith("UE_ENGINE_DIRECTORY") &&
                        !Definition.StartsWith("ORIGINAL_FILE_NAME"))
                    {
                        PreprocessorDefinitions.Add(Definition);
                    }
                }
            }

            // Create SourceFiles, HeaderFiles, and ConfigFiles sections.
            var AllModuleFiles = DiscoverModules(FindGameProjects());

            foreach (FileReference CurModuleFile in AllModuleFiles)
            {
                var FoundFiles = SourceFileSearch.FindModuleSourceFiles(CurModuleFile);
                foreach (FileReference CurSourceFile in FoundFiles)
                {
                    string SourceFileRelativeToRoot = CurSourceFile.MakeRelativeTo(UnrealBuildTool.EngineDirectory);

                    // Exclude files/folders on a per-platform basis.
                    if (!IsPathExcludedOnPlatform(SourceFileRelativeToRoot, BuildHostPlatform.Current.Platform))
                    {
                        if (SourceFileRelativeToRoot.EndsWith(".cpp"))
                        {
                            AppendCleanedPathToList(CMakeEngineSourceFilesList, CMakeProjectSourceFilesList, SourceFileRelativeToRoot, CurSourceFile.FullName, GameProjectPath, UE4RootPath, CMakeGameRootPath);
                        }
                        else if (SourceFileRelativeToRoot.EndsWith(".h"))
                        {
                            AppendCleanedPathToList(CMakeEngineHeaderFilesList, CMakeProjectHeaderFilesList, SourceFileRelativeToRoot, CurSourceFile.FullName, GameProjectPath, UE4RootPath, CMakeGameRootPath);
                        }
                        else if (SourceFileRelativeToRoot.EndsWith(".cs"))
                        {
                            AppendCleanedPathToList(CMakeEngineCSFilesList, CMakeProjectCSFilesList, SourceFileRelativeToRoot, CurSourceFile.FullName, GameProjectPath, UE4RootPath, CMakeGameRootPath);
                        }
                        else if (SourceFileRelativeToRoot.EndsWith(".usf") || SourceFileRelativeToRoot.EndsWith(".ush"))
                        {
                            AppendCleanedPathToList(CMakeEngineShaderFilesList, CMakeProjectShaderFilesList, SourceFileRelativeToRoot, CurSourceFile.FullName, GameProjectPath, UE4RootPath, CMakeGameRootPath);
                        }
                        else if (SourceFileRelativeToRoot.EndsWith(".ini"))
                        {
                            AppendCleanedPathToList(CMakeEngineConfigFilesList, CMakeProjectConfigFilesList, SourceFileRelativeToRoot, CurSourceFile.FullName, GameProjectPath, UE4RootPath, CMakeGameRootPath);
                        }
                    }
                }
            }

            foreach (string IncludeDirectory in IncludeDirectories)
            {
                IncludeDirectoriesList.Append("\t\"" + Utils.CleanDirectorySeparators(IncludeDirectory, '/') + "\"\n");
            }

            foreach (string PreprocessorDefinition in PreprocessorDefinitions)
            {
                PreprocessorDefinitionsList.Append("\t-D" + PreprocessorDefinition + "\n");
            }

            // Add Engine/Shaders files (game are added via modules)
            var EngineShaderFiles = SourceFileSearch.FindFiles(DirectoryReference.Combine(UnrealBuildTool.EngineDirectory, "Shaders"));

            foreach (FileReference CurSourceFile in EngineShaderFiles)
            {
                string SourceFileRelativeToRoot = CurSourceFile.MakeRelativeTo(UnrealBuildTool.EngineDirectory);
                if (SourceFileRelativeToRoot.EndsWith(".usf") || SourceFileRelativeToRoot.EndsWith(".ush"))
                {
                    AppendCleanedPathToList(CMakeEngineShaderFilesList, CMakeProjectShaderFilesList, SourceFileRelativeToRoot, CurSourceFile.FullName, GameProjectPath, UE4RootPath, CMakeGameRootPath);
                }
            }

            // Add Engine/Config ini files (game are added via modules)
            var EngineConfigFiles = SourceFileSearch.FindFiles(DirectoryReference.Combine(UnrealBuildTool.EngineDirectory, "Config"));

            foreach (FileReference CurSourceFile in EngineConfigFiles)
            {
                string SourceFileRelativeToRoot = CurSourceFile.MakeRelativeTo(UnrealBuildTool.EngineDirectory);
                if (SourceFileRelativeToRoot.EndsWith(".ini"))
                {
                    AppendCleanedPathToList(CMakeEngineConfigFilesList, CMakeProjectConfigFilesList, SourceFileRelativeToRoot, CurSourceFile.FullName, GameProjectPath, UE4RootPath, CMakeGameRootPath);
                }
            }

            // Add section end to section strings;
            CMakeEngineSourceFilesList.Append(CMakeSectionEnd);
            CMakeEngineHeaderFilesList.Append(CMakeSectionEnd);
            CMakeEngineCSFilesList.Append(CMakeSectionEnd);
            CMakeEngineConfigFilesList.Append(CMakeSectionEnd);
            CMakeEngineShaderFilesList.Append(CMakeSectionEnd);

            CMakeProjectSourceFilesList.Append(CMakeSectionEnd);
            CMakeProjectHeaderFilesList.Append(CMakeSectionEnd);
            CMakeProjectCSFilesList.Append(CMakeSectionEnd);
            CMakeProjectConfigFilesList.Append(CMakeSectionEnd);
            CMakeProjectShaderFilesList.Append(CMakeSectionEnd);

            IncludeDirectoriesList.Append(CMakeSectionEnd);
            PreprocessorDefinitionsList.Append(CMakeSectionEnd);

            if (bIncludeShaderSource)
            {
                CMakefileContent.Append("# Optional Shader Include\n");
                if (!IsProjectBuild || bIncludeEngineSource)
                {
                    CMakefileContent.Append("include(\"" + EngineShadersFilePath + "\")\n");
                    CMakefileContent.Append("set_source_files_properties(${ENGINE_SHADER_FILES} PROPERTIES HEADER_FILE_ONLY TRUE)\n");
                }
                CMakefileContent.Append("include(\"" + ProjectShadersFilePath + "\")\n");
                CMakefileContent.Append("set_source_files_properties(${PROJECT_SHADER_FILES} PROPERTIES HEADER_FILE_ONLY TRUE)\n");
                CMakefileContent.Append("source_group(\"Shader Files\" REGULAR_EXPRESSION .*.usf)\n\n");
            }

            if (bIncludeConfigFiles)
            {
                CMakefileContent.Append("# Optional Config Include\n");
                if (!IsProjectBuild || bIncludeEngineSource)
                {
                    CMakefileContent.Append("include(\"" + EngineConfigsFilePath + "\")\n");
                    CMakefileContent.Append("set_source_files_properties(${ENGINE_CONFIG_FILES} PROPERTIES HEADER_FILE_ONLY TRUE)\n");
                }
                CMakefileContent.Append("include(\"" + ProjectConfigsFilePath + "\")\n");
                CMakefileContent.Append("set_source_files_properties(${PROJECT_CONFIG_FILES} PROPERTIES HEADER_FILE_ONLY TRUE)\n");
                CMakefileContent.Append("source_group(\"Config Files\" REGULAR_EXPRESSION .*.ini)\n\n");
            }

            string CMakeProjectCmdArg = "";
            string UBTArguements      = "";

            if (bGeneratingGameProjectFiles)
            {
                UBTArguements += " -game";
            }
            // Should the builder output progress ticks
            if (ProgressWriter.bWriteMarkup)
            {
                UBTArguements += " -progress";
            }

            foreach (var Project in GeneratedProjectFiles)
            {
                foreach (var TargetFile in Project.ProjectTargets)
                {
                    if (TargetFile.TargetFilePath == null)
                    {
                        continue;
                    }

                    var TargetName = TargetFile.TargetFilePath.GetFileNameWithoutAnyExtensions();                           // Remove both ".cs" and ".

                    foreach (UnrealTargetConfiguration CurConfiguration in Enum.GetValues(typeof(UnrealTargetConfiguration)))
                    {
                        if (CurConfiguration != UnrealTargetConfiguration.Unknown && CurConfiguration != UnrealTargetConfiguration.Development)
                        {
                            if (UnrealBuildTool.IsValidConfiguration(CurConfiguration) && !IsTargetExcluded(TargetName, BuildHostPlatform.Current.Platform, CurConfiguration))
                            {
                                if (TargetName == GameProjectName || TargetName == (GameProjectName + "Editor"))
                                {
                                    CMakeProjectCmdArg = "\"-project=" + CMakeGameProjectFile + "\"";
                                }

                                string ConfName = Enum.GetName(typeof(UnrealTargetConfiguration), CurConfiguration);
                                CMakefileContent.Append(String.Format("add_custom_target({0}-{3}-{1} {5} {0} {3} {1} {2}{4} VERBATIM)\n", TargetName, ConfName, CMakeProjectCmdArg, HostArchitecture, UBTArguements, BuildCommand));

                                // Add iOS and TVOS targets if valid
                                if (bIncludeIOSTargets && !IsTargetExcluded(TargetName, UnrealTargetPlatform.IOS, CurConfiguration))
                                {
                                    CMakefileContent.Append(String.Format("add_custom_target({0}-{3}-{1} {5} {0} {3} {1} {2}{4} VERBATIM)\n", TargetName, ConfName, CMakeProjectCmdArg, UnrealTargetPlatform.IOS, UBTArguements, BuildCommand));
                                }
                                if (bIncludeTVOSTargets && !IsTargetExcluded(TargetName, UnrealTargetPlatform.TVOS, CurConfiguration))
                                {
                                    CMakefileContent.Append(String.Format("add_custom_target({0}-{3}-{1} {5} {0} {3} {1} {2}{4} VERBATIM)\n", TargetName, ConfName, CMakeProjectCmdArg, UnrealTargetPlatform.TVOS, UBTArguements, BuildCommand));
                                }
                            }
                        }
                    }
                    if (!IsTargetExcluded(TargetName, BuildHostPlatform.Current.Platform, UnrealTargetConfiguration.Development))
                    {
                        if (TargetName == GameProjectName || TargetName == (GameProjectName + "Editor"))
                        {
                            CMakeProjectCmdArg = "\"-project=" + CMakeGameProjectFile + "\"";
                        }

                        CMakefileContent.Append(String.Format("add_custom_target({0} {4} {0} {2} Development {1}{3} VERBATIM)\n\n", TargetName, CMakeProjectCmdArg, HostArchitecture, UBTArguements, BuildCommand));

                        // Add iOS and TVOS targets if valid
                        if (bIncludeIOSTargets && !IsTargetExcluded(TargetName, UnrealTargetPlatform.IOS, UnrealTargetConfiguration.Development))
                        {
                            CMakefileContent.Append(String.Format("add_custom_target({0}-{3} {5} {0} {3} {1} {2}{4} VERBATIM)\n", TargetName, UnrealTargetConfiguration.Development, CMakeProjectCmdArg, UnrealTargetPlatform.IOS, UBTArguements, BuildCommand));
                        }
                        if (bIncludeTVOSTargets && !IsTargetExcluded(TargetName, UnrealTargetPlatform.TVOS, UnrealTargetConfiguration.Development))
                        {
                            CMakefileContent.Append(String.Format("add_custom_target({0}-{3} {5} {0} {3} {1} {2}{4} VERBATIM)\n", TargetName, UnrealTargetConfiguration.Development, CMakeProjectCmdArg, UnrealTargetPlatform.TVOS, UBTArguements, BuildCommand));
                        }
                    }
                }
            }

            // Create Build Template
            if (IsProjectBuild && !bIncludeEngineSource)
            {
                CMakefileContent.AppendLine("add_executable(FakeTarget ${PROJECT_HEADER_FILES} ${PROJECT_SOURCE_FILES} ${PROJECT_CSHARP_FILES} ${PROJECT_SHADER_FILES} ${PROJECT_CONFIG_FILES})");
            }
            else
            {
                CMakefileContent.AppendLine("add_executable(FakeTarget ${ENGINE_HEADER_FILES} ${ENGINE_SOURCE_FILES} ${ENGINE_CSHARP_FILES} ${ENGINE_SHADER_FILES} ${ENGINE_CONFIG_FILES} ${PROJECT_HEADER_FILES} ${PROJECT_SOURCE_FILES} ${PROJECT_CSHARP_FILES} ${PROJECT_SHADER_FILES} ${PROJECT_CONFIG_FILES})");
            }

            var FullFileName = Path.Combine(MasterProjectPath.FullName, ProjectFileName);

            // Write out CMake files
            bool bWriteMakeList       = WriteFileIfChanged(FullFileName, CMakefileContent.ToString());
            bool bWriteEngineHeaders  = WriteFileIfChanged(EngineHeadersFilePath, CMakeEngineHeaderFilesList.ToString());
            bool bWriteProjectHeaders = WriteFileIfChanged(ProjectHeadersFilePath, CMakeProjectHeaderFilesList.ToString());
            bool bWriteEngineSources  = WriteFileIfChanged(EngineSourcesFilePath, CMakeEngineSourceFilesList.ToString());
            bool bWriteProjectSources = WriteFileIfChanged(ProjectSourcesFilePath, CMakeProjectSourceFilesList.ToString());
            bool bWriteIncludes       = WriteFileIfChanged(IncludeFilePath, IncludeDirectoriesList.ToString());
            bool bWriteDefinitions    = WriteFileIfChanged(DefinitionsFilePath, PreprocessorDefinitionsList.ToString());
            bool bWriteEngineConfigs  = WriteFileIfChanged(EngineConfigsFilePath, CMakeEngineConfigFilesList.ToString());
            bool bWriteProjectConfigs = WriteFileIfChanged(ProjectConfigsFilePath, CMakeProjectConfigFilesList.ToString());
            bool bWriteEngineShaders  = WriteFileIfChanged(EngineShadersFilePath, CMakeEngineShaderFilesList.ToString());
            bool bWriteProjectShaders = WriteFileIfChanged(ProjectShadersFilePath, CMakeProjectShaderFilesList.ToString());
            bool bWriteEngineCS       = WriteFileIfChanged(EngineCSFilePath, CMakeEngineCSFilesList.ToString());
            bool bWriteProjectCS      = WriteFileIfChanged(ProjectCSFilePath, CMakeProjectCSFilesList.ToString());

            // Return success flag if all files were written out successfully
            return(bWriteMakeList &&
                   bWriteEngineHeaders && bWriteProjectHeaders &&
                   bWriteEngineSources && bWriteProjectSources &&
                   bWriteEngineConfigs && bWriteProjectConfigs &&
                   bWriteEngineCS && bWriteProjectCS &&
                   bWriteEngineShaders && bWriteProjectShaders &&
                   bWriteIncludes && bWriteDefinitions);
        }
        public static bool GeneratePList(string ProjectDirectory, bool bIsUE4Game, string GameName, string ProjectName, string InEngineDir, string ExeName)
        {
            string IntermediateDirectory = (bIsUE4Game ? InEngineDir : ProjectDirectory) + "/Intermediate/Mac";
            string DestPListFile         = IntermediateDirectory + "/" + ExeName + "-Info.plist";
            string SrcPListFile          = (bIsUE4Game ? (InEngineDir + "Source/Programs/") : (ProjectDirectory + "/Source/")) + GameName + "/Resources/Mac/Info.plist";

            if (!File.Exists(SrcPListFile))
            {
                SrcPListFile = InEngineDir + "/Source/Runtime/Launch/Resources/Mac/Info.plist";
            }

            string PListData = null;

            if (File.Exists(SrcPListFile))
            {
                PListData = File.ReadAllText(SrcPListFile);
            }
            else
            {
                return(false);
            }

            // bundle identifier
            // plist replacements
            DirectoryReference DirRef = bIsUE4Game ? (!string.IsNullOrEmpty(UnrealBuildTool.GetRemoteIniPath()) ? new DirectoryReference(UnrealBuildTool.GetRemoteIniPath()) : null) : new DirectoryReference(ProjectDirectory);
            ConfigHierarchy    Ini    = ConfigCache.ReadHierarchy(ConfigHierarchyType.Engine, DirRef, UnrealTargetPlatform.IOS);

            string BundleIdentifier;

            Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "BundleIdentifier", out BundleIdentifier);

            string BundleVersion = MacToolChain.LoadEngineDisplayVersion();

            PListData = PListData.Replace("${EXECUTABLE_NAME}", ExeName).Replace("${APP_NAME}", BundleIdentifier.Replace("[PROJECT_NAME]", ProjectName).Replace("_", "")).Replace("${ICON_NAME}", GameName).Replace("${MACOSX_DEPLOYMENT_TARGET}", MacToolChain.Settings.MinMacOSVersion).Replace("${BUNDLE_VERSION}", BundleVersion);

            if (!Directory.Exists(IntermediateDirectory))
            {
                Directory.CreateDirectory(IntermediateDirectory);
            }
            File.WriteAllText(DestPListFile, PListData);

            return(true);
        }
        protected override bool WriteMasterProjectFile(ProjectFile UBTProject)
        {
            bool bSuccess = true;

            var SolutionFileName = MasterProjectName + ".sln";

            // Setup solution file content
            var VCSolutionFileContent = new StringBuilder();


            // Solution file header
            if (ProjectFileFormat == VCProjectFileFormat.VisualStudio2013)
            {
                VCSolutionFileContent.Append(
                    ProjectFileGenerator.NewLine +
                    "Microsoft Visual Studio Solution File, Format Version 12.00" + ProjectFileGenerator.NewLine +
                    "# Visual Studio 2013" + ProjectFileGenerator.NewLine);

                /* This is not required by VS 2013 to load the projects
                 * VCSolutionFileContent.Append(
                 *      "VisualStudioVersion = 12.0.20617.1 PREVIEW" + ProjectFileGenerator.NewLine +
                 *      "MinimumVisualStudioVersion = 10.0.40219.1" + ProjectFileGenerator.NewLine );*/
            }
            else if (ProjectFileFormat == VCProjectFileFormat.VisualStudio2012)
            {
                VCSolutionFileContent.Append(
                    ProjectFileGenerator.NewLine +
                    "Microsoft Visual Studio Solution File, Format Version 12.00" + ProjectFileGenerator.NewLine +
                    "# Visual Studio 2012" + ProjectFileGenerator.NewLine);
            }
            else
            {
                throw new BuildException("Unexpected ProjectFileFormat");
            }


            // Solution folders, files and project entries
            {
                // This the GUID that Visual Studio uses to identify a solution folder
                var SolutionFolderEntryGUID = "{2150E333-8FDC-42A3-9474-1A3956D46DE8}";

                // Solution folders
                {
                    var AllSolutionFolders = new List <MasterProjectFolder>();
                    System.Action <List <MasterProjectFolder> /* Folders */> GatherFoldersFunction = null;
                    GatherFoldersFunction = FolderList =>
                    {
                        AllSolutionFolders.AddRange(FolderList);
                        foreach (var CurSubFolder in FolderList)
                        {
                            GatherFoldersFunction(CurSubFolder.SubFolders);
                        }
                    };
                    GatherFoldersFunction(RootFolder.SubFolders);

                    foreach (VisualStudioSolutionFolder CurFolder in AllSolutionFolders)
                    {
                        var FolderGUIDString = CurFolder.FolderGUID.ToString("B").ToUpperInvariant();
                        VCSolutionFileContent.Append(
                            "Project(\"" + SolutionFolderEntryGUID + "\") = \"" + CurFolder.FolderName + "\", \"" + CurFolder.FolderName + "\", \"" + FolderGUIDString + "\"" + ProjectFileGenerator.NewLine);

                        // Add any files that are inlined right inside the solution folder
                        if (CurFolder.Files.Count > 0)
                        {
                            VCSolutionFileContent.Append(
                                "	ProjectSection(SolutionItems) = preProject"+ ProjectFileGenerator.NewLine);
                            foreach (var CurFile in CurFolder.Files)
                            {
                                // Syntax is:  <relative file path> = <relative file path>
                                VCSolutionFileContent.Append(
                                    "		"+ CurFile + " = " + CurFile + ProjectFileGenerator.NewLine);
                            }
                            VCSolutionFileContent.Append(
                                "	EndProjectSection"+ ProjectFileGenerator.NewLine);
                        }

                        VCSolutionFileContent.Append(
                            "EndProject" + ProjectFileGenerator.NewLine
                            );
                    }
                }


                // Project files
                foreach (MSBuildProjectFile CurProject in AllProjectFiles)
                {
                    // Visual Studio uses different GUID types depending on the project type
                    string ProjectTypeGUID = CurProject.ProjectTypeGUID;

                    // NOTE: The project name in the solution doesn't actually *have* to match the project file name on disk.  However,
                    //       we prefer it when it does match so we use the actual file name here.
                    var ProjectNameInSolution = Path.GetFileNameWithoutExtension(CurProject.ProjectFilePath);

                    // Use the existing project's GUID that's already known to us
                    var ProjectGUID = CurProject.ProjectGUID.ToString("B").ToUpperInvariant();

                    VCSolutionFileContent.Append(
                        "Project(\"" + ProjectTypeGUID + "\") = \"" + ProjectNameInSolution + "\", \"" + CurProject.RelativeProjectFilePath + "\", \"" + ProjectGUID + "\"" + ProjectFileGenerator.NewLine);

                    // Setup dependency on UnrealBuildTool, if we need that.  This makes sure that UnrealBuildTool is
                    // freshly compiled before kicking off any build operations on this target project
                    if (!CurProject.IsStubProject)
                    {
                        // Don't add self as a project dependency!
                        if ((CurProject != UBTProject) && (CurProject.IsGeneratedProject || (CurProject.DependsOnProjects.Count > 0)))
                        {
                            VCSolutionFileContent.Append(
                                "	ProjectSection(ProjectDependencies) = postProject"+ ProjectFileGenerator.NewLine);

                            if (CurProject.IsGeneratedProject && UBTProject != null)
                            {
                                var UBTProjectGUID = ((MSBuildProjectFile)UBTProject).ProjectGUID.ToString("B").ToUpperInvariant();
                                VCSolutionFileContent.Append(
                                    "		"+ UBTProjectGUID + " = " + UBTProjectGUID + ProjectFileGenerator.NewLine);
                            }

                            // Setup any addition dependencies this project has...
                            foreach (var DependsOnProject in CurProject.DependsOnProjects)
                            {
                                var DependsOnProjectGUID = ((MSBuildProjectFile)DependsOnProject).ProjectGUID.ToString("B").ToUpperInvariant();
                                VCSolutionFileContent.Append(
                                    "		"+ DependsOnProjectGUID + " = " + DependsOnProjectGUID + ProjectFileGenerator.NewLine);
                            }

                            VCSolutionFileContent.Append(
                                "	EndProjectSection"+ ProjectFileGenerator.NewLine);
                        }
                    }

                    VCSolutionFileContent.Append(
                        "EndProject" + ProjectFileGenerator.NewLine
                        );
                }
            }

            // Solution configuration platforms.  This is just a list of all of the platforms and configurations that
            // appear in Visual Studio's build configuration selector.
            var SolutionConfigCombinations = new List <VCSolutionConfigCombination>();

            // The "Global" section has source control, solution configurations, project configurations,
            // preferences, and project hierarchy data
            {
                VCSolutionFileContent.Append(
                    "Global" + ProjectFileGenerator.NewLine);
                {
                    {
                        VCSolutionFileContent.Append(
                            "	GlobalSection(SolutionConfigurationPlatforms) = preSolution"+ ProjectFileGenerator.NewLine);

                        var SolutionConfigurationsValidForProjects = new Dictionary <string, Tuple <UnrealTargetConfiguration, string> >();
                        var PlatformsValidForProjects = new HashSet <UnrealTargetPlatform>();

                        foreach (var CurConfiguration in SupportedConfigurations)
                        {
                            if (UnrealBuildTool.IsValidConfiguration(CurConfiguration))
                            {
                                foreach (var CurPlatform in SupportedPlatforms)
                                {
                                    if (UnrealBuildTool.IsValidPlatform(CurPlatform))
                                    {
                                        foreach (var CurProject in AllProjectFiles)
                                        {
                                            if (!CurProject.IsStubProject)
                                            {
                                                if (CurProject.ProjectTargets.Count == 0)
                                                {
                                                    throw new BuildException("Expecting project '" + CurProject.ProjectFilePath + "' to have at least one ProjectTarget associated with it!");
                                                }

                                                // Figure out the set of valid target configuration names
                                                foreach (var ProjectTarget in CurProject.ProjectTargets)
                                                {
                                                    if (VCProjectFile.IsValidProjectPlatformAndConfiguration(ProjectTarget, CurPlatform, CurConfiguration))
                                                    {
                                                        PlatformsValidForProjects.Add(CurPlatform);

                                                        // Default to a target configuration name of "Game", since that will collapse down to an empty string
                                                        var TargetConfigurationName = TargetRules.TargetType.Game.ToString();
                                                        if (ProjectTarget.TargetRules != null)
                                                        {
                                                            TargetConfigurationName = ProjectTarget.TargetRules.ConfigurationName;
                                                        }

                                                        var SolutionConfigName = MakeSolutionConfigurationName(CurConfiguration, TargetConfigurationName);
                                                        SolutionConfigurationsValidForProjects[SolutionConfigName] = new Tuple <UnrealTargetConfiguration, string>(CurConfiguration, TargetConfigurationName);
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }

                        foreach (var CurPlatform in PlatformsValidForProjects)
                        {
                            foreach (var SolutionConfigKeyValue in SolutionConfigurationsValidForProjects)
                            {
                                // e.g.  "Development|Win64 = Development|Win64"
                                var SolutionConfigName      = SolutionConfigKeyValue.Key;
                                var Configuration           = SolutionConfigKeyValue.Value.Item1;
                                var TargetConfigurationName = SolutionConfigKeyValue.Value.Item2;

                                var SolutionPlatformName = CurPlatform.ToString();

                                // For Rocket, there are currently no targets that are valid to build both for Win32 and Win64.  So we simply things by
                                // only displaying a "Windows" platform and building for the appropriate Windows platform automatically based on whichever
                                // configuration they have selected.
                                if (UnrealBuildTool.RunningRocket() && (CurPlatform == UnrealTargetPlatform.Win32 || CurPlatform == UnrealTargetPlatform.Win64))
                                {
                                    SolutionPlatformName = "Windows";
                                    if (Configuration == UnrealTargetConfiguration.Shipping)
                                    {
                                        if (CurPlatform != UnrealTargetPlatform.Win32)
                                        {
                                            continue;
                                        }
                                    }
                                    else
                                    {
                                        if (CurPlatform != UnrealTargetPlatform.Win64)
                                        {
                                            continue;
                                        }
                                    }
                                }

                                var SolutionConfigAndPlatformPair = SolutionConfigName + "|" + SolutionPlatformName;
                                SolutionConfigCombinations.Add(
                                    new VCSolutionConfigCombination
                                {
                                    VCSolutionConfigAndPlatformName = SolutionConfigAndPlatformPair,
                                    Configuration           = Configuration,
                                    Platform                = CurPlatform,
                                    TargetConfigurationName = TargetConfigurationName
                                }
                                    );
                            }
                        }

                        // Sort the list of solution platform strings alphabetically (Visual Studio prefers it)
                        SolutionConfigCombinations.Sort(
                            new Comparison <VCSolutionConfigCombination>(
                                (x, y) => { return(String.Compare(x.VCSolutionConfigAndPlatformName, y.VCSolutionConfigAndPlatformName, StringComparison.InvariantCultureIgnoreCase)); }
                                )
                            );

                        var AppendedSolutionConfigAndPlatformNames = new HashSet <string>(StringComparer.InvariantCultureIgnoreCase);
                        foreach (var SolutionConfigCombination in SolutionConfigCombinations)
                        {
                            // We alias "Game" and "Program" to both have the same solution configuration, so we're careful not to add the same combination twice.
                            if (!AppendedSolutionConfigAndPlatformNames.Contains(SolutionConfigCombination.VCSolutionConfigAndPlatformName))
                            {
                                VCSolutionFileContent.Append(
                                    "		"+ SolutionConfigCombination.VCSolutionConfigAndPlatformName + " = " + SolutionConfigCombination.VCSolutionConfigAndPlatformName + ProjectFileGenerator.NewLine);
                                AppendedSolutionConfigAndPlatformNames.Add(SolutionConfigCombination.VCSolutionConfigAndPlatformName);
                            }
                        }

                        VCSolutionFileContent.Append(
                            "	EndGlobalSection"+ ProjectFileGenerator.NewLine);
                    }


                    // Assign each project's "project configuration" to our "solution platform + configuration" pairs.  This
                    // also sets up which projects are actually built when building the solution.
                    {
                        VCSolutionFileContent.Append(
                            "	GlobalSection(ProjectConfigurationPlatforms) = postSolution"+ ProjectFileGenerator.NewLine);

                        var CombinationsThatWereMatchedToProjects = new List <VCSolutionConfigCombination>();

                        foreach (MSBuildProjectFile CurProject in AllProjectFiles)
                        {
                            // NOTE: We don't emit solution configuration entries for "stub" projects.  Those projects are only
                            // built using UnrealBuildTool and don't require a presence in the solution project list

                            // NOTE: We also process projects that were "imported" here, hoping to match those to our solution
                            //       configurations.  In some cases this may not be successful though.  Imported projects
                            //       should always be carefully setup to match our project generator's solution configs.
                            if (!CurProject.IsStubProject)
                            {
                                if (CurProject.ProjectTargets.Count == 0)
                                {
                                    throw new BuildException("Expecting project '" + CurProject.ProjectFilePath + "' to have at least one ProjectTarget associated with it!");
                                }
                                var IsProgramProject = CurProject.ProjectTargets[0].TargetRules != null && CurProject.ProjectTargets[0].TargetRules.Type == TargetRules.TargetType.Program;

                                var GameOrProgramConfigsAlreadyMapped = new HashSet <string>();
                                foreach (var SolutionConfigCombination in SolutionConfigCombinations)
                                {
                                    // Handle aliasing of Program and Game target configuration names
                                    if ((IsProgramProject && GameOrProgramConfigsAlreadyMapped.Add(SolutionConfigCombination.VCSolutionConfigAndPlatformName)) ||
                                        IsProgramProject && SolutionConfigCombination.TargetConfigurationName != TargetRules.TargetType.Game.ToString() ||
                                        !IsProgramProject && SolutionConfigCombination.TargetConfigurationName != TargetRules.TargetType.Program.ToString())
                                    {
                                        var TargetConfigurationName = SolutionConfigCombination.TargetConfigurationName;
                                        if (IsProgramProject && TargetConfigurationName == TargetRules.TargetType.Game.ToString())
                                        {
                                            TargetConfigurationName = TargetRules.TargetType.Program.ToString();
                                        }

                                        // Now, we want to find a target in this project that maps to the current solution config combination.  Only up to one target should
                                        // and every solution config combination should map to at least one target in one project (otherwise we shouldn't have added it!).
                                        ProjectTarget MatchingProjectTarget = null;
                                        foreach (var ProjectTarget in CurProject.ProjectTargets)
                                        {
                                            bool IsMatchingCombination = VCProjectFile.IsValidProjectPlatformAndConfiguration(ProjectTarget, SolutionConfigCombination.Platform, SolutionConfigCombination.Configuration);
                                            if (ProjectTarget.TargetRules != null)
                                            {
                                                if (TargetConfigurationName != ProjectTarget.TargetRules.ConfigurationName)
                                                {
                                                    // Solution configuration name for this combination doesn't match this target's configuration name.  It's not buildable.
                                                    IsMatchingCombination = false;
                                                }
                                            }
                                            else
                                            {
                                                // UBT gets a pass because it is a dependency of every single configuration combination
                                                if (CurProject != UBTProject &&
                                                    !CurProject.ShouldBuildForAllSolutionTargets &&
                                                    TargetConfigurationName != TargetRules.TargetType.Game.ToString())
                                                {
                                                    // Can't build non-generated project in configurations except for the default (Game)
                                                    IsMatchingCombination = false;
                                                }
                                            }

                                            if (IsMatchingCombination)
                                            {
                                                if (MatchingProjectTarget != null)
                                                {
                                                    // Not expecting more than one target to match a single solution configuration per project!
                                                    throw new BuildException("Not expecting more than one target for project " + CurProject.ProjectFilePath + " to match solution configuration " + SolutionConfigCombination.VCSolutionConfigAndPlatformName);
                                                }

                                                MatchingProjectTarget = ProjectTarget;

                                                // NOTE: For faster perf, we could "break" here and bail out early, but that would circumvent the error checking
                                                //		 for multiple targets within a project that may map to a single solution configuration.
                                            }
                                        }

                                        var SolutionConfiguration = SolutionConfigCombination.Configuration;
                                        var SolutionPlatform      = SolutionConfigCombination.Platform;


                                        if (MatchingProjectTarget == null)
                                        {
                                            // The current configuration/platform and target configuration name doesn't map to anything our project actually supports.
                                            // We'll map it to a default config.
                                            SolutionConfiguration = UnrealTargetConfiguration.Development;

                                            // Prefer using Win64 as the default, but fall back to a platform the project file actually supports if needed.  This is for
                                            // projects that can never be compiled in Windows, such as UnrealLaunchDaemon which is an iOS-only program
                                            SolutionPlatform = UnrealTargetPlatform.Win64;
                                            if (CurProject.ProjectTargets[0].TargetRules != null)
                                            {
                                                var ProjectSupportedPlatforms = new List <UnrealTargetPlatform>();
                                                CurProject.ProjectTargets[0].TargetRules.GetSupportedPlatforms(ref ProjectSupportedPlatforms);
                                                if (!ProjectSupportedPlatforms.Contains(SolutionPlatform))
                                                {
                                                    SolutionPlatform = ProjectSupportedPlatforms[0];
                                                }
                                            }


                                            if (IsProgramProject)
                                            {
                                                TargetConfigurationName = TargetRules.TargetType.Program.ToString();
                                            }
                                            else
                                            {
                                                TargetConfigurationName = TargetRules.TargetType.Game.ToString();
                                            }
                                        }


                                        // If the project wants to always build in "Development", regardless of what the solution
                                        // configuration is set to, then we'll do that here.  This is used for projects like
                                        // UnrealBuildTool and ShaderCompileWorker
                                        if (MatchingProjectTarget != null)
                                        {
                                            if (MatchingProjectTarget.ForceDevelopmentConfiguration)
                                            {
                                                SolutionConfiguration = UnrealTargetConfiguration.Development;
                                            }
                                        }


                                        string ProjectConfigName;
                                        string ProjectPlatformName;
                                        CurProject.MakeProjectPlatformAndConfigurationNames(SolutionPlatform, SolutionConfiguration, TargetConfigurationName, out ProjectPlatformName, out ProjectConfigName);

                                        var ProjectConfigAndPlatformPair = ProjectConfigName.ToString() + "|" + ProjectPlatformName.ToString();

                                        // e.g.  "{4232C52C-680F-4850-8855-DC39419B5E9B}.Debug|iOS.ActiveCfg = iOS_Debug|Win32"
                                        var CurProjectGUID = CurProject.ProjectGUID.ToString("B").ToUpperInvariant();
                                        VCSolutionFileContent.Append(
                                            "		"+ CurProjectGUID + "." + SolutionConfigCombination.VCSolutionConfigAndPlatformName + ".ActiveCfg = " + ProjectConfigAndPlatformPair + ProjectFileGenerator.NewLine);


                                        // Set whether this project configuration should be built when the user initiates "build solution"
                                        if (MatchingProjectTarget != null)
                                        {
                                            VCSolutionFileContent.Append(
                                                "		"+ CurProjectGUID + "." + SolutionConfigCombination.VCSolutionConfigAndPlatformName + ".Build.0 = " + ProjectConfigAndPlatformPair + ProjectFileGenerator.NewLine);

                                            var ProjGen = UEPlatformProjectGenerator.GetPlatformProjectGenerator(SolutionConfigCombination.Platform, true);
                                            if (MatchingProjectTarget.ProjectDeploys ||
                                                ((ProjGen != null) && (ProjGen.GetVisualStudioDeploymentEnabled(SolutionPlatform, SolutionConfiguration) == true)))
                                            {
                                                VCSolutionFileContent.Append(
                                                    "		"+ CurProjectGUID + "." + SolutionConfigCombination.VCSolutionConfigAndPlatformName + ".Deploy.0 = " + ProjectConfigAndPlatformPair + ProjectFileGenerator.NewLine);
                                            }
                                        }

                                        CombinationsThatWereMatchedToProjects.Add(SolutionConfigCombination);
                                    }
                                }
                            }
                        }

                        // Check for problems
                        foreach (var SolutionConfigCombination in SolutionConfigCombinations)
                        {
                            if (!CombinationsThatWereMatchedToProjects.Contains(SolutionConfigCombination))
                            {
                                throw new BuildException("Unable to find a ProjectTarget that matches the solution configuration/platform mapping: " + SolutionConfigCombination.Configuration.ToString() + ", " + SolutionConfigCombination.Platform.ToString() + ", " + SolutionConfigCombination.TargetConfigurationName);
                            }
                        }
                        VCSolutionFileContent.Append(
                            "	EndGlobalSection"+ ProjectFileGenerator.NewLine);
                    }


                    // Setup other solution properties
                    {
                        VCSolutionFileContent.Append(
                            "	GlobalSection(SolutionProperties) = preSolution"+ ProjectFileGenerator.NewLine);

                        // HideSolutionNode sets whether or not the top-level solution entry is completely hidden in the UI.
                        // We don't want that, as we need users to be able to right click on the solution tree item.
                        VCSolutionFileContent.Append(
                            "		HideSolutionNode = FALSE"+ ProjectFileGenerator.NewLine);

                        VCSolutionFileContent.Append(
                            "	EndGlobalSection"+ ProjectFileGenerator.NewLine);
                    }



                    // Solution directory hierarchy
                    {
                        VCSolutionFileContent.Append(
                            "	GlobalSection(NestedProjects) = preSolution"+ ProjectFileGenerator.NewLine);

                        // Every entry in this section is in the format "Guid1 = Guid2".  Guid1 is the child project (or solution
                        // filter)'s GUID, and Guid2 is the solution filter directory to parent the child project (or solution
                        // filter) to.  This sets up the hierarchical solution explorer tree for all solution folders and projects.

                        System.Action <StringBuilder /* VCSolutionFileContent */, List <MasterProjectFolder> /* Folders */> FolderProcessorFunction = null;
                        FolderProcessorFunction = (LocalVCSolutionFileContent, LocalMasterProjectFolders) =>
                        {
                            foreach (VisualStudioSolutionFolder CurFolder in LocalMasterProjectFolders)
                            {
                                var CurFolderGUIDString = CurFolder.FolderGUID.ToString("B").ToUpperInvariant();

                                foreach (MSBuildProjectFile ChildProject in CurFolder.ChildProjects)
                                {
                                    //	e.g. "{BF6FB09F-A2A6-468F-BE6F-DEBE07EAD3EA} = {C43B6BB5-3EF0-4784-B896-4099753BCDA9}"
                                    LocalVCSolutionFileContent.Append(
                                        "		"+ ChildProject.ProjectGUID.ToString("B").ToUpperInvariant() + " = " + CurFolderGUIDString + ProjectFileGenerator.NewLine);
                                }

                                foreach (VisualStudioSolutionFolder SubFolder in CurFolder.SubFolders)
                                {
                                    //	e.g. "{BF6FB09F-A2A6-468F-BE6F-DEBE07EAD3EA} = {C43B6BB5-3EF0-4784-B896-4099753BCDA9}"
                                    LocalVCSolutionFileContent.Append(
                                        "		"+ SubFolder.FolderGUID.ToString("B").ToUpperInvariant() + " = " + CurFolderGUIDString + ProjectFileGenerator.NewLine);
                                }

                                // Recurse into subfolders
                                FolderProcessorFunction(LocalVCSolutionFileContent, CurFolder.SubFolders);
                            }
                        };
                        FolderProcessorFunction(VCSolutionFileContent, RootFolder.SubFolders);

                        VCSolutionFileContent.Append(
                            "	EndGlobalSection"+ ProjectFileGenerator.NewLine);
                    }
                }

                VCSolutionFileContent.Append(
                    "EndGlobal" + ProjectFileGenerator.NewLine);
            }


            // Save the solution file
            if (bSuccess)
            {
                var SolutionFilePath = Path.Combine(MasterProjectRelativePath, SolutionFileName);
                bSuccess = WriteFileIfChanged(SolutionFilePath, VCSolutionFileContent.ToString());
            }


            // Save a solution config file which selects the development editor configuration by default.
            if (bSuccess)
            {
                // Figure out the filename for the SUO file. VS2013 will automatically import the VS2012 options if necessary.
                string SolutionOptionsExtension = (ProjectFileFormat == VCProjectFileFormat.VisualStudio2012)? "v11.suo" : "v12.suo";

                // Check it doesn't exist before overwriting it. Since these files store the user's preferences, it'd be bad form to overwrite them.
                string SolutionOptionsFileName = Path.Combine(MasterProjectRelativePath, Path.ChangeExtension(SolutionFileName, SolutionOptionsExtension));
                if (!File.Exists(SolutionOptionsFileName))
                {
                    VCSolutionOptions Options = new VCSolutionOptions();

                    // Set the default configuration and startup project
                    VCSolutionConfigCombination DefaultConfig = SolutionConfigCombinations.Find(x => x.Configuration == UnrealTargetConfiguration.Development && x.Platform == UnrealTargetPlatform.Win64 && x.TargetConfigurationName == "Editor");
                    if (DefaultConfig != null)
                    {
                        List <VCBinarySetting> Settings = new List <VCBinarySetting>();
                        Settings.Add(new VCBinarySetting("ActiveCfg", DefaultConfig.VCSolutionConfigAndPlatformName));
                        if (DefaultProject != null)
                        {
                            Settings.Add(new VCBinarySetting("StartupProject", ((MSBuildProjectFile)DefaultProject).ProjectGUID.ToString("B")));
                        }
                        Options.SetConfiguration(Settings);
                    }

                    // Mark all the projects as closed by default, apart from the startup project
                    VCSolutionExplorerState ExplorerState = new VCSolutionExplorerState();
                    foreach (ProjectFile ProjectFile in AllProjectFiles)
                    {
                        string ProjectName = Path.GetFileNameWithoutExtension(ProjectFile.ProjectFilePath);
                        if (ProjectFile == DefaultProject)
                        {
                            ExplorerState.OpenProjects.Add(new Tuple <string, string[]>(ProjectName, new string[] { ProjectName }));
                        }
                        else
                        {
                            ExplorerState.OpenProjects.Add(new Tuple <string, string[]>(ProjectName, new string[] { }));
                        }
                    }
                    if (IncludeEnginePrograms)
                    {
                        ExplorerState.OpenProjects.Add(new Tuple <string, string[]>("Automation", new string[0]));
                    }
                    Options.SetExplorerState(ExplorerState);

                    // Write the file
                    if (Options.Sections.Count > 0)
                    {
                        Options.Write(SolutionOptionsFileName);
                    }
                }
            }

            return(bSuccess);
        }
        /// <summary>
        ///  Write the Command section for a .kdev4/$ProjectName.kdev4 file.
        /// </summary>
        /// <param name="FileContent">File content.</param>
        private void WriteCommandSection(ref StringBuilder FileContent)
        {
            int BuildConfigIndex = 1;

            var UnrealRootPath = Path.GetFullPath(ProjectFileGenerator.RootRelativePath);

            FileContent.Append("[CustomBuildSystem]\n");
            FileContent.Append("CurrentConfiguration=BuildConfig0\n\n");             //

            // The Basics to get up and running with the editor, utilizing the Makefile.
            FileContent.Append(String.Format("[CustomBuildSystem][BuildConfig0]\nBuildDir=file://{0}\n", UnrealRootPath));

            FileContent.Append("Title=BuildMeFirst\n\n");
            FileContent.Append("[CustomBuildSystem][BuildConfig0][ToolBuild]\n");
            FileContent.Append("Arguments=-f Makefile UE4Editor UE4Game ShaderCompileWorker UnrealLightmass UnrealPak\n");
            FileContent.Append("Enabled=true\n");
            FileContent.Append("Environment=\n");
            FileContent.Append("Executable=make\n");
            FileContent.Append("Type=0\n\n");

            FileContent.Append("[CustomBuildSystem][BuildConfig0][ToolClean]\n");
            FileContent.Append("Arguments=-f Makefile UE4Editor UE4Game ShaderCompileWorker UnrealLightmass UnrealPak -clean\n");
            FileContent.Append("Enabled=true\n");
            FileContent.Append("Environment=\n");
            FileContent.Append("Executable=make\n");
            FileContent.Append("Type=3\n\n");

            FileContent.Append("[CustomBuildSystem][BuildConfig0][ToolConfigure]\n");
            FileContent.Append("Arguments=./GenerateProjectFiles.sh\n");
            FileContent.Append("Enabled=true\n");
            FileContent.Append("Environment=\n");
            FileContent.Append("Executable=bash\n");
            FileContent.Append("Type=1\n\n");

            foreach (var Project in GeneratedProjectFiles)
            {
                foreach (var TargetFile in Project.ProjectTargets)
                {
                    if (TargetFile.TargetFilePath == null)
                    {
                        continue;
                    }

                    var TargetName = TargetFile.TargetFilePath.GetFileNameWithoutAnyExtensions();

                    // Remove both ".cs" and ".
                    foreach (UnrealTargetConfiguration CurConfiguration in Enum.GetValues(typeof(UnrealTargetConfiguration)))
                    {
                        if (CurConfiguration != UnrealTargetConfiguration.Unknown && CurConfiguration != UnrealTargetConfiguration.Development)
                        {
                            if (UnrealBuildTool.IsValidConfiguration(CurConfiguration))
                            {
                                var ConfName = Enum.GetName(typeof(UnrealTargetConfiguration), CurConfiguration);
                                FileContent.Append(String.Format("[CustomBuildSystem][BuildConfig{0}]\nBuildDir=file://{1}\n", BuildConfigIndex, UnrealRootPath));

                                if (TargetName == GameProjectName)
                                {
                                    FileContent.Append(String.Format("Title={0}-Linux-{1}\n\n", TargetName, ConfName));
                                    WriteCommandSubSection(ref FileContent, TargetName, ConfName, BuildConfigIndex, 0);
                                    WriteCommandSubSection(ref FileContent, TargetName, ConfName, BuildConfigIndex, 1);
                                    WriteCommandSubSection(ref FileContent, TargetName, ConfName, BuildConfigIndex, 3);
                                }
                                else if (TargetName == (GameProjectName + "Editor"))
                                {
                                    FileContent.Append(String.Format("Title={0}-Linux-{1}\n\n", TargetName, ConfName));
                                    WriteCommandSubSection(ref FileContent, TargetName, ConfName, BuildConfigIndex, 0);
                                    WriteCommandSubSection(ref FileContent, TargetName, ConfName, BuildConfigIndex, 1);
                                    WriteCommandSubSection(ref FileContent, TargetName, ConfName, BuildConfigIndex, 3);
                                }
                                else
                                {
                                    FileContent.Append(String.Format("Title={0}-Linux-{1}\n\n", TargetName, ConfName));
                                    WriteCommandSubSection(ref FileContent, TargetName, ConfName, BuildConfigIndex, 0);
                                    WriteCommandSubSection(ref FileContent, TargetName, ConfName, BuildConfigIndex, 1);
                                    WriteCommandSubSection(ref FileContent, TargetName, ConfName, BuildConfigIndex, 3);
                                }
                                BuildConfigIndex++;
                            }
                        }
                    }

                    FileContent.Append(String.Format("[CustomBuildSystem][BuildConfig{0}]\nBuildDir=file://{1}\n", BuildConfigIndex, UnrealRootPath));
                    if (TargetName == GameProjectName)
                    {
                        FileContent.Append(String.Format("Title={0}\n\n", TargetName));
                        WriteCommandSubSection(ref FileContent, TargetName, "Development", BuildConfigIndex, 0);
                        WriteCommandSubSection(ref FileContent, TargetName, "Development", BuildConfigIndex, 1);
                        WriteCommandSubSection(ref FileContent, TargetName, "Development", BuildConfigIndex, 3);
                    }
                    else if (TargetName == (GameProjectName + "Editor"))
                    {
                        FileContent.Append(String.Format("Title={0}\n\n", TargetName));
                        WriteCommandSubSection(ref FileContent, TargetName, "Development", BuildConfigIndex, 0);
                        WriteCommandSubSection(ref FileContent, TargetName, "Development", BuildConfigIndex, 1);
                        WriteCommandSubSection(ref FileContent, TargetName, "Development", BuildConfigIndex, 3);
                    }
                    else
                    {
                        FileContent.Append(String.Format("Title={0}\n\n", TargetName));
                        WriteCommandSubSection(ref FileContent, TargetName, "Development", BuildConfigIndex, 0);
                        WriteCommandSubSection(ref FileContent, TargetName, "Development", BuildConfigIndex, 1);
                        WriteCommandSubSection(ref FileContent, TargetName, "Development", BuildConfigIndex, 3);
                    }
                    BuildConfigIndex++;
                }
            }
        }
            public BranchUProject(UnrealBuildTool.UProjectInfo InfoEntry)
            {
                GameName = InfoEntry.GameName;

                //not sure what the heck this path is relative to
                FilePath = InfoEntry.FilePath;

                if (!CommandUtils.FileExists_NoExceptions(FilePath.FullName))
                {
                    throw new AutomationException("Could not resolve relative path corrctly {0} -> {1} which doesn't exist.", InfoEntry.FilePath, FilePath);
                }

                Properties = ProjectUtils.GetProjectProperties(FilePath);



            }
Example #18
0
		XGEItem XGEPrepareBuildWithUBT(string TargetName, UnrealBuildTool.UnrealTargetPlatform Platform, string Config, FileReference UprojectPath, bool ForceMonolithic = false, bool ForceNonUnity = false, bool ForceDebugInfo = false, string InAddArgs = "", bool ForceUnity = false, Dictionary<string, string> EnvVars = null)
		{
			string AddArgs = "";
			if (UprojectPath != null)
			{
				AddArgs += " " + CommandUtils.MakePathSafeToUseWithCommandLine(UprojectPath.FullName);
			}
			AddArgs += " " + InAddArgs;
			if (ForceMonolithic)
			{
				AddArgs += " -monolithic";
			}
			if (ForceNonUnity)
			{
				AddArgs += " -disableunity";
			}
			if (ForceUnity)
			{
				AddArgs += " -forceunity";
			}
			if (ForceDebugInfo)
			{
				AddArgs += " -forcedebuginfo";
			}

			PrepareUBT();

            string UBTManifest = GetUBTManifest(UprojectPath, AddArgs);

			DeleteFile(UBTManifest);
			XGEItem Result = new XGEItem();

			ClearExportedXGEXML();

			using(TelemetryStopwatch GenerateManifestStopwatch = new TelemetryStopwatch("GenerateXGEManifest.{0}.{1}.{2}", TargetName, Platform.ToString(), Config))
			{
				RunUBT(CmdEnv, UBTExecutable: UBTExecutable, Project: UprojectPath, Target: TargetName, Platform: Platform.ToString(), Config: Config, AdditionalArgs: "-generatemanifest -nobuilduht -xgeexport" + AddArgs, EnvVars: EnvVars);
			}

			PrepareManifest(UBTManifest, true);

			Result.Platform = Platform;
			Result.Config = Config;
			Result.TargetName = TargetName;
			Result.UProjectPath = UprojectPath;
			Result.Manifest = ReadManifest(UBTManifest);
			Result.OutputCaption = String.Format("{0}-{1}-{2}", TargetName, Platform.ToString(), Config.ToString());
			DeleteFile(UBTManifest);

			Result.CommandLine = UBTExecutable + " " + UBTCommandline(Project: UprojectPath, Target: TargetName, Platform: Platform.ToString(), Config: Config, AdditionalArgs: "-noxge -nobuilduht" + AddArgs);

			Result.XgeXmlFiles = new List<string>();
			foreach (var XGEFile in FindXGEFiles())
			{
				if (!FileExists_NoExceptions(XGEFile))
				{
					throw new AutomationException("BUILD FAILED: Couldn't find file: {0}", XGEFile);
				}
				int FileNum = 0;
				string OutFile;
				while (true)
				{
					OutFile = CombinePaths(CmdEnv.LogFolder, String.Format("UBTExport.{0}.xge.xml", FileNum));
					FileInfo ItemInfo = new FileInfo(OutFile);
					if (!ItemInfo.Exists)
					{
						break;
					}
					FileNum++;
				}
				CopyFile(XGEFile, OutFile);
				Result.XgeXmlFiles.Add(OutFile);
			}
			ClearExportedXGEXML();
			return Result;
		}
Example #19
0
        // Look for any build options in the engine config file.
        public override void ParseProjectSettings()
        {
            base.ParseProjectSettings();

            ConfigCacheIni Ini        = new ConfigCacheIni(UnrealTargetPlatform.IOS, "Engine", UnrealBuildTool.GetUProjectPath());
            string         ServerName = RemoteServerName;

            if (Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "RemoteServerName", out ServerName) && !String.IsNullOrEmpty(ServerName))
            {
                RemoteServerName = ServerName;
            }

            bool bUseRSync = false;

            if (Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bUseRSync", out bUseRSync))
            {
                bUseRPCUtil = !bUseRSync;
                string UserName = RSyncUsername;

                if (Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "RSyncUsername", out UserName))
                {
                    RSyncUsername = UserName;
                }

                if (Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "DeltaCopyInstallPath", out OverrideDeltaCopyInstallPath))
                {
                    if (!string.IsNullOrEmpty(OverrideDeltaCopyInstallPath))
                    {
                        SSHExe   = Path.Combine(OverrideDeltaCopyInstallPath, Path.GetFileName(SSHExe));
                        RSyncExe = Path.Combine(OverrideDeltaCopyInstallPath, Path.GetFileName(RSyncExe));
                    }
                }

                string ConfigKeyPath;
                if (Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "SSHPrivateKeyOverridePath", out ConfigKeyPath))
                {
                    if (File.Exists(ConfigKeyPath))
                    {
                        SSHPrivateKeyOverridePath = ConfigKeyPath;
                    }
                }
            }
        }
Example #20
0
			/// <summary>
			/// Adds multiple targets with the specified configuration.
			/// </summary>
			/// <param name="TargetNames">List of targets.</param>
			/// <param name="InPlatform">Platform</param>
			/// <param name="InConfiguration">Configuration</param>
			/// <param name="InUprojectPath">Path to optional uproject file</param>
			/// <param name="InAddArgs">Specifies additional arguments for UBT</param>
			public void AddTargets(string[] TargetNames, UnrealBuildTool.UnrealTargetPlatform InPlatform, UnrealBuildTool.UnrealTargetConfiguration InConfiguration, FileReference InUprojectPath = null, string InAddArgs = "")
			{
				// Is this platform a compilable target?
				if (!Platform.GetPlatform(InPlatform).CanBeCompiled())
				{
					return;
				}

				foreach (var Target in TargetNames)
				{
					Targets.Add(new BuildTarget()
					{
						TargetName = Target,
						Platform = InPlatform,
						Config = InConfiguration,
						UprojectPath = InUprojectPath,
						UBTArgs = InAddArgs,
					});
				}
			}
Example #21
0
        private static RemoteToolChainErrorCode InitializeRemoteExecution()
        {
            if (bHasBeenInitialized)
            {
                return(InitializationErrorCode);
            }

            if (BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac)
            {
                // If we don't care which machine we're going to build on, query and
                // pick the one with the most free command slots available
                if (RemoteServerName == "best_available")
                {
                    int AvailableSlots = 0;
                    int Attempts       = 0;
                    if (!ProjectFileGenerator.bGenerateProjectFiles)
                    {
                        Log.TraceInformation("Picking a random Mac builder...");
                    }
                    while (AvailableSlots < 2 && Attempts < 20)
                    {
                        RemoteServerName = PotentialServerNames.OrderBy(x => Guid.NewGuid()).FirstOrDefault();

                        // make sure it's ready to take commands
                        AvailableSlots = GetAvailableCommandSlotCount(RemoteServerName);

                        Attempts++;
                    }

                    // make sure it succeeded
                    if (AvailableSlots <= 1)
                    {
                        throw new BuildException("Failed to find a Mac available to take commands!");
                    }
                    else if (!ProjectFileGenerator.bGenerateProjectFiles)
                    {
                        Log.TraceInformation("Chose {0} after {1} attempts to find a Mac, with {2} slots", RemoteServerName, Attempts, AvailableSlots);
                    }

/*
 * this does not work right, because it pushes a lot of tasks to machines that have substantially more slots than others
 *                                      Log.TraceInformation("Picking the best available Mac builder...");
 *                      Int32 MostAvailableCount = Int32.MinValue;
 *                                      foreach (string NextMacName in PotentialServerNames)
 *                      {
 *                      Int32 NextAvailableCount = GetAvailableCommandSlotCount(NextMacName);
 *                      if (NextAvailableCount > MostAvailableCount)
 *                      {
 *                              MostAvailableName = NextMacName;
 *                              MostAvailableCount = NextAvailableCount;
 *                      }
 *
 *                                              Log.TraceVerbose("... " + NextMacName + " has " + NextAvailableCount + " slots available");
 *                      }
 *                      Log.TraceVerbose("Picking the compile server with the most available command slots: " + MostAvailableName);
 *
 *                      // Finally, assign the name of the Mac we're going to use
 *                                      RemoteServerName = MostAvailableName;
 */
                }
                else if (!ProjectFileGenerator.bGenerateProjectFiles)
                {
                    Log.TraceInformation("Picking the default remote server " + RemoteServerName);
                }

                // we need a server name!
                if (string.IsNullOrEmpty(RemoteServerName))
                {
                    Log.TraceError("Remote compiling requires a server name. Use the editor to set up your remote compilation settings.");
                    return(RemoteToolChainErrorCode.ServerNameNotSpecified);
                }

                if (!bUseRPCUtil)
                {
                    // Verify the Delta Copy install path
                    ResolvedRSyncExe = ResolveString(RSyncExe, true);
                    ResolvedSSHExe   = ResolveString(SSHExe, true);

                    if (!File.Exists(ResolvedRSyncExe) || !File.Exists(ResolvedSSHExe))
                    {
                        Log.TraceError("Remote compiling requires Delta Copy to be installed.");
                        return(RemoteToolChainErrorCode.MissingDeltaCopyInstall);
                    }

                    // we need the RemoteServerName and the Username to find the private key
                    ResolvedRSyncUsername = ResolveString(RSyncUsername, false);
                    if (string.IsNullOrEmpty(ResolvedRSyncUsername))
                    {
                        Log.TraceError("Remote compiling requires a user name. Use the editor to set up your remote compilation settings.");
                        return(RemoteToolChainErrorCode.MissingRemoteUserName);
                    }

                    bool bFoundOverrideSSHPrivateKey = false;

                    // if the override path is set, just use it directly
                    if (!string.IsNullOrEmpty(SSHPrivateKeyOverridePath))
                    {
                        ResolvedSSHPrivateKey = ResolveString(SSHPrivateKeyOverridePath, true);

                        bFoundOverrideSSHPrivateKey = File.Exists(ResolvedSSHPrivateKey);

                        // make sure it exists
                        if (!bFoundOverrideSSHPrivateKey)
                        {
                            Log.TraceWarning("An SSHKey override was specified [" + SSHPrivateKeyOverridePath + "] but it doesn't exist. Looking elsewhere...");
                        }
                    }

                    if (!bFoundOverrideSSHPrivateKey)
                    {
                        // all the places to look for a key
                        string[] Locations = new string[] {
                            Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Unreal Engine", "UnrealBuildTool"),
                            Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "Unreal Engine", "UnrealBuildTool"),
                            Path.Combine(UnrealBuildTool.GetUProjectPath(), "Build", "NotForLicensees"),
                            Path.Combine(UnrealBuildTool.GetUProjectPath(), "Build", "NoRedist"),
                            Path.Combine(UnrealBuildTool.GetUProjectPath(), "Build"),
                            Path.Combine(BuildConfiguration.RelativeEnginePath, "Build", "NotForLicensees"),
                            Path.Combine(BuildConfiguration.RelativeEnginePath, "Build", "NoRedist"),
                            Path.Combine(BuildConfiguration.RelativeEnginePath, "Build"),
                        };

                        // look for a key file
                        foreach (string Location in Locations)
                        {
                            string KeyPath = Path.Combine(Location, "SSHKeys", RemoteServerName, ResolvedRSyncUsername, "RemoteToolChainPrivate.key");
                            if (File.Exists(KeyPath))
                            {
                                ResolvedSSHPrivateKey       = KeyPath;
                                bFoundOverrideSSHPrivateKey = true;
                                break;
                            }
                        }
                    }

                    // resolve the rest of the strings
                    ResolvedRsyncAuthentication = ResolveString(RsyncAuthentication, false);
                    ResolvedSSHAuthentication   = ResolveString(SSHAuthentication, false);
                }

                // start up remote communication and record if it succeeds
                InitializationErrorCode = (RemoteToolChainErrorCode)RPCUtilHelper.Initialize(RemoteServerName);
                if (InitializationErrorCode != RemoteToolChainErrorCode.NoError && InitializationErrorCode != RemoteToolChainErrorCode.MissingSSHKey)
                {
                    Log.TraceError("Failed to initialize a connection to the Remote Server {0}", RemoteServerName);
                    return(InitializationErrorCode);
                }
                else if (InitializationErrorCode == RemoteToolChainErrorCode.MissingSSHKey)
                {
                    // Allow the user to set up a key from here.
                    Process KeyProcess = new Process();
                    KeyProcess.StartInfo.WorkingDirectory = Path.GetFullPath(Path.Combine(BuildConfiguration.RelativeEnginePath, "Build", "BatchFiles"));
                    KeyProcess.StartInfo.FileName         = "MakeAndInstallSSHKey.bat";
                    KeyProcess.StartInfo.Arguments        = string.Format(
                        "\"{0}\" \"{1}\" {2} {3} \"{4}\" \"{5}\" \"{6}\"",
                        ResolvedSSHExe,
                        ResolvedRSyncExe,
                        ResolvedRSyncUsername,
                        RemoteServerName,
                        Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
                        ConvertPathToCygwin(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)),
                        Path.GetFullPath(BuildConfiguration.RelativeEnginePath));

                    KeyProcess.Start();
                    KeyProcess.WaitForExit();

                    // make sure it succeeded if we want to re-init
                    if (KeyProcess.ExitCode == 0)
                    {
                        InitializationErrorCode = InitializeRemoteExecution();
                    }
                }
            }
            else
            {
                RemoteServerName = Environment.MachineName;
                // can't error in this case
            }

            bHasBeenInitialized = true;
            return(InitializationErrorCode);
        }
Example #22
0
        public override void ResetBuildConfiguration(UnrealTargetPlatform InPlatform, UnrealTargetConfiguration InConfiguration)
        {
            UEBuildConfiguration.bCompileICU = true;

            // Should we enable Windows XP support
            {
                // If it wasnt set as an XML flag, check if it is requested from the commandline.
                if (!SupportWindowsXPIfAvailable)
                {
                    string[] CmdLine = Environment.GetCommandLineArgs();
                    SupportWindowsXPIfAvailable = CmdLine.Contains("-winxp", StringComparer.InvariantCultureIgnoreCase);

                    // ...check if it was supported from a config.
                    if (!SupportWindowsXPIfAvailable)
                    {
                        ConfigCacheIni Ini = new ConfigCacheIni(UnrealTargetPlatform.Win64, "Engine", UnrealBuildTool.GetUProjectPath());
                        string         MinimumOS;
                        if (Ini.GetString("/Script/WindowsTargetPlatform.WindowsTargetSettings", "MinimumOSVersion", out MinimumOS))
                        {
                            if (string.IsNullOrEmpty(MinimumOS) == false)
                            {
                                SupportWindowsXPIfAvailable = MinimumOS == "MSOS_XP";
                            }
                        }
                    }
                }

                // Win32 XP is only supported at this time.
                SupportWindowsXP = SupportWindowsXPIfAvailable && (GetCPPTargetPlatform(InPlatform) == CPPTargetPlatform.Win32);
            }
        }
Example #23
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, CommandLineArguments 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());
            }

            // Return the target file name to the caller
            Rules.File = TargetNameToTargetFile[TargetInfo.Name];

            // 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())
                {
                    Arguments.ApplyTo(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;
                }
            }

            // 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");
            }

            if (!Rules.bAllowNonUFSIniWhenCooked)
            {
                Rules.GlobalDefinitions.Add("DISABLE_NONUFS_INI_WHEN_COOKED=1");
            }

            if (Rules.bDisableUnverifiedCertificates)
            {
                Rules.GlobalDefinitions.Add("DISABLE_UNVERIFIED_CERTIFICATE_LOADING=1");
            }

            // Allow the platform to finalize the settings
            UEBuildPlatform Platform = UEBuildPlatform.GetBuildPlatform(Rules.Platform);

            Platform.ValidateTarget(Rules);

            // Some platforms may *require* monolithic compilation...
            if (Rules.LinkType != TargetLinkType.Monolithic && UEBuildPlatform.PlatformRequiresMonolithicBuilds(Rules.Platform, Rules.Configuration))
            {
                throw new BuildException(String.Format("{0}: {1} does not support modular builds", Rules.Name, Rules.Platform));
            }

            return(Rules);
        }
Example #24
0
        /**
         * Checks the class header files and determines if generated UObject code files are out of date in comparison.
         * @param UObjectModules	Modules that we generate headers for
         *
         * @return					True if the code files are out of date
         * */
        private static bool AreGeneratedCodeFilesOutOfDate(List <UHTModuleInfo> UObjectModules)
        {
            bool bIsOutOfDate = false;

            // Get UnrealHeaderTool timestamp. If it's newer than generated headers, they need to be rebuilt too.
            var HeaderToolTimestamp = CheckIfUnrealHeaderToolIsUpToDate();

            // 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)
            {
                // In Rocket, we skip checking timestamps for modules that don't exist within the project's directory
                if (UnrealBuildTool.RunningRocket())
                {
                    // @todo Rocket: This could be done in a better way I'm sure
                    if (!Utils.IsFileUnderDirectory(Module.ModuleDirectory, UnrealBuildTool.GetUProjectPath()))
                    {
                        // Engine or engine plugin module - Rocket does not regenerate them so don't compare their timestamps
                        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)
                {
                    // 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)
                    {
                        // 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 (SavedTimestamp.CompareTo(HeaderToolTimestamp) > 0 &&
                            SavedTimestamp.CompareTo(CoreGeneratedTimestamp) > 0)
                        {
                            // 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)
                                {
                                    for (int FileIndex = 0; FileIndex < AllUObjectHeaders.Count; ++FileIndex)
                                    {
                                        if (!UObjectFilesFromPreviousRun[FileIndex].Equals(AllUObjectHeaders[FileIndex].AbsolutePath, StringComparison.InvariantCultureIgnoreCase))
                                        {
                                            bIsOutOfDate = true;
                                            Log.TraceVerbose("UnrealHeaderTool needs to run because the set of UObject source files in module {0} has changed", Module.ModuleName);
                                            break;
                                        }
                                    }
                                }
                                else
                                {
                                    bIsOutOfDate = true;
                                    Log.TraceVerbose("UnrealHeaderTool needs to run because there are a different number of UObject source files in module {0}", Module.ModuleName);
                                }
                            }

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

                                // Has the source header changed since we last generated headers successfully?
                                if (SavedTimestamp.CompareTo(HeaderFileTimestamp) < 0)
                                {
                                    Log.TraceVerbose("UnrealHeaderTool needs to run because SavedTimestamp is older than HeaderFileTimestamp (" + HeaderFile.AbsolutePath + ") for module {0}", Module.ModuleName);
                                    bIsOutOfDate = true;
                                    break;
                                }
                            }
                        }
                        else
                        {
                            // Generated code is older 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);
                            bIsOutOfDate = true;
                        }
                    }
                    else
                    {
                        // 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);
                        bIsOutOfDate = true;
                    }
                }
                else
                {
                    // Generated code directory is missing entirely!
                    Log.TraceVerbose("UnrealHeaderTool needs to run because no generated code directory was found for module {0}", Module.ModuleName);
                    bIsOutOfDate = true;
                }

                // If even one module is out of date, we're done!  UHT does them all in one fell swoop.;
                if (bIsOutOfDate)
                {
                    break;
                }
            }

            return(bIsOutOfDate);
        }
        private bool WriteQMakePro()
        {
            // Some more stuff borrowed from Mac side of things.
            List <string> IncludeDirectories       = new List <string>();
            List <string> SystemIncludeDirectories = new List <string>();
            List <string> DefinesAndValues         = new List <string>();

            // DefineList.Add ("");

            string        QMakeIncludesFileName       = MasterProjectName + "Includes.pri";
            StringBuilder QMakeIncludesPriFileContent = new StringBuilder();

            string        QMakeDefinesFileName       = MasterProjectName + "Defines.pri";
            StringBuilder QMakeDefinesPriFileContent = new StringBuilder();

            string GameProjectPath     = "";
            string GameProjectFile     = "";
            string GameProjectRootPath = "";

            string BuildCommand = "";

            string QMakeGameProjectFile = "";

            foreach (ProjectFile CurProject in GeneratedProjectFiles)
            {
                QMakefileProjectFile QMakeProject = CurProject as QMakefileProjectFile;
                if (QMakeProject == null)
                {
                    Log.TraceInformation("QMakeProject == null");
                    continue;
                }

                foreach (string CurPath in QMakeProject.IntelliSenseIncludeSearchPaths)
                {
                    AddIncludeDirectory(ref IncludeDirectories, CurPath, Path.GetDirectoryName(QMakeProject.ProjectFilePath.FullName));
                    // System.Console.WriteLine ("Not empty now? CurPath == ", CurPath);
                }
                foreach (string CurPath in QMakeProject.IntelliSenseSystemIncludeSearchPaths)
                {
                    AddIncludeDirectory(ref SystemIncludeDirectories, CurPath, Path.GetDirectoryName(QMakeProject.ProjectFilePath.FullName));
                }
            }

            // Remove duplicate paths from include dir and system include dir list
            IncludeDirectories       = IncludeDirectories.Distinct().ToList();
            SystemIncludeDirectories = SystemIncludeDirectories.Distinct().ToList();

            // Iterate through all the defines for the projects that are generated by
            // UnrealBuildTool.exe
            // !RAKE: move to seperate function
            QMakeDefinesPriFileContent.Append("DEFINES += \\\n");
            foreach (ProjectFile CurProject in GeneratedProjectFiles)
            {
                QMakefileProjectFile QMakeProject = CurProject as QMakefileProjectFile;
                if (QMakeProject == null)
                {
                    Log.TraceInformation("QMakeProject == null");
                    continue;
                }

                foreach (string CurDefine in QMakeProject.IntelliSensePreprocessorDefinitions)
                {
                    String define = "";
                    String value  = "";

                    SplitDefinitionAndValue(CurDefine, out define, out value);

                    if (!DefinesAndValues.Contains(define))
                    {
                        // Log.TraceInformation (CurDefine);
                        if (string.IsNullOrEmpty(value))
                        {
                            DefinesAndValues.Add("\t");
                            DefinesAndValues.Add(String.Format("{0}=", define));
                            DefinesAndValues.Add(" \\\n");
                        }
                        else
                        {
                            DefinesAndValues.Add("\t");
                            DefinesAndValues.Add(define);
                            DefinesAndValues.Add("=");
                            DefinesAndValues.Add(value);
                            DefinesAndValues.Add(" \\\n");
                        }
                    }
                }
            }

            foreach (string Def in DefinesAndValues)
            {
                QMakeDefinesPriFileContent.Append(Def);
            }

            // Iterate through all the include paths that
            // UnrealBuildTool.exe generates
            // !RAKE: Move to seperate function
            QMakeIncludesPriFileContent.Append("INCLUDEPATH += \\\n");
            foreach (string CurPath in IncludeDirectories)
            {
                QMakeIncludesPriFileContent.Append("\t");
                QMakeIncludesPriFileContent.Append(CurPath);
                QMakeIncludesPriFileContent.Append(" \\\n");
            }

            foreach (string CurPath in SystemIncludeDirectories)
            {
                QMakeIncludesPriFileContent.Append("\t");
                QMakeIncludesPriFileContent.Append(CurPath);
                QMakeIncludesPriFileContent.Append(" \\\n");
            }
            QMakeIncludesPriFileContent.Append("\n");

            if (!String.IsNullOrEmpty(GameProjectName))
            {
                GameProjectPath      = OnlyGameProject.Directory.FullName;
                GameProjectFile      = OnlyGameProject.FullName;
                QMakeGameProjectFile = "gameProjectFile=" + GameProjectFile + "\n";
                BuildCommand         = "build=mono $$unrealRootPath/Engine/Binaries/DotNET/UnrealBuildTool.exe\n\n";
            }
            else
            {
                BuildCommand = "build=bash $$unrealRootPath/Engine/Build/BatchFiles/Linux/Build.sh\n";
            }

            string UnrealRootPath = UnrealBuildTool.RootDirectory.FullName;

            string FileName = MasterProjectName + ".pro";

            string QMakeSourcePriFileName = MasterProjectName + "Source.pri";
            string QMakeHeaderPriFileName = MasterProjectName + "Header.pri";
            string QMakeConfigPriFileName = MasterProjectName + "Config.pri";

            StringBuilder QMakeFileContent = new StringBuilder();

            StringBuilder QMakeSourcePriFileContent = new StringBuilder();
            StringBuilder QMakeHeaderPriFileContent = new StringBuilder();
            StringBuilder QMakeConfigPriFileContent = new StringBuilder();

            string QMakeSectionEnd = " \n\n";

            string QMakeSourceFilesList = "SOURCES += \\ \n";
            string QMakeHeaderFilesList = "HEADERS += \\ \n";
            string QMakeConfigFilesList = "OTHER_FILES += \\ \n";
            string QMakeTargetList      = "QMAKE_EXTRA_TARGETS += \\ \n";

            if (!String.IsNullOrEmpty(GameProjectName))
            {
                GameProjectRootPath = GameProjectName + "RootPath=" + GameProjectPath + "\n\n";
            }

            QMakeFileContent.Append(
                "# UnrealEngine.pro generated by QMakefileGenerator.cs\n" +
                "# *DO NOT EDIT*\n\n" +
                "TEMPLATE = aux\n" +
                "CONFIG += c++14\n" +
                "CONFIG -= console\n" +
                "CONFIG -= app_bundle\n" +
                "CONFIG -= qt\n\n" +
                "TARGET = UE4 \n\n" +
                "unrealRootPath=" + UnrealRootPath + "\n" +
                GameProjectRootPath +
                QMakeGameProjectFile +
                BuildCommand +
                "args=$(ARGS)\n\n" +
                "include(" + QMakeSourcePriFileName + ")\n" +
                "include(" + QMakeHeaderPriFileName + ")\n" +
                "include(" + QMakeConfigPriFileName + ")\n" +
                "include(" + QMakeIncludesFileName + ")\n" +
                "include(" + QMakeDefinesFileName + ")\n\n"
                );

            // Create SourceFiles, HeaderFiles, and ConfigFiles sections.
            List <FileReference> AllModuleFiles = DiscoverModules(FindGameProjects());

            foreach (FileReference CurModuleFile in AllModuleFiles)
            {
                List <FileReference> FoundFiles = SourceFileSearch.FindModuleSourceFiles(CurModuleFile);
                foreach (FileReference CurSourceFile in FoundFiles)
                {
                    string SourceFileRelativeToRoot = CurSourceFile.MakeRelativeTo(UnrealBuildTool.EngineDirectory);
                    // Exclude some directories that we don't compile (note that we still want Windows/Mac etc for code navigation)
                    if (!SourceFileRelativeToRoot.Contains("Source/ThirdParty/"))
                    {
                        if (SourceFileRelativeToRoot.EndsWith(".cpp"))
                        {
                            if (!SourceFileRelativeToRoot.StartsWith("..") && !Path.IsPathRooted(SourceFileRelativeToRoot))
                            {
                                QMakeSourceFilesList += ("\t\"" + "$$unrealRootPath/Engine/" + SourceFileRelativeToRoot + "\" \\\n");
                            }
                            else
                            {
                                if (String.IsNullOrEmpty(GameProjectName))
                                {
                                    QMakeSourceFilesList += ("\t\"" + SourceFileRelativeToRoot.Substring(3) + "\" \\\n");
                                }
                                else
                                {
                                    QMakeSourceFilesList += ("\t\"$$" + GameProjectName + "RootPath/" + Utils.MakePathRelativeTo(CurSourceFile.FullName, GameProjectPath) + "\" \\\n");
                                }
                            }
                        }
                        if (SourceFileRelativeToRoot.EndsWith(".h"))
                        {
                            if (!SourceFileRelativeToRoot.StartsWith("..") && !Path.IsPathRooted(SourceFileRelativeToRoot))
                            {
                                // SourceFileRelativeToRoot = "Engine/" + SourceFileRelativeToRoot;
                                QMakeHeaderFilesList += ("\t\"" + "$$unrealRootPath/Engine/" + SourceFileRelativeToRoot + "\" \\\n");
                            }
                            else
                            {
                                if (String.IsNullOrEmpty(GameProjectName))
                                {
                                    // SourceFileRelativeToRoot = SourceFileRelativeToRoot.Substring (3);
                                    QMakeHeaderFilesList += ("\t\"" + SourceFileRelativeToRoot.Substring(3) + "\" \\\n");
                                }
                                else
                                {
                                    QMakeHeaderFilesList += ("\t\"$$" + GameProjectName + "RootPath/" + Utils.MakePathRelativeTo(CurSourceFile.FullName, GameProjectPath) + "\" \\\n");
                                }
                            }
                        }
                        if (SourceFileRelativeToRoot.EndsWith(".cs"))
                        {
                            if (!SourceFileRelativeToRoot.StartsWith("..") && !Path.IsPathRooted(SourceFileRelativeToRoot))
                            {
                                // SourceFileRelativeToRoot = "Engine/" + SourceFileRelativeToRoot;
                                QMakeConfigFilesList += ("\t\"" + "$$unrealRootPath/Engine/" + SourceFileRelativeToRoot + "\" \\\n");
                            }
                            else
                            {
                                if (String.IsNullOrEmpty(GameProjectName))
                                {
                                    // SourceFileRelativeToRoot = SourceFileRelativeToRoot.Substring (3);
                                    QMakeConfigFilesList += ("\t\"" + SourceFileRelativeToRoot.Substring(3) + "\" \\\n");
                                }
                                else
                                {
                                    QMakeConfigFilesList += ("\t\"$$" + GameProjectName + "RootPath/" + Utils.MakePathRelativeTo(CurSourceFile.FullName, GameProjectPath) + "\" \\\n");
                                }
                            }
                        }
                    }
                }
            }

            // Add section end to section strings;
            QMakeSourceFilesList += QMakeSectionEnd;
            QMakeHeaderFilesList += QMakeSectionEnd;
            QMakeConfigFilesList += QMakeSectionEnd;

            // Append sections to the QMakeLists.txt file
            QMakeSourcePriFileContent.Append(QMakeSourceFilesList);
            QMakeHeaderPriFileContent.Append(QMakeHeaderFilesList);
            QMakeConfigPriFileContent.Append(QMakeConfigFilesList);

            string QMakeProjectCmdArg = "";

            foreach (ProjectFile Project in GeneratedProjectFiles)
            {
                foreach (ProjectTarget TargetFile in Project.ProjectTargets)
                {
                    if (TargetFile.TargetFilePath == null)
                    {
                        continue;
                    }

                    string TargetName = TargetFile.TargetFilePath.GetFileNameWithoutAnyExtensions();                                    // Remove both ".cs" and ".

                    foreach (UnrealTargetConfiguration CurConfiguration in Enum.GetValues(typeof(UnrealTargetConfiguration)))
                    {
                        if (CurConfiguration != UnrealTargetConfiguration.Unknown && CurConfiguration != UnrealTargetConfiguration.Development)
                        {
                            if (UnrealBuildTool.IsValidConfiguration(CurConfiguration))
                            {
                                if (TargetName == GameProjectName || TargetName == (GameProjectName + "Editor"))
                                {
                                    QMakeProjectCmdArg = " -project=\"\\\"$$gameProjectFile\\\"\"";
                                }
                                string ConfName = Enum.GetName(typeof(UnrealTargetConfiguration), CurConfiguration);
                                QMakeFileContent.Append(String.Format("{0}-Linux-{1}.commands = $$build {0} Linux {1} {2} $$args\n", TargetName, ConfName, QMakeProjectCmdArg));
                                QMakeTargetList += "\t" + TargetName + "-Linux-" + ConfName + " \\\n";                                 // , TargetName, ConfName);
                            }
                        }
                    }

                    if (TargetName == GameProjectName || TargetName == (GameProjectName + "Editor"))
                    {
                        QMakeProjectCmdArg = " -project=\"\\\"$$gameProjectFile\\\"\"";
                    }

                    QMakeFileContent.Append(String.Format("{0}.commands = $$build {0} Linux Development {1} $$args\n\n", TargetName, QMakeProjectCmdArg));
                    QMakeTargetList += "\t" + TargetName + " \\\n";
                }
            }

            QMakeFileContent.Append(QMakeTargetList.TrimEnd('\\'));

            string FullFileName = Path.Combine(MasterProjectPath.FullName, FileName);

            string FullQMakeDefinesFileName   = Path.Combine(MasterProjectPath.FullName, QMakeDefinesFileName);
            string FullQMakeIncludesFileName  = Path.Combine(MasterProjectPath.FullName, QMakeIncludesFileName);
            string FullQMakeSourcePriFileName = Path.Combine(MasterProjectPath.FullName, QMakeSourcePriFileName);
            string FullQMakeHeaderPriFileName = Path.Combine(MasterProjectPath.FullName, QMakeHeaderPriFileName);
            string FullQMakeConfigPriFileName = Path.Combine(MasterProjectPath.FullName, QMakeConfigPriFileName);

            WriteFileIfChanged(FullQMakeDefinesFileName, QMakeDefinesPriFileContent.ToString());
            WriteFileIfChanged(FullQMakeIncludesFileName, QMakeIncludesPriFileContent.ToString());
            WriteFileIfChanged(FullQMakeSourcePriFileName, QMakeSourcePriFileContent.ToString());

            WriteFileIfChanged(FullQMakeHeaderPriFileName, QMakeHeaderPriFileContent.ToString());
            WriteFileIfChanged(FullQMakeConfigPriFileName, QMakeConfigPriFileContent.ToString());

            return(WriteFileIfChanged(FullFileName, QMakeFileContent.ToString()));
        }
Example #26
0
        public static bool GenerateIOSPList(string ProjectDirectory, bool bIsUE4Game, string GameName, string ProjectName, string InEngineDir, string AppDirectory, UEDeployIOS InThis = null)
        {
            // generate the Info.plist for future use
            string BuildDirectory        = ProjectDirectory + "/Build/IOS";
            bool   bSkipDefaultPNGs      = false;
            string IntermediateDirectory = (bIsUE4Game ? InEngineDir : ProjectDirectory) + "/Intermediate/IOS";
            string PListFile             = IntermediateDirectory + "/" + GameName + "-Info.plist";

            ProjectName = !String.IsNullOrEmpty(ProjectName) ? ProjectName : GameName;
            VersionUtilities.BuildDirectory = BuildDirectory;
            VersionUtilities.GameName       = GameName;

            // read the old file
            string OldPListData = File.Exists(PListFile) ? File.ReadAllText(PListFile) : "";

            // determine if there is a launch.xib
            string LaunchXib = InEngineDir + "/Build/IOS/Resources/Interface/LaunchScreen.xib";

            if (File.Exists(BuildDirectory + "/Resources/Interface/LaunchScreen.xib"))
            {
                LaunchXib = BuildDirectory + "/Resources/Interface/LaunchScreen.xib";
            }

            // get the settings from the ini file
            // plist replacements
            DirectoryReference DirRef = bIsUE4Game ? (!string.IsNullOrEmpty(UnrealBuildTool.GetRemoteIniPath()) ? new DirectoryReference(UnrealBuildTool.GetRemoteIniPath()) : null) : new DirectoryReference(ProjectDirectory);
            ConfigCacheIni     Ini    = ConfigCacheIni.CreateConfigCacheIni(UnrealTargetPlatform.IOS, "Engine", DirRef);

            // orientations
            string SupportedOrientations = "";
            bool   bSupported            = true;

            Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bSupportsPortraitOrientation", out bSupported);
            SupportedOrientations += bSupported ? "\t\t<string>UIInterfaceOrientationPortrait</string>\n" : "";
            Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bSupportsUpsideDownOrientation", out bSupported);
            SupportedOrientations += bSupported ? "\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n" : "";
            Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bSupportsLandscapeLeftOrientation", out bSupported);
            SupportedOrientations += bSupported ? "\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n" : "";
            Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bSupportsLandscapeRightOrientation", out bSupported);
            SupportedOrientations += bSupported ? "\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n" : "";

            // bundle display name
            string BundleDisplayName;

            Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "BundleDisplayName", out BundleDisplayName);

            // bundle identifier
            string BundleIdentifier;

            Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "BundleIdentifier", out BundleIdentifier);

            // bundle name
            string BundleName;

            Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "BundleName", out BundleName);

            // disable https requirement
            bool bDisableHTTPS;

            Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bDisableHTTPS", out bDisableHTTPS);

            // short version string
            string BundleShortVersion;

            Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "VersionInfo", out BundleShortVersion);

            // required capabilities
            string RequiredCaps = "";

            if (InThis != null)
            {
                // required capabilities
                RequiredCaps += InThis.IOSPlatformContext.GetRequiredCapabilities();
            }

            Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bSupportsOpenGLES2", out bSupported);
            RequiredCaps += bSupported ? "\t\t<string>opengles-2</string>\n" : "";
            if (!bSupported)
            {
                Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bSupportsMetal", out bSupported);
                RequiredCaps += bSupported ? "\t\t<string>metal</string>\n" : "";
            }

            // minimum iOS version
            string MinVersion;

            if (Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "MinimumiOSVersion", out MinVersion))
            {
                switch (MinVersion)
                {
                case "IOS_61":
                    Log.TraceWarning("IOS 6 is no longer supported in UE4 as 4.11");
                    MinVersion = "7.0";
                    break;

                case "IOS_7":
                    MinVersion = "7.0";
                    break;

                case "IOS_8":
                    MinVersion = "8.0";
                    break;

                case "IOS_9":
                    MinVersion = "9.0";
                    break;
                }
            }
            else
            {
                MinVersion = "7.0";
            }

            // Get Facebook Support details
            bool bEnableFacebookSupport = true;

            Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bEnableFacebookSupport", out bEnableFacebookSupport);

            // Write the Facebook App ID if we need it.
            string FacebookAppID = "";

            Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "FacebookAppID", out FacebookAppID);
            bEnableFacebookSupport = bEnableFacebookSupport && !string.IsNullOrWhiteSpace(FacebookAppID);

            // extra plist data
            string ExtraData = "";

            Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "AdditionalPlistData", out ExtraData);

            // generate the plist file
            StringBuilder Text = new StringBuilder();

            Text.AppendLine("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
            Text.AppendLine("<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">");
            Text.AppendLine("<plist version=\"1.0\">");
            Text.AppendLine("<dict>");
            Text.AppendLine("\t<key>CFBundleURLTypes</key>");
            Text.AppendLine("\t<array>");
            Text.AppendLine("\t\t<dict>");
            Text.AppendLine("\t\t\t<key>CFBundleURLName</key>");
            Text.AppendLine("\t\t\t<string>com.Epic.Unreal</string>");
            Text.AppendLine("\t\t\t<key>CFBundleURLSchemes</key>");
            Text.AppendLine("\t\t\t<array>");
            Text.AppendLine(string.Format("\t\t\t\t<string>{0}</string>", bIsUE4Game ? "UE4Game" : GameName));
            if (bEnableFacebookSupport)
            {
                // This is needed for facebook login to redirect back to the app after completion.
                Text.AppendLine(string.Format("\t\t\t\t<string>fb{0}</string>", FacebookAppID));
            }
            Text.AppendLine("\t\t\t</array>");
            Text.AppendLine("\t\t</dict>");
            Text.AppendLine("\t</array>");
            Text.AppendLine("\t<key>CFBundleDevelopmentRegion</key>");
            Text.AppendLine("\t<string>English</string>");
            Text.AppendLine("\t<key>CFBundleDisplayName</key>");
            Text.AppendLine(string.Format("\t<string>{0}</string>", EncodeBundleName(BundleDisplayName, ProjectName)));
            Text.AppendLine("\t<key>CFBundleExecutable</key>");
            Text.AppendLine(string.Format("\t<string>{0}</string>", bIsUE4Game ? "UE4Game" : GameName));
            Text.AppendLine("\t<key>CFBundleIdentifier</key>");
            Text.AppendLine(string.Format("\t<string>{0}</string>", BundleIdentifier.Replace("[PROJECT_NAME]", ProjectName).Replace("_", "")));
            Text.AppendLine("\t<key>CFBundleInfoDictionaryVersion</key>");
            Text.AppendLine("\t<string>6.0</string>");
            Text.AppendLine("\t<key>CFBundleName</key>");
            Text.AppendLine(string.Format("\t<string>{0}</string>", EncodeBundleName(BundleName, ProjectName)));
            Text.AppendLine("\t<key>CFBundlePackageType</key>");
            Text.AppendLine("\t<string>APPL</string>");
            Text.AppendLine("\t<key>CFBundleSignature</key>");
            Text.AppendLine("\t<string>????</string>");
            Text.AppendLine("\t<key>CFBundleVersion</key>");
            Text.AppendLine(string.Format("\t<string>{0}</string>", VersionUtilities.UpdateBundleVersion(OldPListData)));
            Text.AppendLine("\t<key>CFBundleShortVersionString</key>");
            Text.AppendLine(string.Format("\t<string>{0}</string>", BundleShortVersion));
            Text.AppendLine("\t<key>LSRequiresIPhoneOS</key>");
            Text.AppendLine("\t<true/>");
            Text.AppendLine("\t<key>UIStatusBarHidden</key>");
            Text.AppendLine("\t<true/>");
            Text.AppendLine("\t<key>UIRequiresFullScreen</key>");
            Text.AppendLine("\t<true/>");
            Text.AppendLine("\t<key>UIViewControllerBasedStatusBarAppearance</key>");
            Text.AppendLine("\t<false/>");
            Text.AppendLine("\t<key>UISupportedInterfaceOrientations</key>");
            Text.AppendLine("\t<array>");
            foreach (string Line in SupportedOrientations.Split("\r\n".ToCharArray()))
            {
                if (!string.IsNullOrWhiteSpace(Line))
                {
                    Text.AppendLine(Line);
                }
            }
            Text.AppendLine("\t</array>");
            Text.AppendLine("\t<key>UIRequiredDeviceCapabilities</key>");
            Text.AppendLine("\t<array>");
            foreach (string Line in RequiredCaps.Split("\r\n".ToCharArray()))
            {
                if (!string.IsNullOrWhiteSpace(Line))
                {
                    Text.AppendLine(Line);
                }
            }
            Text.AppendLine("\t</array>");
            Text.AppendLine("\t<key>CFBundleIcons</key>");
            Text.AppendLine("\t<dict>");
            Text.AppendLine("\t\t<key>CFBundlePrimaryIcon</key>");
            Text.AppendLine("\t\t<dict>");
            Text.AppendLine("\t\t\t<key>CFBundleIconFiles</key>");
            Text.AppendLine("\t\t\t<array>");
            Text.AppendLine("\t\t\t\t<string>Icon29.png</string>");
            Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
            Text.AppendLine("\t\t\t\t<string>Icon40.png</string>");
            Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
            Text.AppendLine("\t\t\t\t<string>Icon57.png</string>");
            Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
            Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
            Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
            Text.AppendLine("\t\t\t</array>");
            Text.AppendLine("\t\t\t<key>UIPrerenderedIcon</key>");
            Text.AppendLine("\t\t\t<true/>");
            Text.AppendLine("\t\t</dict>");
            Text.AppendLine("\t</dict>");
            Text.AppendLine("\t<key>CFBundleIcons~ipad</key>");
            Text.AppendLine("\t<dict>");
            Text.AppendLine("\t\t<key>CFBundlePrimaryIcon</key>");
            Text.AppendLine("\t\t<dict>");
            Text.AppendLine("\t\t\t<key>CFBundleIconFiles</key>");
            Text.AppendLine("\t\t\t<array>");
            Text.AppendLine("\t\t\t\t<string>Icon29.png</string>");
            Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
            Text.AppendLine("\t\t\t\t<string>Icon40.png</string>");
            Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
            Text.AppendLine("\t\t\t\t<string>Icon50.png</string>");
            Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
            Text.AppendLine("\t\t\t\t<string>Icon72.png</string>");
            Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
            Text.AppendLine("\t\t\t\t<string>Icon76.png</string>");
            Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
            Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
            Text.AppendLine("\t\t\t</array>");
            Text.AppendLine("\t\t\t<key>UIPrerenderedIcon</key>");
            Text.AppendLine("\t\t\t<true/>");
            Text.AppendLine("\t\t</dict>");
            Text.AppendLine("\t</dict>");
            if (File.Exists(LaunchXib))
            {
                // TODO: compile the xib via remote tool
                Text.AppendLine("\t<key>UILaunchStoryboardName</key>");
                Text.AppendLine("\t<string>LaunchScreen</string>");
                bSkipDefaultPNGs = true;
            }
            else
            {
                // this is a temp way to inject the iphone 6 images without needing to upgrade everyone's plist
                // eventually we want to generate this based on what the user has set in the project settings
                string[] IPhoneConfigs =
                {
                    "Default-IPhone6-Landscape",     "Landscape", "{375, 667}", "8.0",
                    "Default-IPhone6",               "Portrait",  "{375, 667}", "8.0",
                    "Default-IPhone6Plus-Landscape", "Landscape", "{414, 736}", "8.0",
                    "Default-IPhone6Plus-Portrait",  "Portrait",  "{414, 736}", "8.0",
                    "Default",                       "Landscape", "{320, 480}", "7.0",
                    "Default",                       "Portrait",  "{320, 480}", "7.0",
                    "Default-568h",                  "Landscape", "{320, 568}", "7.0",
                    "Default-568h",                  "Portrait",  "{320, 568}", "7.0",
                };

                Text.AppendLine("\t<key>UILaunchImages~iphone</key>");
                Text.AppendLine("\t<array>");
                for (int ConfigIndex = 0; ConfigIndex < IPhoneConfigs.Length; ConfigIndex += 4)
                {
                    Text.AppendLine("\t\t<dict>");
                    Text.AppendLine("\t\t\t<key>UILaunchImageMinimumOSVersion</key>");
                    Text.AppendLine(string.Format("\t\t\t<string>{0}</string>", IPhoneConfigs[ConfigIndex + 3]));
                    Text.AppendLine("\t\t\t<key>UILaunchImageName</key>");
                    Text.AppendLine(string.Format("\t\t\t<string>{0}</string>", IPhoneConfigs[ConfigIndex + 0]));
                    Text.AppendLine("\t\t\t<key>UILaunchImageOrientation</key>");
                    Text.AppendLine(string.Format("\t\t\t<string>{0}</string>", IPhoneConfigs[ConfigIndex + 1]));
                    Text.AppendLine("\t\t\t<key>UILaunchImageSize</key>");
                    Text.AppendLine(string.Format("\t\t\t<string>{0}</string>", IPhoneConfigs[ConfigIndex + 2]));
                    Text.AppendLine("\t\t</dict>");
                }

                // close it out
                Text.AppendLine("\t</array>");

                // this is a temp way to inject the iPad Pro without needing to upgrade everyone's plist
                // eventually we want to generate this based on what the user has set in the project settings
                string[] IPadConfigs =
                {
                    "Default-Landscape",      "Landscape", "{768, 1024}",  "7.0",
                    "Default-Portrait",       "Portrait",  "{768, 1024}",  "7.0",
                    "Default-Landscape-1336", "Landscape", "{1024, 1366}", "9.0",
                    "Default-Portrait-1336",  "Portrait",  "{1024, 1366}", "9.0",
                };

                Text.AppendLine("\t<key>UILaunchImages~ipad</key>");
                Text.AppendLine("\t<array>");
                for (int ConfigIndex = 0; ConfigIndex < IPadConfigs.Length; ConfigIndex += 4)
                {
                    Text.AppendLine("\t\t<dict>");
                    Text.AppendLine("\t\t\t<key>UILaunchImageMinimumOSVersion</key>");
                    Text.AppendLine(string.Format("\t\t\t<string>{0}</string>", IPhoneConfigs[ConfigIndex + 3]));
                    Text.AppendLine("\t\t\t<key>UILaunchImageName</key>");
                    Text.AppendLine(string.Format("\t\t\t<string>{0}</string>", IPhoneConfigs[ConfigIndex + 0]));
                    Text.AppendLine("\t\t\t<key>UILaunchImageOrientation</key>");
                    Text.AppendLine(string.Format("\t\t\t<string>{0}</string>", IPhoneConfigs[ConfigIndex + 1]));
                    Text.AppendLine("\t\t\t<key>UILaunchImageSize</key>");
                    Text.AppendLine(string.Format("\t\t\t<string>{0}</string>", IPhoneConfigs[ConfigIndex + 2]));
                    Text.AppendLine("\t\t</dict>");
                }
                Text.AppendLine("\t</array>");
            }
            Text.AppendLine("\t<key>CFBundleSupportedPlatforms</key>");
            Text.AppendLine("\t<array>");
            Text.AppendLine("\t\t<string>iPhoneOS</string>");
            Text.AppendLine("\t</array>");
            Text.AppendLine("\t<key>MinimumOSVersion</key>");
            Text.AppendLine(string.Format("\t<string>{0}</string>", MinVersion));
            // disable exempt encryption
            Text.AppendLine("\t<key>ITSAppUsesNonExemptEncryption</key>");
            Text.AppendLine("\t<false/>");

            // disable HTTPS requirement
            if (bDisableHTTPS)
            {
                Text.AppendLine("\t<key>NSAppTransportSecurity</key>");
                Text.AppendLine("\t\t<dict>");
                Text.AppendLine("\t\t\t<key>NSAllowsArbitraryLoads</key><true/>");
                Text.AppendLine("\t\t</dict>");
            }

            if (bEnableFacebookSupport)
            {
                Text.AppendLine("\t<key>FacebookAppID</key>");
                Text.AppendLine(string.Format("\t<string>{0}</string>", FacebookAppID));
            }
            if (!string.IsNullOrEmpty(ExtraData))
            {
                ExtraData = ExtraData.Replace("\\n", "\n");
                foreach (string Line in ExtraData.Split("\r\n".ToCharArray()))
                {
                    if (!string.IsNullOrWhiteSpace(Line))
                    {
                        Text.AppendLine("\t" + Line);
                    }
                }
            }
            Text.AppendLine("</dict>");
            Text.AppendLine("</plist>");

            // Create the intermediate directory if needed
            if (!Directory.Exists(IntermediateDirectory))
            {
                Directory.CreateDirectory(IntermediateDirectory);
            }

            if (InThis != null && InThis.UPL != null)
            {
                // Allow UPL to modify the plist here
                XDocument XDoc;
                try
                {
                    XDoc = XDocument.Parse(Text.ToString());
                }
                catch (Exception e)
                {
                    throw new BuildException("plist is invalid {0}\n{1}", e, Text.ToString());
                }

                XDoc.DocumentType.InternalSubset = "";
                InThis.UPL.ProcessPluginNode("None", "iosPListUpdates", "", ref XDoc);
                string result = XDoc.Declaration.ToString() + "\n" + XDoc.ToString().Replace("<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"[]>", "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">");
                File.WriteAllText(PListFile, result);
            }
            else
            {
                File.WriteAllText(PListFile, Text.ToString());
            }

            if (BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac)
            {
                if (!Directory.Exists(AppDirectory))
                {
                    Directory.CreateDirectory(AppDirectory);
                }
                File.WriteAllText(AppDirectory + "/Info.plist", Text.ToString());
            }

            return(bSkipDefaultPNGs);
        }
Example #27
0
        static public string GetNdkApiLevel()
        {
            // ask the .ini system for what version to use
            ConfigCacheIni Ini = new ConfigCacheIni(UnrealTargetPlatform.Android, "Engine", UnrealBuildTool.GetUProjectPath());
            string         NDKLevel;

            Ini.GetString("/Script/AndroidPlatformEditor.AndroidSDKSettings", "NDKAPILevel", out NDKLevel);

            if (NDKLevel == "latest")
            {
                // get a list of NDK platforms
                string PlatformsDir = Environment.ExpandEnvironmentVariables("%NDKROOT%/platforms");
                if (!Directory.Exists(PlatformsDir))
                {
                    throw new BuildException("No platforms found in {0}", PlatformsDir);
                }

                // return the largest of them
                NDKLevel = GetLargestApiLevel(Directory.GetDirectories(PlatformsDir));
            }

            return(NDKLevel);
        }
Example #28
0
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="ProjectFile">Project to read settings from</param>
        public RemoteMac(FileReference ProjectFile)
        {
            this.RsyncExe         = FileReference.Combine(UnrealBuildTool.EngineDirectory, "Extras", "ThirdPartyNotUE", "DeltaCopy", "Binaries", "Rsync.exe");
            this.SshExe           = FileReference.Combine(UnrealBuildTool.EngineDirectory, "Extras", "ThirdPartyNotUE", "DeltaCopy", "Binaries", "Ssh.exe");
            this.ProjectFile      = ProjectFile;
            this.ProjectDirectory = DirectoryReference.FromFile(ProjectFile);

            // Apply settings from the XML file
            XmlConfig.ApplyTo(this);

            // Get the project config file path
            DirectoryReference EngineIniPath = ProjectFile != null ? ProjectFile.Directory : null;

            if (EngineIniPath == null && UnrealBuildTool.GetRemoteIniPath() != null)
            {
                EngineIniPath = new DirectoryReference(UnrealBuildTool.GetRemoteIniPath());
            }
            ConfigHierarchy Ini = ConfigCache.ReadHierarchy(ConfigHierarchyType.Engine, EngineIniPath, UnrealTargetPlatform.IOS);

            // Read the project settings if we don't have anything in the build configuration settings
            if (String.IsNullOrEmpty(ServerName))
            {
                // Read the server name
                string IniServerName;
                if (Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "RemoteServerName", out IniServerName) && !String.IsNullOrEmpty(IniServerName))
                {
                    this.ServerName = IniServerName;
                }
                else
                {
                    throw new BuildException("Remote compiling requires a server name. Use the editor (Project Settings > IOS) to set up your remote compilation settings.");
                }

                // Parse the username
                string IniUserName;
                if (Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "RSyncUsername", out IniUserName) && !String.IsNullOrEmpty(IniUserName))
                {
                    this.UserName = IniUserName;
                }
            }

            // Split port out from the server name
            int PortIdx = ServerName.LastIndexOf(':');

            if (PortIdx != -1)
            {
                string Port = ServerName.Substring(PortIdx + 1);
                if (!int.TryParse(Port, out ServerPort))
                {
                    throw new BuildException("Unable to parse port number from '{0}'", ServerName);
                }
                ServerName = ServerName.Substring(0, PortIdx);
            }

            // If a user name is not set, use the current user
            if (String.IsNullOrEmpty(UserName))
            {
                UserName = Environment.UserName;
            }

            // Print out the server info
            Log.TraceInformation("[Remote] Using remote server '{0}' on port {1} (user '{2}')", ServerName, ServerPort, UserName);

            // Get the path to the SSH private key
            string OverrideSshPrivateKeyPath;

            if (Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "SSHPrivateKeyOverridePath", out OverrideSshPrivateKeyPath) && !String.IsNullOrEmpty(OverrideSshPrivateKeyPath))
            {
                SshPrivateKey = new FileReference(OverrideSshPrivateKeyPath);
                if (!FileReference.Exists(SshPrivateKey))
                {
                    throw new BuildException("SSH private key specified in config file ({0}) does not exist.", SshPrivateKey);
                }
            }

            // If it's not set, look in the standard locations. If that fails, spawn the batch file to generate one.
            if (SshPrivateKey == null && !TryGetSshPrivateKey(out SshPrivateKey))
            {
                Log.TraceWarning("No SSH private key found for {0}@{1}. Launching SSH to generate one.", UserName, ServerName);

                StringBuilder CommandLine = new StringBuilder();
                CommandLine.AppendFormat("/C \"\"{0}\"", FileReference.Combine(UnrealBuildTool.EngineDirectory, "Build", "BatchFiles", "MakeAndInstallSSHKey.bat"));
                CommandLine.AppendFormat(" \"{0}\"", SshExe);
                CommandLine.AppendFormat(" \"{0}\"", ServerPort);
                CommandLine.AppendFormat(" \"{0}\"", RsyncExe);
                CommandLine.AppendFormat(" \"{0}\"", UserName);
                CommandLine.AppendFormat(" \"{0}\"", ServerName);
                CommandLine.AppendFormat(" \"{0}\"", DirectoryReference.GetSpecialFolder(Environment.SpecialFolder.MyDocuments));
                CommandLine.AppendFormat(" \"{0}\"", GetLocalCygwinPath(DirectoryReference.GetSpecialFolder(Environment.SpecialFolder.MyDocuments)));
                CommandLine.AppendFormat(" \"{0}\"", UnrealBuildTool.EngineDirectory);
                CommandLine.Append("\"");

                using (Process ChildProcess = Process.Start("C:\\Windows\\System32\\Cmd.exe", CommandLine.ToString()))
                {
                    ChildProcess.WaitForExit();
                }

                if (!TryGetSshPrivateKey(out SshPrivateKey))
                {
                    throw new BuildException("Failed to generate SSH private key for {0}@{1}.", UserName, ServerName);
                }
            }

            // resolve the rest of the strings
            RsyncAuthentication = ExpandVariables(RsyncAuthentication);
            SshAuthentication   = ExpandVariables(SshAuthentication);

            // Build a list of arguments for SSH
            CommonSshArguments = new List <string>();
            CommonSshArguments.Add("-o BatchMode=yes");
            CommonSshArguments.Add(SshAuthentication);
            CommonSshArguments.Add(String.Format("-p {0}", ServerPort));
            CommonSshArguments.Add(String.Format("\"{0}@{1}\"", UserName, ServerName));

            // Build a list of arguments for Rsync
            BasicRsyncArguments = new List <string>();
            BasicRsyncArguments.Add("--compress");
            BasicRsyncArguments.Add("--verbose");
            BasicRsyncArguments.Add(String.Format("--rsh=\"{0} -p {1}\"", RsyncAuthentication, ServerPort));
            BasicRsyncArguments.Add("--chmod=ug=rwX,o=rxX");

            // Build a list of arguments for Rsync filters
            CommonRsyncArguments = new List <string>(BasicRsyncArguments);
            CommonRsyncArguments.Add("--recursive");
            CommonRsyncArguments.Add("--delete");            // Delete anything not in the source directory
            CommonRsyncArguments.Add("--delete-excluded");   // Delete anything not in the source directory
            CommonRsyncArguments.Add("--times");             // Preserve modification times
            CommonRsyncArguments.Add("--prune-empty-dirs");  // Remove empty directories from the file list

            // Get the remote base directory
            StringBuilder Output;

            if (ExecuteAndCaptureOutput("'echo ~'", out Output) != 0)
            {
                throw new BuildException("Unable to determine home directory for remote user");
            }
            RemoteBaseDir = String.Format("{0}/UE4/Builds/{1}", Output.ToString().Trim().TrimEnd('/'), Environment.MachineName);
            Log.TraceInformation("[Remote] Using base directory '{0}'", RemoteBaseDir);

            // Build the list of directory mappings between the local and remote machines
            Mappings = new List <RemoteMapping>();
            Mappings.Add(new RemoteMapping(UnrealBuildTool.EngineDirectory, GetRemotePath(UnrealBuildTool.EngineDirectory)));
            if (ProjectFile != null && !ProjectFile.IsUnderDirectory(UnrealBuildTool.EngineDirectory))
            {
                Mappings.Add(new RemoteMapping(ProjectFile.Directory, GetRemotePath(ProjectFile.Directory)));
            }
        }
Example #29
0
        public static void ParseArchitectures()
        {
            // look in ini settings for what platforms to compile for
            ConfigCacheIni Ini           = new ConfigCacheIni(UnrealTargetPlatform.Android, "Engine", UnrealBuildTool.GetUProjectPath());
            List <string>  ProjectArches = new List <string>();
            bool           bBuild        = true;

            if (Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bBuildForArmV7", out bBuild) && bBuild)
            {
                ProjectArches.Add("-armv7");
            }
            if (Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bBuildForArm64", out bBuild) && bBuild)
            {
                ProjectArches.Add("-arm64");
            }
            if (Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bBuildForx86", out bBuild) && bBuild)
            {
                ProjectArches.Add("-x86");
            }
            if (Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bBuildForx8664", out bBuild) && bBuild)
            {
                ProjectArches.Add("-x64");
            }

            // force armv7 if something went wrong
            if (ProjectArches.Count == 0)
            {
                ProjectArches.Add("-armv7");
            }

            Arches = ProjectArches.ToArray();

            // Parse selected GPU architectures
            List <string> ProjectGPUArches = new List <string>();

            if (Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bBuildForES2", out bBuild) && bBuild)
            {
                ProjectGPUArches.Add("-es2");
            }
            if (Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bBuildForES31", out bBuild) && bBuild)
            {
                ProjectGPUArches.Add("-es31");
            }
            if (Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bBuildForGL4", out bBuild) && bBuild)
            {
                ProjectGPUArches.Add("-gl4");
            }
            if (ProjectGPUArches.Count == 0)
            {
                ProjectGPUArches.Add("-es2");
            }
            GPUArchitectures = ProjectGPUArches.ToArray();

            List <string> FullArchCombinations = new List <string>();

            foreach (string Arch in Arches)
            {
                foreach (string GPUArch in GPUArchitectures)
                {
                    FullArchCombinations.Add(Arch + GPUArch);
                }
            }
            AllComboNames = FullArchCombinations.ToArray();
        }
Example #30
0
        /**
         * Checks the class header files and determines if generated UObject code files are out of date in comparison.
         * @param UObjectModules	Modules that we generate headers for
         *
         * @return					True if the code files are out of date
         * */
        private static bool AreGeneratedCodeFilesOutOfDate(List <UHTModuleInfo> UObjectModules)
        {
            bool bIsOutOfDate = false;

            // Get UnrealHeaderTool timestamp. If it's newer than generated headers, they need to be rebuilt too.
            var HeaderToolTimestamp = CheckIfUnrealHeaderToolIsUpToDate();

            // 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)
            {
                // In Rocket, we skip checking timestamps for modules that don't exist within the project's directory
                if (UnrealBuildTool.RunningRocket())
                {
                    // @todo Rocket: This could be done in a better way I'm sure
                    if (!Utils.IsFileUnderDirectory(Module.ModuleDirectory, UnrealBuildTool.GetUProjectPath()))
                    {
                        // Engine or engine plugin module - Rocket does not regenerate them so don't compare their timestamps
                        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)
                {
                    // Grab our special "Timestamp" file that we saved after the last set of headers were generated
                    string TimestampFile          = Path.Combine(GeneratedCodeDirectory, @"Timestamp");
                    var    SavedTimestampFileInfo = (FileSystemInfo) new FileInfo(TimestampFile);
                    if (SavedTimestampFileInfo.Exists)
                    {
                        // 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 (SavedTimestamp.CompareTo(HeaderToolTimestamp) > 0 &&
                            SavedTimestamp.CompareTo(CoreGeneratedTimestamp) > 0)
                        {
                            // 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);
                            foreach (var HeaderFile in AllUObjectHeaders)
                            {
                                var HeaderFileTimestamp = HeaderFile.Info.LastWriteTime;

                                // Has the source header changed since we last generated headers successfully?
                                if (SavedTimestamp.CompareTo(HeaderFileTimestamp) < 0)
                                {
                                    bIsOutOfDate = true;
                                    break;
                                }

                                // 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 (SavedTimestamp.CompareTo(HeaderDirectoryTimestamp) < 0)
                                    {
                                        bIsOutOfDate = true;
                                        break;
                                    }
                                }
                            }
                        }
                        else
                        {
                            // Generated code is older UnrealHeaderTool.exe or CoreUObject headers.  Out of date!
                            bIsOutOfDate = true;
                        }
                    }
                    else
                    {
                        // Timestamp file was missing (possibly deleted/cleaned), so headers are out of date
                        bIsOutOfDate = true;
                    }
                }
                else
                {
                    // Generated code directory is missing entirely!
                    bIsOutOfDate = true;
                }

                // If even one module is out of date, we're done!  UHT does them all in one fell swoop.;
                if (bIsOutOfDate)
                {
                    break;
                }
            }

            return(bIsOutOfDate);
        }
Example #31
0
        private bool WriteQMakePro()
        {
            string GameProjectPath     = "";
            string GameProjectFile     = "";
            string GameProjectRootPath = "";

            string BuildCommand = "";

            string QMakeGameProjectFile = "";

            if (!String.IsNullOrEmpty(GameProjectName))
            {
                GameProjectPath      = UnrealBuildTool.GetUProjectPath();
                GameProjectFile      = UnrealBuildTool.GetUProjectFile();
                QMakeGameProjectFile = "gameProjectFile=" + GameProjectFile + "\n";
                BuildCommand         = "build=mono $$unrealRootPath/Engine/Binaries/DotNET/UnrealBuildTool.exe\n\n";
            }
            else
            {
                BuildCommand = "build=bash $$unrealRootPath/Engine/Build/BatchFiles/Linux/Build.sh\n";
            }

            var UnrealRootPath = Path.GetFullPath(ProjectFileGenerator.RootRelativePath);

            var FileName         = MasterProjectName + ".pro";
            var QMakeFileContent = new StringBuilder();

            var QMakeSectionEnd = " \n\n";

            var QMakeSourceFilesList = "SOURCES += \\ \n";
            var QMakeHeaderFilesList = "HEADERS += \\ \n";
            var QMakeConfigFilesList = "OTHER_FILES += \\ \n";
            var QMakeTargetList      = "QMAKE_EXTRA_TARGETS += \\ \n";

            if (!String.IsNullOrEmpty(GameProjectName))
            {
                GameProjectRootPath = GameProjectName + "RootPath=" + GameProjectPath + "\n\n";
            }

            QMakeFileContent.Append(
                "# UnrealEngine.pro generated by QMakefileGenerator.cs\n" +
                "# *DO NOT EDIT*\n\n" +
                "TEMPLATE = aux\n" +
                "CONFIG -= console\n" +
                "CONFIG -= app_bundle\n" +
                "CONFIG -= qt\n\n" +
                "TARGET = UE4 \n\n" +
                "unrealRootPath=" + UnrealRootPath + "\n" +
                GameProjectRootPath +
                QMakeGameProjectFile +
                BuildCommand +
                "args=$(ARGS)\n\n"
                );

            // Create SourceFiles, HeaderFiles, and ConfigFiles sections.
            var AllModuleFiles = DiscoverModules();

            foreach (string CurModuleFile in AllModuleFiles)
            {
                var FoundFiles = SourceFileSearch.FindModuleSourceFiles(CurModuleFile, ExcludeNoRedistFiles: bExcludeNoRedistFiles);
                foreach (string CurSourceFile in FoundFiles)
                {
                    string SourceFileRelativeToRoot = Utils.MakePathRelativeTo(CurSourceFile, Path.Combine(EngineRelativePath));
                    // Exclude Windows, Mac, and iOS only files/folders.
                    // This got ugly quick.
                    if (!SourceFileRelativeToRoot.Contains("Source/ThirdParty/") &&
                        !SourceFileRelativeToRoot.Contains("/Windows/") &&
                        !SourceFileRelativeToRoot.Contains("/Mac/") &&
                        !SourceFileRelativeToRoot.Contains("/IOS/") &&
                        !SourceFileRelativeToRoot.Contains("/iOS/") &&
                        !SourceFileRelativeToRoot.Contains("/VisualStudioSourceCodeAccess/") &&
                        !SourceFileRelativeToRoot.Contains("/XCodeSourceCodeAccess/") &&
                        !SourceFileRelativeToRoot.Contains("/WmfMedia/") &&
                        !SourceFileRelativeToRoot.Contains("/IOSDeviceProfileSelector/") &&
                        !SourceFileRelativeToRoot.Contains("/WindowsDeviceProfileSelector/") &&
                        !SourceFileRelativeToRoot.Contains("/WindowsMoviePlayer/") &&
                        !SourceFileRelativeToRoot.Contains("/AppleMoviePlayer/") &&
                        !SourceFileRelativeToRoot.Contains("/MacGraphicsSwitching/") &&
                        !SourceFileRelativeToRoot.Contains("/Apple/") &&
                        !SourceFileRelativeToRoot.Contains("/WinRT/")
                        )
                    {
                        if (SourceFileRelativeToRoot.EndsWith(".cpp"))
                        {
                            if (!SourceFileRelativeToRoot.StartsWith("..") && !Path.IsPathRooted(SourceFileRelativeToRoot))
                            {
                                // SourceFileRelativeToRoot = "Engine/" + SourceFileRelativeToRoot;
                                QMakeSourceFilesList += ("\t\"" + "$$unrealRootPath/Engine/" + SourceFileRelativeToRoot + "\" \\\n");
                            }
                            else
                            {
                                if (String.IsNullOrEmpty(GameProjectName))
                                {
                                    // SourceFileRelativeToRoot = SourceFileRelativeToRoot.Substring (3);
                                    QMakeSourceFilesList += ("\t\"" + SourceFileRelativeToRoot.Substring(3) + "\" \\\n");
                                }
                                else if (!String.IsNullOrEmpty(GameProjectName))
                                {
                                    QMakeSourceFilesList += ("\t\"$$" + GameProjectName + "RootPath/" + Utils.MakePathRelativeTo(CurSourceFile, GameProjectPath) + "\" \\\n");
                                }
                                else
                                {
                                    System.Console.WriteLine("Error!, you should not be here.");
                                }
                            }
                        }
                        if (SourceFileRelativeToRoot.EndsWith(".h"))
                        {
                            if (!SourceFileRelativeToRoot.StartsWith("..") && !Path.IsPathRooted(SourceFileRelativeToRoot))
                            {
                                // SourceFileRelativeToRoot = "Engine/" + SourceFileRelativeToRoot;
                                QMakeHeaderFilesList += ("\t\"" + "$$unrealRootPath/Engine/" + SourceFileRelativeToRoot + "\" \\\n");
                            }
                            else
                            {
                                if (String.IsNullOrEmpty(GameProjectName))
                                {
                                    // SourceFileRelativeToRoot = SourceFileRelativeToRoot.Substring (3);
                                    QMakeHeaderFilesList += ("\t\"" + SourceFileRelativeToRoot.Substring(3) + "\" \\\n");
                                }
                                else if (!String.IsNullOrEmpty(GameProjectName))
                                {
                                    QMakeHeaderFilesList += ("\t\"$$" + GameProjectName + "RootPath/" + Utils.MakePathRelativeTo(CurSourceFile, GameProjectPath) + "\" \\\n");
                                }
                                else
                                {
                                    System.Console.WriteLine("Error!, you should not be here.");
                                }
                            }
                        }
                        if (SourceFileRelativeToRoot.EndsWith(".cs"))
                        {
                            if (!SourceFileRelativeToRoot.StartsWith("..") && !Path.IsPathRooted(SourceFileRelativeToRoot))
                            {
                                // SourceFileRelativeToRoot = "Engine/" + SourceFileRelativeToRoot;
                                QMakeConfigFilesList += ("\t\"" + "$$unrealRootPath/Engine/" + SourceFileRelativeToRoot + "\" \\\n");
                            }
                            else
                            {
                                if (String.IsNullOrEmpty(GameProjectName))
                                {
                                    // SourceFileRelativeToRoot = SourceFileRelativeToRoot.Substring (3);
                                    QMakeConfigFilesList += ("\t\"" + SourceFileRelativeToRoot.Substring(3) + "\" \\\n");
                                }
                                else if (!String.IsNullOrEmpty(GameProjectName))
                                {
                                    QMakeConfigFilesList += ("\t\"$$" + GameProjectName + "RootPath/" + Utils.MakePathRelativeTo(CurSourceFile, GameProjectPath) + "\" \\\n");
                                }
                                else
                                {
                                    System.Console.WriteLine("Error!, you should not be here.");
                                }
                            }
                        }
                    }
                }
            }

            // Add section end to section strings;
            QMakeSourceFilesList += QMakeSectionEnd;
            QMakeHeaderFilesList += QMakeSectionEnd;
            QMakeConfigFilesList += QMakeSectionEnd;

            // Append sections to the QMakeLists.txt file
            QMakeFileContent.Append(QMakeSourceFilesList);
            QMakeFileContent.Append(QMakeHeaderFilesList);
            QMakeFileContent.Append(QMakeConfigFilesList);

            string QMakeProjectCmdArg = "";

            foreach (string TargetFilePath in DiscoverTargets())
            {
                var TargetName = Utils.GetFilenameWithoutAnyExtensions(TargetFilePath);                         // Remove both ".cs" and ".

                foreach (UnrealTargetConfiguration CurConfiguration in Enum.GetValues(typeof(UnrealTargetConfiguration)))
                {
                    if (CurConfiguration != UnrealTargetConfiguration.Unknown && CurConfiguration != UnrealTargetConfiguration.Development)
                    {
                        if (UnrealBuildTool.IsValidConfiguration(CurConfiguration))
                        {
                            if (TargetName == GameProjectName || TargetName == (GameProjectName + "Editor"))
                            {
                                QMakeProjectCmdArg = " -project=\"\\\"$$gameProjectFile\\\"\"";
                            }
                            var ConfName = Enum.GetName(typeof(UnrealTargetConfiguration), CurConfiguration);
                            QMakeFileContent.Append(String.Format("{0}-Linux-{1}.commands = $$build {2} {0} Linux {1} $$args\n", TargetName, ConfName, QMakeProjectCmdArg));
                            QMakeTargetList += "\t" + TargetName + "-Linux-" + ConfName + " \\\n";                             // , TargetName, ConfName);
                        }
                    }
                }

                if (TargetName == GameProjectName || TargetName == (GameProjectName + "Editor"))
                {
                    QMakeProjectCmdArg = " -project=\"\\\"$$gameProjectFile\\\"\"";
                }

                QMakeFileContent.Append(String.Format("{0}.commands = $$build {1} {0} Linux Development $$args\n\n", TargetName, QMakeProjectCmdArg));
                QMakeTargetList += "\t" + TargetName + " \\\n";
            }

            QMakeFileContent.Append(QMakeTargetList.TrimEnd('\\'));

            var FullFileName = Path.Combine(MasterProjectRelativePath, FileName);

            return(WriteFileIfChanged(FullFileName, QMakeFileContent.ToString()));
        }
	public static UE4Build.BuildAgenda MakeAgenda(UnrealBuildTool.UnrealTargetPlatform[] Platforms, List<string> ExtraBuildProducts)
	{
		// Create the build agenda
		UE4Build.BuildAgenda Agenda = new UE4Build.BuildAgenda();
		
		// C# binaries
		Agenda.SwarmProject = @"Engine\Source\Programs\UnrealSwarm\UnrealSwarm.sln";
		Agenda.DotNetProjects.Add(@"Engine/Source/Editor/SwarmInterface/DotNET/SwarmInterface.csproj");
		Agenda.DotNetProjects.Add(@"Engine/Source/Programs/DotNETCommon/DotNETUtilities/DotNETUtilities.csproj");
		Agenda.DotNetProjects.Add(@"Engine/Source/Programs/RPCUtility/RPCUtility.csproj");
		Agenda.DotNetProjects.Add(@"Engine/Source/Programs/UnrealControls/UnrealControls.csproj");

		// Windows binaries
		if(Platforms.Contains(UnrealBuildTool.UnrealTargetPlatform.Win64))
		{
			Agenda.AddTarget("CrashReportClient", UnrealBuildTool.UnrealTargetPlatform.Win64, UnrealBuildTool.UnrealTargetConfiguration.Development);
			Agenda.AddTarget("CrashReportClient", UnrealBuildTool.UnrealTargetPlatform.Win32, UnrealBuildTool.UnrealTargetConfiguration.Development);
			Agenda.AddTarget("UnrealHeaderTool", UnrealBuildTool.UnrealTargetPlatform.Win64, UnrealBuildTool.UnrealTargetConfiguration.Development);
			Agenda.AddTarget("UnrealPak", UnrealBuildTool.UnrealTargetPlatform.Win64, UnrealBuildTool.UnrealTargetConfiguration.Development);
			Agenda.AddTarget("UnrealLightmass", UnrealBuildTool.UnrealTargetPlatform.Win64, UnrealBuildTool.UnrealTargetConfiguration.Development);
			Agenda.AddTarget("ShaderCompileWorker", UnrealBuildTool.UnrealTargetPlatform.Win64, UnrealBuildTool.UnrealTargetConfiguration.Development);
			Agenda.AddTarget("UnrealVersionSelector", UnrealBuildTool.UnrealTargetPlatform.Win64, UnrealBuildTool.UnrealTargetConfiguration.Shipping);
			Agenda.AddTarget("BootstrapPackagedGame", UnrealBuildTool.UnrealTargetPlatform.Win64, UnrealBuildTool.UnrealTargetConfiguration.Shipping);
			Agenda.AddTarget("BootstrapPackagedGame", UnrealBuildTool.UnrealTargetPlatform.Win32, UnrealBuildTool.UnrealTargetConfiguration.Shipping);
			Agenda.AddTarget("UnrealCEFSubProcess", UnrealBuildTool.UnrealTargetPlatform.Win64, UnrealBuildTool.UnrealTargetConfiguration.Development);
			Agenda.AddTarget("UnrealCEFSubProcess", UnrealBuildTool.UnrealTargetPlatform.Win32, UnrealBuildTool.UnrealTargetConfiguration.Development);
		}

		// Mac binaries
		if(Platforms.Contains(UnrealBuildTool.UnrealTargetPlatform.Mac))
		{
			Agenda.AddTarget("CrashReportClient", UnrealBuildTool.UnrealTargetPlatform.Mac, UnrealBuildTool.UnrealTargetConfiguration.Development, InAddArgs: "-CopyAppBundleBackToDevice");
			Agenda.AddTarget("UnrealPak", UnrealBuildTool.UnrealTargetPlatform.Mac, UnrealBuildTool.UnrealTargetConfiguration.Development, InAddArgs: "-CopyAppBundleBackToDevice");
			Agenda.AddTarget("UnrealLightmass", UnrealBuildTool.UnrealTargetPlatform.Mac, UnrealBuildTool.UnrealTargetConfiguration.Development, InAddArgs: "-CopyAppBundleBackToDevice");
			Agenda.AddTarget("ShaderCompileWorker", UnrealBuildTool.UnrealTargetPlatform.Mac, UnrealBuildTool.UnrealTargetConfiguration.Development, InAddArgs: "-CopyAppBundleBackToDevice");
			Agenda.AddTarget("UE4EditorServices", UnrealBuildTool.UnrealTargetPlatform.Mac, UnrealBuildTool.UnrealTargetConfiguration.Development, InAddArgs: "-CopyAppBundleBackToDevice");
			Agenda.AddTarget("UnrealCEFSubProcess", UnrealBuildTool.UnrealTargetPlatform.Mac, UnrealBuildTool.UnrealTargetConfiguration.Development, InAddArgs: "-CopyAppBundleBackToDevice");
		}

		// iOS binaries
		if(Platforms.Contains(UnrealBuildTool.UnrealTargetPlatform.IOS))
		{
			Agenda.DotNetProjects.Add(@"Engine/Source/Programs/iOS/iPhonePackager/iPhonePackager.csproj");
			ExtraBuildProducts.Add(CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, @"Engine/Binaries/DotNET/iOS/iPhonePackager.exe"));

			Agenda.DotNetProjects.Add(@"Engine/Source/Programs/iOS/DeploymentServer/DeploymentServer.csproj");
			ExtraBuildProducts.Add(CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, @"Engine/Binaries/DotNET/iOS/DeploymentServer.exe"));
	
			Agenda.DotNetProjects.Add(@"Engine/Source/Programs/iOS/DeploymentInterface/DeploymentInterface.csproj");
			ExtraBuildProducts.Add(CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, @"Engine/Binaries/DotNET/iOS/DeploymentInterface.dll"));
			
			Agenda.DotNetProjects.Add(@"Engine/Source/Programs/iOS/MobileDeviceInterface/MobileDeviceInterface.csproj");
			ExtraBuildProducts.Add(CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, @"Engine/Binaries/DotNET/iOS/MobileDeviceInterface.dll"));
		}

		// PS4 binaries
		if(Platforms.Contains(UnrealBuildTool.UnrealTargetPlatform.PS4))
		{
			Agenda.AddTarget("PS4MapFileUtil", UnrealBuildTool.UnrealTargetPlatform.Win64, UnrealBuildTool.UnrealTargetConfiguration.Development);

			Agenda.DotNetProjects.Add(CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, @"Engine/Source/Programs/PS4/PS4DevKitUtil/PS4DevKitUtil.csproj"));
			ExtraBuildProducts.Add(CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, @"Engine/Binaries/DotNET/PS4/PS4DevKitUtil.exe"));
		}
		
		// Xbox One binaries
		if(Platforms.Contains(UnrealBuildTool.UnrealTargetPlatform.XboxOne))
		{
			Agenda.AddTarget("XboxOnePDBFileUtil", UnrealBuildTool.UnrealTargetPlatform.Win64, UnrealBuildTool.UnrealTargetConfiguration.Development);
		}

		// HTML5 binaries
		if (Platforms.Contains(UnrealBuildTool.UnrealTargetPlatform.HTML5))
		{
			Agenda.DotNetProjects.Add(@"Engine/Source/Programs/HTML5/HTML5LaunchHelper/HTML5LaunchHelper.csproj");
			ExtraBuildProducts.Add(CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, @"Engine/Binaries/DotNET/HTML5LaunchHelper.exe"));
		}
		
		return Agenda;
	}
Example #33
0
        /// <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)
        {
            FileInfo MakefileInfo;

            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
                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, MakefileInfo.LastWriteTimeUtc);
                    }
                }
                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 any config settings have changed. Ini files contain build settings too.
                if (!Makefile.ConfigValueTracker.IsValid())
                {
                    ReasonNotLoaded = "config setting changed";
                    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);
        }
Example #34
0
		public bool CanUseXGE(UnrealBuildTool.UnrealTargetPlatform Platform)
		{
			if (!UnrealBuildTool.UEBuildPlatform.IsPlatformAvailable(Platform))
			{
				return false;
			}

			return UnrealBuildTool.UEBuildPlatform.GetBuildPlatform(Platform).CanUseXGE();
		}
Example #35
0
        /// <summary>
        /// Given a set of C++ files, generates another set of C++ files that #include all the original
        /// files, the goal being to compile the same code in fewer translation units.
        /// The "unity" files are written to the CompileEnvironment's OutputDirectory.
        /// </summary>
        /// <param name="Target">The target we're building</param>
        /// <param name="CPPFiles">The C++ files to #include.</param>
        /// <param name="CompileEnvironment">The environment that is used to compile the C++ files.</param>
        /// <param name="BaseName">Base name to use for the Unity files</param>
        /// <returns>The "unity" C++ files.</returns>
        public static List <FileItem> GenerateUnityCPPs(
            UEToolChain ToolChain,
            UEBuildTarget Target,
            List <FileItem> CPPFiles,
            CPPEnvironment CompileEnvironment,
            string BaseName
            )
        {
            List <FileItem> NewCPPFiles = new List <FileItem>();

            UEBuildPlatform BuildPlatform = UEBuildPlatform.GetBuildPlatformForCPPTargetPlatform(CompileEnvironment.Config.Platform);

            // Figure out size of all input files combined. We use this to determine whether to use larger unity threshold or not.
            long TotalBytesInCPPFiles = CPPFiles.Sum(F => F.Info.Length);

            // We have an increased threshold for unity file size if, and only if, all files fit into the same unity file. This
            // is beneficial when dealing with PCH files. The default PCH creation limit is X unity files so if we generate < X
            // this could be fairly slow and we'd rather bump the limit a bit to group them all into the same unity file.


            // When enabled, UnrealBuildTool will try to determine source files that you are actively iteratively changing, and break those files
            // out of their unity blobs so that you can compile them as individual translation units, much faster than recompiling the entire
            // unity blob each time.
            bool bUseAdaptiveUnityBuild = BuildConfiguration.bUseAdaptiveUnityBuild && !BuildConfiguration.bStressTestUnity;

            // Optimization only makes sense if PCH files are enabled.
            bool bForceIntoSingleUnityFile = BuildConfiguration.bStressTestUnity || (TotalBytesInCPPFiles < BuildConfiguration.NumIncludedBytesPerUnityCPP * 2 && CompileEnvironment.ShouldUsePCHs());

            // Build the list of unity files.
            List <FileCollection> AllUnityFiles;
            {
                // Sort the incoming file paths alphabetically, so there will be consistency in unity blobs across multiple machines.
                // Note that we're relying on this not only sorting files within each directory, but also the directories
                // themselves, so the whole list of file paths is the same across computers.
                List <FileItem> SortedCPPFiles = CPPFiles.GetRange(0, CPPFiles.Count);
                {
                    // Case-insensitive file path compare, because you never know what is going on with local file systems
                    Comparison <FileItem> FileItemComparer = (FileA, FileB) => { return(FileA.AbsolutePath.ToLowerInvariant().CompareTo(FileB.AbsolutePath.ToLowerInvariant())); };
                    SortedCPPFiles.Sort(FileItemComparer);
                }


                // Figure out whether we REALLY want to use adaptive unity for this module.  If nearly every file in the module appears in the working
                // set, we'll just go ahead and let unity build do its thing.
                if (bUseAdaptiveUnityBuild)
                {
                    int CandidateWorkingSetSourceFileCount = 0;
                    int WorkingSetSourceFileCount          = 0;
                    foreach (FileItem CPPFile in SortedCPPFiles)
                    {
                        // Don't include writable source files into unity blobs
                        if (!CPPFile.Reference.IsUnderDirectory(Target.EngineIntermediateDirectory) &&
                            !CPPFile.Reference.IsUnderDirectory(Target.ProjectIntermediateDirectory))
                        {
                            ++CandidateWorkingSetSourceFileCount;

                            if (UnrealBuildTool.ShouldSourceFileBePartOfWorkingSet(CPPFile.AbsolutePath))
                            {
                                ++WorkingSetSourceFileCount;

                                // Mark this file as part of the working set.  This will be saved into the UBT Makefile so that
                                // the assembler can automatically invalidate the Makefile when the working set changes (allowing this
                                // code to run again, to build up new unity blobs.)
                                SourceFileWorkingSet.Add(CPPFile);
                            }
                        }
                    }

                    if (WorkingSetSourceFileCount >= CandidateWorkingSetSourceFileCount)
                    {
                        // Every single file in the module appears in the working set, so don't bother using adaptive unity for this
                        // module.  Otherwise it would make full builds really slow.
                        bUseAdaptiveUnityBuild = false;
                    }
                }

                UnityFileBuilder CPPUnityFileBuilder          = new UnityFileBuilder(bForceIntoSingleUnityFile ? -1 : BuildConfiguration.NumIncludedBytesPerUnityCPP);
                StringBuilder    AdaptiveUnityBuildInfoString = new StringBuilder();
                foreach (FileItem CPPFile in SortedCPPFiles)
                {
                    if (!bForceIntoSingleUnityFile && CPPFile.AbsolutePath.IndexOf(".GeneratedWrapper.", StringComparison.InvariantCultureIgnoreCase) != -1)
                    {
                        NewCPPFiles.Add(CPPFile);
                    }

                    // When adaptive unity is enabled, go ahead and exclude any source files that we're actively working with
                    if (bUseAdaptiveUnityBuild && SourceFileWorkingSet.Contains(CPPFile))
                    {
                        // Just compile this file normally, not as part of the unity blob
                        NewCPPFiles.Add(CPPFile);

                        // Let the unity file builder know about the file, so that we can retain the existing size of the unity blobs.
                        // This won't actually make the source file part of the unity blob, but it will keep track of how big the
                        // file is so that other existing unity blobs from the same module won't be invalidated.  This prevents much
                        // longer compile times the first time you build after your working file set changes.
                        CPPUnityFileBuilder.AddVirtualFile(CPPFile);

                        string CPPFileName = Path.GetFileName(CPPFile.AbsolutePath);
                        if (AdaptiveUnityBuildInfoString.Length == 0)
                        {
                            AdaptiveUnityBuildInfoString.Append(String.Format("[Adaptive unity build] Excluded from {0} unity file: {1}", BaseName, CPPFileName));
                        }
                        else
                        {
                            AdaptiveUnityBuildInfoString.Append(", " + CPPFileName);
                        }
                    }

                    else
                    {
                        // If adaptive unity build is enabled for this module, add this source file to the set that will invalidate the makefile
                        if (bUseAdaptiveUnityBuild)
                        {
                            CandidateSourceFilesForWorkingSet.Add(CPPFile);
                        }

                        // Compile this file as part of the unity blob
                        CPPUnityFileBuilder.AddFile(CPPFile);

                        // Now that the CPPFile is part of this unity file, we will no longer need to treat it like a root level prerequisite for our
                        // dependency cache, as it is now an "indirect include" from the unity file.  We'll clear out the compile environment
                        // attached to this file.  This prevents us from having to cache all of the indirect includes from these files inside our
                        // dependency cache, which speeds up iterative builds a lot!
                        CPPFile.CachedCPPIncludeInfo = null;
                    }
                }

                if (AdaptiveUnityBuildInfoString.Length > 0)
                {
                    Log.TraceInformation(AdaptiveUnityBuildInfoString.ToString());
                }

                AllUnityFiles = CPPUnityFileBuilder.GetUnityFiles();
            }

            // Create a set of CPP files that combine smaller CPP files into larger compilation units, along with the corresponding
            // actions to compile them.
            int CurrentUnityFileCount = 0;

            foreach (FileCollection UnityFile in AllUnityFiles)
            {
                ++CurrentUnityFileCount;

                StringWriter OutputUnityCPPWriter      = new StringWriter();
                StringWriter OutputUnityCPPWriterExtra = null;

                // add an extra file for UBT to get the #include dependencies from
                if (BuildPlatform.RequiresExtraUnityCPPWriter() == true)
                {
                    OutputUnityCPPWriterExtra = new StringWriter();
                }

                OutputUnityCPPWriter.WriteLine("// This file is automatically generated at compile-time to include some subset of the user-created cpp files.");

                // Add source files to the unity file
                foreach (FileItem CPPFile in UnityFile.Files)
                {
                    OutputUnityCPPWriter.WriteLine("#include \"{0}\"", ToolChain.ConvertPath(CPPFile.AbsolutePath));
                    if (OutputUnityCPPWriterExtra != null)
                    {
                        OutputUnityCPPWriterExtra.WriteLine("#include \"{0}\"", CPPFile.AbsolutePath);
                    }
                }

                // Determine unity file path name
                string UnityCPPFileName;
                if (AllUnityFiles.Count > 1)
                {
                    UnityCPPFileName = string.Format("{0}{1}.{2}_of_{3}.cpp", ModulePrefix, BaseName, CurrentUnityFileCount, AllUnityFiles.Count);
                }
                else
                {
                    UnityCPPFileName = string.Format("{0}{1}.cpp", ModulePrefix, BaseName);
                }
                FileReference UnityCPPFilePath = FileReference.Combine(CompileEnvironment.Config.OutputDirectory, UnityCPPFileName);

                // Write the unity file to the intermediate folder.
                FileItem UnityCPPFile = FileItem.CreateIntermediateTextFile(UnityCPPFilePath, OutputUnityCPPWriter.ToString());
                if (OutputUnityCPPWriterExtra != null)
                {
                    FileItem.CreateIntermediateTextFile(UnityCPPFilePath + ".ex", OutputUnityCPPWriterExtra.ToString());
                }

                UnityCPPFile.RelativeCost = UnityFile.TotalLength;
                NewCPPFiles.Add(UnityCPPFile);

                // Cache information about the unity .cpp dependencies
                // @todo ubtmake urgent: Fails when building remotely for Mac because unity .cpp has an include for a PCH on the REMOTE machine
                UEBuildModuleCPP.CachePCHUsageForModuleSourceFile(CompileEnvironment, UnityCPPFile);
            }

            return(NewCPPFiles);
        }
Example #36
0
		void XGEDeleteBuildProducts(UnrealBuildTool.BuildManifest Manifest)
		{
			foreach (string Item in Manifest.BuildProducts)
			{
				DeleteFile(Item);
			}
		}
Example #37
0
            public BranchUProject(UnrealBuildTool.UProjectInfo InfoEntry)
            {
                GameName = InfoEntry.GameName;

                //not sure what the heck this path is relative to
                FilePath = Path.GetFullPath(CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, "Engine", "Binaries", InfoEntry.FilePath));

                if (!CommandUtils.FileExists_NoExceptions(FilePath))
                {
                    throw new AutomationException("Could not resolve relative path corrctly {0} -> {1} which doesn't exist.", InfoEntry.FilePath, FilePath);
                }

                Properties = ProjectUtils.GetProjectProperties(Path.GetFullPath(FilePath));
            }
Example #38
0
		BuildManifest BuildWithUBT(string TargetName, UnrealBuildTool.UnrealTargetPlatform TargetPlatform, string Config, FileReference UprojectPath, bool ForceMonolithic = false, bool ForceNonUnity = false, bool ForceDebugInfo = false, bool ForceFlushMac = false, bool DisableXGE = false, string InAddArgs = "", bool ForceUnity = false, Dictionary<string, string> EnvVars = null)
		{
			string AddArgs = "";
			if (UprojectPath != null)
			{
				AddArgs += " " + CommandUtils.MakePathSafeToUseWithCommandLine(UprojectPath.FullName);
			}
			AddArgs += " " + InAddArgs;
			if (ForceMonolithic)
			{
				AddArgs += " -monolithic";
			}
			if (ForceNonUnity)
			{
				AddArgs += " -disableunity";
			}
			if (ForceUnity)
			{
				AddArgs += " -forceunity";
			}
			if (ForceDebugInfo)
			{
				AddArgs += " -forcedebuginfo";
			}
			if (ForceFlushMac)
			{
				AddArgs += " -flushmac";
			}
			if (DisableXGE)
			{
				AddArgs += " -noxge";
			}

			PrepareUBT();

			// let the platform determine when to use the manifest
            bool UseManifest = Platform.GetPlatform(TargetPlatform).ShouldUseManifestForUBTBuilds(AddArgs);

			BuildManifest Manifest = null;
			if (UseManifest)
			{
                string UBTManifest = GetUBTManifest(UprojectPath, AddArgs);

				DeleteFile(UBTManifest);
				using(TelemetryStopwatch PrepareManifestStopwatch = new TelemetryStopwatch("PrepareUBTManifest.{0}.{1}.{2}", TargetName, TargetPlatform.ToString(), Config))
				{
					RunUBT(CmdEnv, UBTExecutable: UBTExecutable, Project: UprojectPath, Target: TargetName, Platform: TargetPlatform.ToString(), Config: Config, AdditionalArgs: AddArgs + " -generatemanifest", EnvVars: EnvVars);
				}
                Manifest = PrepareManifest(UBTManifest, false);
			}

			using(TelemetryStopwatch CompileStopwatch = new TelemetryStopwatch("Compile.{0}.{1}.{2}", TargetName, TargetPlatform.ToString(), Config))
			{
				RunUBT(CmdEnv, UBTExecutable: UBTExecutable, Project: UprojectPath, Target: TargetName, Platform: TargetPlatform.ToString(), Config: Config, AdditionalArgs: AddArgs, EnvVars: EnvVars);
			}

			if(!AddArgs.Contains("-nolink"))
			{
				// allow the platform to perform any actions after building a target (seems almost like this should be done in UBT)
				Platform.GetPlatform(TargetPlatform).PostBuildTarget(this, UprojectPath, TargetName, Config);
			}

			if (UseManifest)
			{
                string UBTManifest = GetUBTManifest(UprojectPath, AddArgs);

				AddBuildProductsFromManifest(UBTManifest);

				DeleteFile(UBTManifest);
			}
			return Manifest;
		}
		/// <summary>
		/// Returns the default path of the editor executable to use for running commandlets.
		/// </summary>
		/// <param name="BuildRoot">Root directory for the build</param>
		/// <param name="HostPlatform">Platform to get the executable for</param>
		/// <returns>Path to the editor executable</returns>
		public static string GetEditorCommandletExe(string BuildRoot, UnrealBuildTool.UnrealTargetPlatform HostPlatform)
		{
			switch(HostPlatform)
			{
				case UnrealBuildTool.UnrealTargetPlatform.Mac:
					return CommandUtils.CombinePaths(BuildRoot, "Engine/Binaries/Mac/UE4Editor.app/Contents/MacOS/UE4Editor");
				case UnrealBuildTool.UnrealTargetPlatform.Win64:
					return CommandUtils.CombinePaths(BuildRoot, "Engine/Binaries/Win64/UE4Editor-Cmd.exe");
				case UnrealBuildTool.UnrealTargetPlatform.Linux:
					return CommandUtils.CombinePaths(BuildRoot, "Engine/Binaries/Linux/UE4Editor");
				default:
					throw new AutomationException("EditorCommandlet is not supported for platform {0}", HostPlatform);
			}
		}
Example #40
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);

            // 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);

            // 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
            {
                // Parse all the target descriptors
                List <TargetDescriptor> TargetDescriptors;
                using (Timeline.ScopeEvent("TargetDescriptor.ParseCommandLine()"))
                {
                    TargetDescriptors = TargetDescriptor.ParseCommandLine(Arguments, BuildConfiguration.bUsePrecompiled, BuildConfiguration.bSkipRulesCompile);
                }

                // Hack for single file 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.SingleFileToCompile != null);
                }

                // 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))
                        {
                            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;
                    }

                    // Create the working set provider
                    using (ISourceFileWorkingSet WorkingSet = SourceFileWorkingSet.Create(UnrealBuildTool.RootDirectory, ProjectDirs))
                    {
                        Build(TargetDescriptors, BuildConfiguration, WorkingSet, Options, WriteOutdatedActionsFile);
                    }
                }
            }
            finally
            {
                // Save all the caches
                SourceFileMetadataCache.SaveAll();
                CppDependencyCache.SaveAll();
            }
            return(0);
        }
        /// <summary>
        /// Creates a rules assembly with the given parameters.
        /// </summary>
        /// <param name="ProjectFileName">The project file to create rules for. Null for the engine.</param>
        /// <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 CreateProjectRulesAssembly(FileReference ProjectFileName, bool bUsePrecompiled, bool bSkipCompile)
        {
            // Check if there's an existing assembly for this project
            RulesAssembly ProjectRulesAssembly;

            if (!LoadedAssemblyMap.TryGetValue(ProjectFileName, out ProjectRulesAssembly))
            {
                ProjectDescriptor Project = ProjectDescriptor.FromFile(ProjectFileName);

                // Create the parent assembly
                RulesAssembly Parent;
                if (Project.IsEnterpriseProject)
                {
                    Parent = CreateEnterpriseRulesAssembly(bUsePrecompiled, bSkipCompile);
                }
                else
                {
                    Parent = CreateEngineRulesAssembly(bUsePrecompiled, bSkipCompile);
                }

                DirectoryReference MainProjectDirectory = ProjectFileName.Directory;
                //DirectoryReference MainProjectSourceDirectory = DirectoryReference.Combine(MainProjectDirectory, "Source");

                // Create a scope for things in this assembly
                RulesScope Scope = new RulesScope("Project", Parent.Scope);

                // Create a new context for modules created by this assembly
                ModuleRulesContext DefaultModuleContext = new ModuleRulesContext(Scope, MainProjectDirectory);
                DefaultModuleContext.bCanBuildDebugGame          = true;
                DefaultModuleContext.bCanHotReload               = true;
                DefaultModuleContext.bClassifyAsGameModuleForUHT = true;
                DefaultModuleContext.bCanUseForSharedPCH         = false;

                // gather modules from project and platforms
                Dictionary <FileReference, ModuleRulesContext> ModuleFiles = new Dictionary <FileReference, ModuleRulesContext>();
                List <FileReference> TargetFiles = new List <FileReference>();

                // Find all the project directories
                List <DirectoryReference> ProjectDirectories = new List <DirectoryReference>(UnrealBuildTool.GetAllProjectDirectories(ProjectFileName));
                if (Project.AdditionalRootDirectories != null)
                {
                    ProjectDirectories.AddRange(Project.AdditionalRootDirectories);
                }

                // Find all the rules/plugins under the project source directories
                foreach (DirectoryReference ProjectDirectory in ProjectDirectories)
                {
                    DirectoryReference ProjectSourceDirectory = DirectoryReference.Combine(ProjectDirectory, "Source");

                    AddModuleRulesWithContext(ProjectSourceDirectory, DefaultModuleContext, ModuleFiles);
                    TargetFiles.AddRange(FindAllRulesFiles(ProjectSourceDirectory, RulesFileType.Target));
                }

                // Find all the project plugins
                List <PluginInfo> ProjectPlugins = new List <PluginInfo>();
                ProjectPlugins.AddRange(Plugins.ReadProjectPlugins(MainProjectDirectory));

                // Add the project's additional plugin directories plugins too
                if (Project.AdditionalPluginDirectories != null)
                {
                    foreach (DirectoryReference AdditionalPluginDirectory in Project.AdditionalPluginDirectories)
                    {
                        ProjectPlugins.AddRange(Plugins.ReadAdditionalPlugins(AdditionalPluginDirectory));
                    }
                }

                // Find all the plugin module rules
                FindModuleRulesForPlugins(ProjectPlugins, DefaultModuleContext, ModuleFiles);

                // Add the games project's intermediate source folder
                DirectoryReference ProjectIntermediateSourceDirectory = DirectoryReference.Combine(MainProjectDirectory, "Intermediate", "Source");
                if (DirectoryReference.Exists(ProjectIntermediateSourceDirectory))
                {
                    AddModuleRulesWithContext(ProjectIntermediateSourceDirectory, DefaultModuleContext, ModuleFiles);
                    TargetFiles.AddRange(FindAllRulesFiles(ProjectIntermediateSourceDirectory, RulesFileType.Target));
                }

                // Compile the assembly. If there are no module or target files, just use the parent assembly.
                FileReference AssemblyFileName = FileReference.Combine(MainProjectDirectory, "Intermediate", "Build", "BuildRules", ProjectFileName.GetFileNameWithoutExtension() + "ModuleRules" + FrameworkAssemblyExtension);
                if (ModuleFiles.Count == 0 && TargetFiles.Count == 0)
                {
                    ProjectRulesAssembly = Parent;
                }
                else
                {
                    ProjectRulesAssembly = new RulesAssembly(Scope, new List <DirectoryReference> {
                        MainProjectDirectory
                    }, ProjectPlugins, ModuleFiles, TargetFiles, AssemblyFileName, bContainsEngineModules: false, DefaultBuildSettings: null, bReadOnly: UnrealBuildTool.IsProjectInstalled(), bSkipCompile: bSkipCompile, Parent: Parent);
                }
                LoadedAssemblyMap.Add(ProjectFileName, ProjectRulesAssembly);
            }
            return(ProjectRulesAssembly);
        }
 public virtual UnrealBuildTool.UEDeployIOS GetDeployHandler(FileReference InProject, UnrealBuildTool.IOSPlatformContext inPlatformContext)
 {
     Console.WriteLine("Getting IOS Deploy()");
     return new UnrealBuildTool.UEDeployIOS(InProject, inPlatformContext);
 }
Example #43
0
        /// <summary>
        /// Discover and fill in the project info
        /// </summary>
        public static void FillProjectInfo()
        {
            DateTime StartTime = DateTime.Now;

            List <string> DirectoriesToSearch = new List <string>();

            // Find all the .uprojectdirs files contained in the root folder and add their entries to the search array
            string RootDirectory         = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetOriginalLocation()), "..", "..", "..");
            string EngineSourceDirectory = Path.GetFullPath(Path.Combine(RootDirectory, "Engine", "Source"));

            foreach (var File in Directory.EnumerateFiles(RootDirectory, "*.uprojectdirs", SearchOption.TopDirectoryOnly))
            {
                string FilePath = Path.GetFullPath(File);
                Log.TraceVerbose("\tFound uprojectdirs file {0}", FilePath);

                using (StreamReader Reader = new StreamReader(FilePath))
                {
                    string LineRead;
                    while ((LineRead = Reader.ReadLine()) != null)
                    {
                        string ProjDirEntry = LineRead.Trim();
                        if (String.IsNullOrEmpty(ProjDirEntry) == false)
                        {
                            if (ProjDirEntry.StartsWith(";"))
                            {
                                // Commented out line... skip it
                                continue;
                            }
                            else
                            {
                                string DirPath = Path.GetFullPath(Path.Combine(RootDirectory, ProjDirEntry));
                                DirectoriesToSearch.Add(DirPath);
                            }
                        }
                    }
                }
            }

            Log.TraceVerbose("\tFound {0} directories to search", DirectoriesToSearch.Count);

            foreach (string DirToSearch in DirectoriesToSearch)
            {
                Log.TraceVerbose("\t\tSearching {0}", DirToSearch);
                if (Directory.Exists(DirToSearch))
                {
                    foreach (string SubDir in Directory.EnumerateDirectories(DirToSearch, "*", SearchOption.TopDirectoryOnly))
                    {
                        Log.TraceVerbose("\t\t\tFound subdir {0}", SubDir);
                        string[] SubDirFiles = Directory.GetFiles(SubDir, "*.uproject", SearchOption.TopDirectoryOnly);
                        foreach (string UProjFile in SubDirFiles)
                        {
                            Log.TraceVerbose("\t\t\t\t{0}", UProjFile);
                            AddProject(new FileReference(UProjFile));
                        }
                    }
                }
                else
                {
                    Log.TraceVerbose("ProjectInfo: Skipping directory {0} from .uprojectdirs file as it doesn't exist.", DirToSearch);
                }
            }

            DateTime StopTime = DateTime.Now;

            if (BuildConfiguration.bPrintPerformanceInfo)
            {
                TimeSpan TotalProjectInfoTime = StopTime - StartTime;
                Log.TraceInformation("FillProjectInfo took {0} milliseconds", TotalProjectInfoTime.Milliseconds);
            }

            if (UnrealBuildTool.CommandLineContains("-dumpprojectinfo"))
            {
                UProjectInfo.DumpProjectInfo();
            }
        }
	private static void MakeFreshDirectoryIfRequired(UnrealBuildTool.DirectoryReference Directory)
	{
		if (!Directory.Exists())
		{
			Directory.CreateDirectory();
		}
		else
		{

			InternalUtils.SafeDeleteDirectory(Directory.FullName);
			Directory.CreateDirectory();
		}
	}
        public static bool GenerateTVOSPList(string ProjectDirectory, bool bIsUE4Game, string GameName, string ProjectName, string InEngineDir, string AppDirectory, UEDeployTVOS InThis = null)
        {
            // @todo tvos: THIS!


            // generate the Info.plist for future use
            string BuildDirectory        = ProjectDirectory + "/Build/TVOS";
            bool   bSkipDefaultPNGs      = false;
            string IntermediateDirectory = (bIsUE4Game ? InEngineDir : ProjectDirectory) + "/Intermediate/TVOS";
            string PListFile             = IntermediateDirectory + "/" + GameName + "-Info.plist";

            // @todo tvos: This is really nasty - both IOS and TVOS are setting static vars
            VersionUtilities.BuildDirectory = BuildDirectory;
            VersionUtilities.GameName       = GameName;

            // read the old file
            string OldPListData = File.Exists(PListFile) ? File.ReadAllText(PListFile) : "";

            // determine if there is a launch.xib
            string LaunchXib = InEngineDir + "/Build/IOS/Resources/Interface/LaunchScreen.xib";

            if (File.Exists(BuildDirectory + "/Resources/Interface/LaunchScreen.xib"))
            {
                LaunchXib = BuildDirectory + "/Resources/Interface/LaunchScreen.xib";
            }

            // get the settings from the ini file
            // plist replacements
            // @todo tvos: Are we going to make TVOS specific .ini files?
            DirectoryReference DirRef = bIsUE4Game ? (!string.IsNullOrEmpty(UnrealBuildTool.GetRemoteIniPath()) ? new DirectoryReference(UnrealBuildTool.GetRemoteIniPath()) : null) : new DirectoryReference(ProjectDirectory);
            ConfigHierarchy    Ini    = ConfigCache.ReadHierarchy(ConfigHierarchyType.Engine, DirRef, UnrealTargetPlatform.IOS);

            // bundle display name
            string BundleDisplayName;

            Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "BundleDisplayName", out BundleDisplayName);

            // bundle identifier
            string BundleIdentifier;

            Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "BundleIdentifier", out BundleIdentifier);

            // bundle name
            string BundleName;

            Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "BundleName", out BundleName);

            // short version string
            string BundleShortVersion;

            Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "VersionInfo", out BundleShortVersion);

            // required capabilities
            string RequiredCaps = "\t\t<string>arm64</string>\n";

            // minimum iOS version
            string MinVersion;

            if (Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "MinimumTVOSVersion", out MinVersion))
            {
                switch (MinVersion)
                {
                case "TVOS_9":
                    MinVersion = "9.0";
                    break;
                }
            }
            else
            {
                MinVersion = "9.0";
            }

            // extra plist data
            string ExtraData = "";

            Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "AdditionalPlistData", out ExtraData);

            // create the final display name, including converting all entities for XML use
            string FinalDisplayName = BundleDisplayName.Replace("[PROJECT_NAME]", ProjectName).Replace("_", "");

            FinalDisplayName = FinalDisplayName.Replace("&", "&amp;");
            FinalDisplayName = FinalDisplayName.Replace("\"", "&quot;");
            FinalDisplayName = FinalDisplayName.Replace("\'", "&apos;");
            FinalDisplayName = FinalDisplayName.Replace("<", "&lt;");
            FinalDisplayName = FinalDisplayName.Replace(">", "&gt;");

            // generate the plist file
            StringBuilder Text = new StringBuilder();

            Text.AppendLine("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
            Text.AppendLine("<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">");
            Text.AppendLine("<plist version=\"1.0\">");
            Text.AppendLine("<dict>");
            Text.AppendLine("\t<key>CFBundleDevelopmentRegion</key>");
            Text.AppendLine("\t<string>en</string>");
            Text.AppendLine("\t<key>CFBundleDisplayName</key>");
            Text.AppendLine(string.Format("\t<string>{0}</string>", EncodeBundleName(BundleDisplayName, ProjectName)));
            Text.AppendLine("\t<key>CFBundleExecutable</key>");
            Text.AppendLine(string.Format("\t<string>{0}</string>", bIsUE4Game ? "UE4Game" : GameName));
            Text.AppendLine("\t<key>CFBundleIdentifier</key>");
            Text.AppendLine(string.Format("\t<string>{0}</string>", BundleIdentifier.Replace("[PROJECT_NAME]", ProjectName).Replace("_", "")));
            Text.AppendLine("\t<key>CFBundleInfoDictionaryVersion</key>");
            Text.AppendLine("\t<string>6.0</string>");
            Text.AppendLine("\t<key>CFBundleName</key>");
            Text.AppendLine(string.Format("\t<string>{0}</string>", EncodeBundleName(BundleName, ProjectName)));
            Text.AppendLine("\t<key>CFBundlePackageType</key>");
            Text.AppendLine("\t<string>APPL</string>");
            Text.AppendLine("\t<key>CFBundleSignature</key>");
            Text.AppendLine("\t<string>????</string>");
            Text.AppendLine("\t<key>CFBundleVersion</key>");
            Text.AppendLine(string.Format("\t<string>{0}</string>", VersionUtilities.UpdateBundleVersion(OldPListData, InEngineDir)));
            Text.AppendLine("\t<key>CFBundleShortVersionString</key>");
            Text.AppendLine(string.Format("\t<string>{0}</string>", BundleShortVersion));
            Text.AppendLine("\t<key>LSRequiresIPhoneOS</key>");
            Text.AppendLine("\t<true/>");
            Text.AppendLine("\t<key>UIRequiredDeviceCapabilities</key>");
            Text.AppendLine("\t<array>");
            foreach (string Line in RequiredCaps.Split("\r\n".ToCharArray()))
            {
                if (!string.IsNullOrWhiteSpace(Line))
                {
                    Text.AppendLine(Line);
                }
            }
            Text.AppendLine("\t</array>");

            Text.AppendLine("\t<key>TVTopShelfImage</key>");
            Text.AppendLine("\t<dict>");
            Text.AppendLine("\t\t<key>TVTopShelfPrimaryImage</key>");
            Text.AppendLine("\t\t<string>TopShelf</string>");
            Text.AppendLine("\t</dict>");
            Text.AppendLine("\t<key>UILaunchImages</key>");
            Text.AppendLine("\t<array>");
            Text.AppendLine("\t\t<dict>");
            Text.AppendLine("\t\t\t<key>UILaunchImageSize</key>");
            Text.AppendLine("\t\t\t<string>{1920, 1080}</string>");
            Text.AppendLine("\t\t\t<key>UILaunchImageName</key>");
            Text.AppendLine("\t\t\t<string>LaunchImage</string>");
            Text.AppendLine("\t\t\t<key>UILaunchImageMinimumOSVersion</key>");
            Text.AppendLine("\t\t\t<string>9.0</string>");
            Text.AppendLine("\t\t\t<key>UILaunchImageOrientation</key>");
            Text.AppendLine("\t\t\t<string>Landscape</string>");
            Text.AppendLine("\t\t</dict>");
            Text.AppendLine("\t</array>");
            Text.AppendLine("\t<key>CFBundleIcons</key>");
            Text.AppendLine("\t<dict>");
            Text.AppendLine("\t\t<key>CFBundlePrimaryIcon</key>");
            Text.AppendLine("\t\t<string>AppIconSmall</string>");
            Text.AppendLine("\t</dict>");

            /*			Text.AppendLine("\t<key>CFBundleIcons</key>");
             *          Text.AppendLine("\t<dict>");
             *          Text.AppendLine("\t\t<key>CFBundlePrimaryIcon</key>");
             *          Text.AppendLine("\t\t<dict>");
             *          Text.AppendLine("\t\t\t<key>CFBundleIconFiles</key>");
             *          Text.AppendLine("\t\t\t<array>");
             *          Text.AppendLine("\t\t\t\t<string>Icon29.png</string>");
             *          Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
             *          Text.AppendLine("\t\t\t\t<string>Icon40.png</string>");
             *          Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
             *          Text.AppendLine("\t\t\t\t<string>Icon57.png</string>");
             *          Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
             *          Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
             *          Text.AppendLine("\t\t\t</array>");
             *          Text.AppendLine("\t\t\t<key>UIPrerenderedIcon</key>");
             *          Text.AppendLine("\t\t\t<true/>");
             *          Text.AppendLine("\t\t</dict>");
             *          Text.AppendLine("\t</dict>");
             *          Text.AppendLine("\t<key>CFBundleIcons~ipad</key>");
             *          Text.AppendLine("\t<dict>");
             *          Text.AppendLine("\t\t<key>CFBundlePrimaryIcon</key>");
             *          Text.AppendLine("\t\t<dict>");
             *          Text.AppendLine("\t\t\t<key>CFBundleIconFiles</key>");
             *          Text.AppendLine("\t\t\t<array>");
             *          Text.AppendLine("\t\t\t\t<string>Icon29.png</string>");
             *          Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
             *          Text.AppendLine("\t\t\t\t<string>Icon40.png</string>");
             *          Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
             *          Text.AppendLine("\t\t\t\t<string>Icon50.png</string>");
             *          Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
             *          Text.AppendLine("\t\t\t\t<string>Icon72.png</string>");
             *          Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
             *          Text.AppendLine("\t\t\t\t<string>Icon76.png</string>");
             *          Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
             *          Text.AppendLine("\t\t\t</array>");
             *          Text.AppendLine("\t\t\t<key>UIPrerenderedIcon</key>");
             *          Text.AppendLine("\t\t\t<true/>");
             *          Text.AppendLine("\t\t</dict>");
             *          Text.AppendLine("\t</dict>");
             *          if (File.Exists(LaunchXib))
             *          {
             *              // TODO: compile the xib via remote tool
             *              Text.AppendLine("\t<key>UILaunchStoryboardName</key>");
             *              Text.AppendLine("\t<string>LaunchScreen</string>");
             *              bSkipDefaultPNGs = true;
             *          }
             *          else
             *          {
             *              // this is a temp way to inject the iphone 6 images without needing to upgrade everyone's plist
             *              // eventually we want to generate this based on what the user has set in the project settings
             *              string[] IPhoneConfigs =
             *                  {
             *                      "Default-IPhone6", "Landscape", "{375, 667}",
             *                      "Default-IPhone6", "Portrait", "{375, 667}",
             *                      "Default-IPhone6Plus-Landscape", "Landscape", "{414, 736}",
             *                      "Default-IPhone6Plus-Portrait", "Portrait", "{414, 736}",
             *                      "Default", "Landscape", "{320, 480}",
             *                      "Default", "Portrait", "{320, 480}",
             *                      "Default-568h", "Landscape", "{320, 568}",
             *                      "Default-568h", "Portrait", "{320, 568}",
             *                  };
             *
             *              Text.AppendLine("\t<key>UILaunchImages~iphone</key>");
             *              Text.AppendLine("\t<array>");
             *              for (int ConfigIndex = 0; ConfigIndex < IPhoneConfigs.Length; ConfigIndex += 3)
             *              {
             *                  Text.AppendLine("\t\t<dict>");
             *                  Text.AppendLine("\t\t\t<key>UILaunchImageMinimumOSVersion</key>");
             *                  Text.AppendLine("\t\t\t<string>8.0</string>");
             *                  Text.AppendLine("\t\t\t<key>UILaunchImageName</key>");
             *                  Text.AppendLine(string.Format("\t\t\t<string>{0}</string>", IPhoneConfigs[ConfigIndex + 0]));
             *                  Text.AppendLine("\t\t\t<key>UILaunchImageOrientation</key>");
             *                  Text.AppendLine(string.Format("\t\t\t<string>{0}</string>", IPhoneConfigs[ConfigIndex + 1]));
             *                  Text.AppendLine("\t\t\t<key>UILaunchImageSize</key>");
             *                  Text.AppendLine(string.Format("\t\t\t<string>{0}</string>", IPhoneConfigs[ConfigIndex + 2]));
             *                  Text.AppendLine("\t\t</dict>");
             *              }
             *
             *              // close it out
             *              Text.AppendLine("\t</array>");
             *          }
             *          Text.AppendLine("\t<key>UILaunchImages~ipad</key>");
             *          Text.AppendLine("\t<array>");
             *          Text.AppendLine("\t\t<dict>");
             *          Text.AppendLine("\t\t\t<key>UILaunchImageMinimumOSVersion</key>");
             *          Text.AppendLine("\t\t\t<string>7.0</string>");
             *          Text.AppendLine("\t\t\t<key>UILaunchImageName</key>");
             *          Text.AppendLine("\t\t\t<string>Default-Landscape</string>");
             *          Text.AppendLine("\t\t\t<key>UILaunchImageOrientation</key>");
             *          Text.AppendLine("\t\t\t<string>Landscape</string>");
             *          Text.AppendLine("\t\t\t<key>UILaunchImageSize</key>");
             *          Text.AppendLine("\t\t\t<string>{768, 1024}</string>");
             *          Text.AppendLine("\t\t</dict>");
             *          Text.AppendLine("\t\t<dict>");
             *          Text.AppendLine("\t\t\t<key>UILaunchImageMinimumOSVersion</key>");
             *          Text.AppendLine("\t\t\t<string>7.0</string>");
             *          Text.AppendLine("\t\t\t<key>UILaunchImageName</key>");
             *          Text.AppendLine("\t\t\t<string>Default-Portrait</string>");
             *          Text.AppendLine("\t\t\t<key>UILaunchImageOrientation</key>");
             *          Text.AppendLine("\t\t\t<string>Portrait</string>");
             *          Text.AppendLine("\t\t\t<key>UILaunchImageSize</key>");
             *          Text.AppendLine("\t\t\t<string>{768, 1024}</string>");
             *          Text.AppendLine("\t\t</dict>");
             *          Text.AppendLine("\t</array>”);
             *          Text.AppendLine("\t<key>CFBundleSupportedPlatforms</key>");
             *          Text.AppendLine("\t<array>");
             *          Text.AppendLine("\t\t<string>iPhoneOS</string>");
             *          Text.AppendLine("\t</array>");
             *          Text.AppendLine("\t<key>MinimumOSVersion</key>");
             *          Text.AppendLine(string.Format("\t<string>{0}</string>", MinVersion));
             *          if (!string.IsNullOrEmpty(ExtraData))
             *          {
             *              ExtraData = ExtraData.Replace("\\n", "\n");
             *              foreach (string Line in ExtraData.Split("\r\n".ToCharArray()))
             *              {
             *                  if (!string.IsNullOrWhiteSpace(Line))
             *                  {
             *                      Text.AppendLine("\t" + Line);
             *                  }
             *              }
             *          }*/
            Text.AppendLine("</dict>");
            Text.AppendLine("</plist>");

            // Create the intermediate directory if needed
            if (!Directory.Exists(IntermediateDirectory))
            {
                Directory.CreateDirectory(IntermediateDirectory);
            }

            if (InThis != null && InThis.UPL != null)
            {
                // Allow UPL to modify the plist here
                XDocument XDoc;
                try
                {
                    XDoc = XDocument.Parse(Text.ToString());
                }
                catch (Exception e)
                {
                    throw new BuildException("plist is invalid {0}\n{1}", e, Text.ToString());
                }

                XDoc.DocumentType.InternalSubset = "";
                InThis.UPL.ProcessPluginNode("None", "iosPListUpdates", "", ref XDoc);
                string result = XDoc.Declaration.ToString() + "\n" + XDoc.ToString().Replace("<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"[]>", "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">");
                File.WriteAllText(PListFile, result);
            }
            else
            {
                File.WriteAllText(PListFile, Text.ToString());
            }

            if (BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac)
            {
                if (!Directory.Exists(AppDirectory))
                {
                    Directory.CreateDirectory(AppDirectory);
                }
                File.WriteAllText(AppDirectory + "/Info.plist", Text.ToString());
            }

            return(bSkipDefaultPNGs);
        }