Beispiel #1
0
        /// <summary>
        /// Writes information about the targets in an assembly to a file
        /// </summary>
        /// <param name="ProjectFile">The project file for the targets being built</param>
        /// <param name="Assembly">The rules assembly for this target</param>
        /// <param name="OutputFile">Output file to write to</param>
        /// <param name="Arguments"></param>
        public static void WriteTargetInfo(FileReference ProjectFile, RulesAssembly Assembly, FileReference OutputFile, CommandLineArguments Arguments)
        {
            // Construct all the targets in this assembly
            List <string> TargetNames = new List <string>();

            Assembly.GetAllTargetNames(TargetNames, false);

            // Write the output file
            DirectoryReference.CreateDirectory(OutputFile.Directory);
            using (JsonWriter Writer = new JsonWriter(OutputFile))
            {
                Writer.WriteObjectStart();
                Writer.WriteArrayStart("Targets");
                foreach (string TargetName in TargetNames)
                {
                    // skip target rules that are platform extension or platform group specializations
                    string[] TargetPathSplit = TargetName.Split(new char[] { '_' }, StringSplitOptions.RemoveEmptyEntries);
                    if (TargetPathSplit.Length > 1 && (UnrealTargetPlatform.IsValidName(TargetPathSplit.Last()) || UnrealPlatformGroup.IsValidName(TargetPathSplit.Last())))
                    {
                        continue;
                    }

                    // Construct the rules object
                    TargetRules TargetRules;
                    try
                    {
                        string Architecture = UEBuildPlatform.GetBuildPlatform(BuildHostPlatform.Current.Platform).GetDefaultArchitecture(ProjectFile);
                        TargetRules = Assembly.CreateTargetRules(TargetName, BuildHostPlatform.Current.Platform, UnrealTargetConfiguration.Development, Architecture, ProjectFile, Arguments);
                    }
                    catch (Exception Ex)
                    {
                        Log.TraceWarning("Unable to construct target rules for {0}", TargetName);
                        Log.TraceVerbose(ExceptionUtils.FormatException(Ex));
                        continue;
                    }

                    // Write the target info
                    Writer.WriteObjectStart();
                    Writer.WriteValue("Name", TargetName);
                    Writer.WriteValue("Path", Assembly.GetTargetFileName(TargetName).ToString());
                    Writer.WriteValue("Type", TargetRules.Type.ToString());
                    Writer.WriteObjectEnd();
                }
                Writer.WriteArrayEnd();
                Writer.WriteObjectEnd();
            }
        }
Beispiel #2
0
        /// <summary>
        /// Creates a target rules object for the specified target name.
        /// </summary>
        /// <param name="TargetName">Name of the target</param>
        /// <param name="Platform">Platform being compiled</param>
        /// <param name="Configuration">Configuration being compiled</param>
        /// <param name="Architecture">Architecture being built</param>
        /// <param name="ProjectFile">Path to the project file for this target</param>
        /// <param name="Version">The current build version</param>
        /// <param name="TargetFileName">The original source file name of the Target.cs file for this target</param>
        /// <returns>The build target rules for the specified target</returns>
        public TargetRules CreateTargetRules(string TargetName, UnrealTargetPlatform Platform, UnrealTargetConfiguration Configuration, string Architecture, FileReference ProjectFile, ReadOnlyBuildVersion Version, out FileReference TargetFileName)
        {
            bool bFoundTargetName = TargetNameToTargetFile.ContainsKey(TargetName);

            if (bFoundTargetName == false)
            {
                if (Parent == null)
                {
                    //				throw new BuildException("Couldn't find target rules file for target '{0}' in rules assembly '{1}'.", TargetName, RulesAssembly.FullName);
                    string ExceptionMessage = "Couldn't find target rules file for target '";
                    ExceptionMessage += TargetName;
                    ExceptionMessage += "' in rules assembly '";
                    ExceptionMessage += CompiledAssembly.FullName;
                    ExceptionMessage += "'." + Environment.NewLine;

                    ExceptionMessage += "Location: " + CompiledAssembly.Location + Environment.NewLine;

                    ExceptionMessage += "Target rules found:" + Environment.NewLine;
                    foreach (KeyValuePair <string, FileReference> entry in TargetNameToTargetFile)
                    {
                        ExceptionMessage += "\t" + entry.Key + " - " + entry.Value + Environment.NewLine;
                    }

                    throw new BuildException(ExceptionMessage);
                }
                else
                {
                    return(Parent.CreateTargetRules(TargetName, Platform, Configuration, Architecture, ProjectFile, Version, out TargetFileName));
                }
            }

            // Return the target file name to the caller
            TargetFileName = TargetNameToTargetFile[TargetName];

            // Currently, we expect the user's rules object type name to be the same as the module name + 'Target'
            string TargetTypeName = TargetName + "Target";

            // The build module must define a type named '<TargetName>Target' that derives from our 'TargetRules' type.
            return(CreateTargetRulesInstance(TargetTypeName, new TargetInfo(TargetName, Platform, Configuration, Architecture, ProjectFile, Version)));
        }
Beispiel #3
0
        /// <summary>
        /// Writes information about the targets in an assembly to a file
        /// </summary>
        /// <param name="ProjectFile">The project file for the targets being built</param>
        /// <param name="Assembly">The rules assembly for this target</param>
        /// <param name="OutputFile">Output file to write to</param>
        /// <param name="Arguments"></param>
        public static void WriteTargetInfo(FileReference ProjectFile, RulesAssembly Assembly, FileReference OutputFile, CommandLineArguments Arguments)
        {
            // Construct all the targets in this assembly
            List <string> TargetNames = new List <string>();

            Assembly.GetAllTargetNames(TargetNames, false);

            // Write the output file
            DirectoryReference.CreateDirectory(OutputFile.Directory);
            using (JsonWriter Writer = new JsonWriter(OutputFile))
            {
                Writer.WriteObjectStart();
                Writer.WriteArrayStart("Targets");
                foreach (string TargetName in TargetNames)
                {
                    // Construct the rules object
                    TargetRules TargetRules;
                    try
                    {
                        string Architecture = UEBuildPlatform.GetBuildPlatform(BuildHostPlatform.Current.Platform).GetDefaultArchitecture(ProjectFile);
                        TargetRules = Assembly.CreateTargetRules(TargetName, BuildHostPlatform.Current.Platform, UnrealTargetConfiguration.Development, Architecture, ProjectFile, Arguments);
                    }
                    catch (Exception Ex)
                    {
                        Log.TraceWarning("Unable to construct target rules for {0}", TargetName);
                        Log.TraceVerbose(ExceptionUtils.FormatException(Ex));
                        continue;
                    }

                    // Write the target info
                    Writer.WriteObjectStart();
                    Writer.WriteValue("Name", TargetName);
                    Writer.WriteValue("Path", Assembly.GetTargetFileName(TargetName).ToString());
                    Writer.WriteValue("Type", TargetRules.Type.ToString());
                    Writer.WriteObjectEnd();
                }
                Writer.WriteArrayEnd();
                Writer.WriteObjectEnd();
            }
        }
Beispiel #4
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);

            // Create the build configuration object, and read the settings
            BuildConfiguration BuildConfiguration = new BuildConfiguration();

            XmlConfig.ApplyTo(BuildConfiguration);
            Arguments.ApplyTo(BuildConfiguration);

            // Parse all the targets being built
            List <TargetDescriptor> TargetDescriptors = TargetDescriptor.ParseCommandLine(Arguments, BuildConfiguration.bUsePrecompiled, bSkipRulesCompile);

            if (TargetDescriptors.Count == 0)
            {
                throw new BuildException("No targets specified to clean");
            }

            // Also add implicit descriptors for cleaning UnrealBuildTool
            if (!BuildConfiguration.bDoNotBuildUHT)
            {
                const string UnrealHeaderToolTarget = "UnrealHeaderTool";

                // Get a list of project files to clean UHT for
                List <FileReference> ProjectFiles = new List <FileReference>();
                foreach (TargetDescriptor TargetDesc in TargetDescriptors)
                {
                    if (TargetDesc.Name != UnrealHeaderToolTarget && !RemoteMac.HandlesTargetPlatform(TargetDesc.Platform))
                    {
                        if (ProjectFiles.Count == 0)
                        {
                            ProjectFiles.Add(null);
                        }
                        if (TargetDesc.ProjectFile != null && !ProjectFiles.Contains(TargetDesc.ProjectFile))
                        {
                            ProjectFiles.Add(TargetDesc.ProjectFile);
                        }
                    }
                }

                // Add descriptors for cleaning UHT with all these projects
                if (ProjectFiles.Count > 0)
                {
                    UnrealTargetConfiguration Configuration = BuildConfiguration.bForceDebugUnrealHeaderTool ? UnrealTargetConfiguration.Debug : UnrealTargetConfiguration.Development;
                    string Architecture = UEBuildPlatform.GetBuildPlatform(BuildHostPlatform.Current.Platform).GetDefaultArchitecture(null);
                    foreach (FileReference ProjectFile in ProjectFiles)
                    {
                        TargetDescriptors.Add(new TargetDescriptor(ProjectFile, UnrealHeaderToolTarget, BuildHostPlatform.Current.Platform, Configuration, Architecture, null));
                    }
                }
            }

            // Output the list of targets that we're cleaning
            Log.TraceInformation("Cleaning {0} binaries...", StringUtils.FormatList(TargetDescriptors.Select(x => x.Name).Distinct()));

            // Loop through all the targets, and clean them all
            HashSet <FileReference>      FilesToDelete       = new HashSet <FileReference>();
            HashSet <DirectoryReference> DirectoriesToDelete = new HashSet <DirectoryReference>();

            foreach (TargetDescriptor TargetDescriptor in TargetDescriptors)
            {
                // Create the rules assembly
                RulesAssembly RulesAssembly = RulesCompiler.CreateTargetRulesAssembly(TargetDescriptor.ProjectFile, TargetDescriptor.Name, bSkipRulesCompile, BuildConfiguration.bUsePrecompiled, TargetDescriptor.ForeignPlugin);

                // Create the rules object
                ReadOnlyTargetRules Target = new ReadOnlyTargetRules(RulesAssembly.CreateTargetRules(TargetDescriptor.Name, TargetDescriptor.Platform, TargetDescriptor.Configuration, TargetDescriptor.Architecture, TargetDescriptor.ProjectFile, TargetDescriptor.AdditionalArguments));

                // Find the base folders that can contain binaries
                List <DirectoryReference> BaseDirs = new List <DirectoryReference>();
                BaseDirs.Add(UnrealBuildTool.EngineDirectory);
                BaseDirs.Add(UnrealBuildTool.EnterpriseDirectory);
                foreach (FileReference Plugin in Plugins.EnumeratePlugins(Target.ProjectFile))
                {
                    BaseDirs.Add(Plugin.Directory);
                }
                if (Target.ProjectFile != null)
                {
                    BaseDirs.Add(Target.ProjectFile.Directory);
                }

                // If we're running a precompiled build, remove anything under the engine folder
                BaseDirs.RemoveAll(x => RulesAssembly.IsReadOnly(x));

                // Get all the names which can prefix build products
                List <string> NamePrefixes = new List <string>();
                if (Target.Type != TargetType.Program)
                {
                    NamePrefixes.Add(UEBuildTarget.GetAppNameForTargetType(Target.Type));
                }
                NamePrefixes.Add(Target.Name);

                // Get the suffixes for this configuration
                List <string> NameSuffixes = new List <string>();
                if (Target.Configuration == Target.UndecoratedConfiguration)
                {
                    NameSuffixes.Add("");
                }
                NameSuffixes.Add(String.Format("-{0}-{1}", Target.Platform.ToString(), Target.Configuration.ToString()));
                if (!String.IsNullOrEmpty(Target.Architecture))
                {
                    NameSuffixes.AddRange(NameSuffixes.ToArray().Select(x => x + Target.Architecture));
                }

                // Add all the makefiles and caches to be deleted
                FilesToDelete.Add(TargetMakefile.GetLocation(Target.ProjectFile, Target.Name, Target.Platform, Target.Configuration));
                FilesToDelete.UnionWith(SourceFileMetadataCache.GetFilesToClean(Target.ProjectFile));
                FilesToDelete.UnionWith(ActionHistory.GetFilesToClean(Target.ProjectFile, Target.Name, Target.Platform, Target.Type));

                // Add all the intermediate folders to be deleted
                foreach (DirectoryReference BaseDir in BaseDirs)
                {
                    foreach (string NamePrefix in NamePrefixes)
                    {
                        DirectoryReference GeneratedCodeDir = DirectoryReference.Combine(BaseDir, "Intermediate", "Build", Target.Platform.ToString(), NamePrefix, "Inc");
                        if (DirectoryReference.Exists(GeneratedCodeDir))
                        {
                            DirectoriesToDelete.Add(GeneratedCodeDir);
                        }

                        DirectoryReference IntermediateDir = DirectoryReference.Combine(BaseDir, "Intermediate", "Build", Target.Platform.ToString(), NamePrefix, Target.Configuration.ToString());
                        if (DirectoryReference.Exists(IntermediateDir))
                        {
                            DirectoriesToDelete.Add(IntermediateDir);
                        }
                    }
                }

                // List of additional files and directories to clean, specified by the target platform
                List <FileReference>      AdditionalFilesToDelete       = new List <FileReference>();
                List <DirectoryReference> AdditionalDirectoriesToDelete = new List <DirectoryReference>();

                // Add all the build products from this target
                string[] NamePrefixesArray = NamePrefixes.Distinct().ToArray();
                string[] NameSuffixesArray = NameSuffixes.Distinct().ToArray();
                foreach (DirectoryReference BaseDir in BaseDirs)
                {
                    DirectoryReference BinariesDir = DirectoryReference.Combine(BaseDir, "Binaries", Target.Platform.ToString());
                    if (DirectoryReference.Exists(BinariesDir))
                    {
                        UEBuildPlatform.GetBuildPlatform(Target.Platform).FindBuildProductsToClean(BinariesDir, NamePrefixesArray, NameSuffixesArray, AdditionalFilesToDelete, AdditionalDirectoriesToDelete);
                    }
                }

                // Get all the additional intermediate folders created by this platform
                UEBuildPlatform.GetBuildPlatform(Target.Platform).FindAdditionalBuildProductsToClean(Target, AdditionalFilesToDelete, AdditionalDirectoriesToDelete);

                // Add the platform's files and directories to the main list
                FilesToDelete.UnionWith(AdditionalFilesToDelete);
                DirectoriesToDelete.UnionWith(AdditionalDirectoriesToDelete);
            }

            // Delete all the directories, then all the files. By sorting the list of directories before we delete them, we avoid spamming the log if a parent directory is deleted first.
            foreach (DirectoryReference DirectoryToDelete in DirectoriesToDelete.OrderBy(x => x.FullName))
            {
                if (DirectoryReference.Exists(DirectoryToDelete))
                {
                    Log.TraceVerbose("    Deleting {0}{1}...", DirectoryToDelete, Path.DirectorySeparatorChar);
                    try
                    {
                        DirectoryReference.Delete(DirectoryToDelete, true);
                    }
                    catch (Exception Ex)
                    {
                        throw new BuildException(Ex, "Unable to delete {0} ({1})", DirectoryToDelete, Ex.Message.TrimEnd());
                    }
                }
            }

            foreach (FileReference FileToDelete in FilesToDelete.OrderBy(x => x.FullName))
            {
                if (FileReference.Exists(FileToDelete))
                {
                    Log.TraceVerbose("    Deleting " + FileToDelete);
                    try
                    {
                        FileReference.Delete(FileToDelete);
                    }
                    catch (Exception Ex)
                    {
                        throw new BuildException(Ex, "Unable to delete {0} ({1})", FileToDelete, Ex.Message.TrimEnd());
                    }
                }
            }

            // Also clean all the remote targets
            for (int Idx = 0; Idx < TargetDescriptors.Count; Idx++)
            {
                TargetDescriptor TargetDescriptor = TargetDescriptors[Idx];
                if (RemoteMac.HandlesTargetPlatform(TargetDescriptor.Platform))
                {
                    RemoteMac RemoteMac = new RemoteMac(TargetDescriptor.ProjectFile);
                    RemoteMac.Clean(TargetDescriptor);
                }
            }

            return(0);
        }
        /// <summary>
        /// Creates a target rules object for the specified target name.
        /// </summary>
        /// <param name="TargetName">Name of the target</param>
        /// <param name="Target">Information about the target associated with this target</param>
        /// <param name="TargetFileName">The original source file name of the Target.cs file for this target</param>
        /// <returns>The build target rules for the specified target</returns>
        public TargetRules CreateTargetRules(string TargetName, TargetInfo Target, bool bInEditorRecompile, out FileReference TargetFileName)
        {
            // Make sure the target file is known to us
            bool bFoundTargetName = TargetNameToTargetFile.ContainsKey(TargetName);

            if (bFoundTargetName == false)
            {
                if (Parent == null)
                {
                    //				throw new BuildException("Couldn't find target rules file for target '{0}' in rules assembly '{1}'.", TargetName, RulesAssembly.FullName);
                    string ExceptionMessage = "Couldn't find target rules file for target '";
                    ExceptionMessage += TargetName;
                    ExceptionMessage += "' in rules assembly '";
                    ExceptionMessage += CompiledAssembly.FullName;
                    ExceptionMessage += "'." + Environment.NewLine;

                    ExceptionMessage += "Location: " + CompiledAssembly.Location + Environment.NewLine;

                    ExceptionMessage += "Target rules found:" + Environment.NewLine;
                    foreach (KeyValuePair <string, FileReference> entry in TargetNameToTargetFile)
                    {
                        ExceptionMessage += "\t" + entry.Key + " - " + entry.Value + Environment.NewLine;
                    }

                    throw new BuildException(ExceptionMessage);
                }
                else
                {
                    return(Parent.CreateTargetRules(TargetName, Target, bInEditorRecompile, out TargetFileName));
                }
            }

            // Return the target file name to the caller
            TargetFileName = TargetNameToTargetFile[TargetName];

            // Currently, we expect the user's rules object type name to be the same as the module name + 'Target'
            string TargetTypeName = TargetName + "Target";

            // The build module must define a type named '<TargetName>Target' that derives from our 'TargetRules' type.
            TargetRules RulesObject = CreateTargetRulesInstance(TargetTypeName, Target);

            if (bInEditorRecompile)
            {
                // Make sure this is an editor module.
                if (RulesObject != null)
                {
                    if (RulesObject.Type != TargetRules.TargetType.Editor)
                    {
                        // Not the editor... determine the editor project
                        string TargetSourceFolderString = TargetFileName.FullName;
                        Int32  SourceFolderIndex        = -1;
                        if (Utils.IsRunningOnMono)
                        {
                            TargetSourceFolderString = TargetSourceFolderString.Replace("\\", "/");
                            SourceFolderIndex        = TargetSourceFolderString.LastIndexOf("/Source/", StringComparison.InvariantCultureIgnoreCase);
                        }
                        else
                        {
                            TargetSourceFolderString = TargetSourceFolderString.Replace("/", "\\");
                            SourceFolderIndex        = TargetSourceFolderString.LastIndexOf("\\Source\\", StringComparison.InvariantCultureIgnoreCase);
                        }
                        if (SourceFolderIndex != -1)
                        {
                            DirectoryReference TargetSourceFolder = new DirectoryReference(TargetSourceFolderString.Substring(0, SourceFolderIndex + 7));
                            foreach (KeyValuePair <string, FileReference> CheckEntry in TargetNameToTargetFile)
                            {
                                if (CheckEntry.Value.IsUnderDirectory(TargetSourceFolder))
                                {
                                    if (CheckEntry.Key.Equals(TargetName, StringComparison.InvariantCultureIgnoreCase) == false)
                                    {
                                        // We have found a target in the same source folder that is not the original target found.
                                        // See if it is the editor project
                                        string      CheckTargetTypeName = CheckEntry.Key + "Target";
                                        TargetRules CheckRulesObject    = CreateTargetRulesInstance(CheckTargetTypeName, Target);
                                        if (CheckRulesObject != null)
                                        {
                                            if (CheckRulesObject.Type == TargetRules.TargetType.Editor)
                                            {
                                                // Found it
                                                // NOTE: This prevents multiple Editor targets from co-existing...
                                                RulesObject = CheckRulesObject;
                                                break;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            return(RulesObject);
        }
Beispiel #6
0
        /// <summary>
        /// Build a target remotely
        /// </summary>
        /// <param name="TargetDesc">Descriptor for the target to build</param>
        /// <param name="RemoteLogFile">Path to store the remote log file</param>
        /// <returns>True if the build succeeded, false otherwise</returns>
        public bool Build(TargetDescriptor TargetDesc, FileReference RemoteLogFile)
        {
            // Get the directory for working files
            DirectoryReference BaseDir = DirectoryReference.FromFile(TargetDesc.ProjectFile) ?? UnrealBuildTool.EngineDirectory;
            DirectoryReference TempDir = DirectoryReference.Combine(BaseDir, "Intermediate", "Remote", TargetDesc.Name, TargetDesc.Platform.ToString(), TargetDesc.Configuration.ToString());

            DirectoryReference.CreateDirectory(TempDir);

            bool bLogIsMapped = false;

            foreach (RemoteMapping Mapping in Mappings)
            {
                if (RemoteLogFile.Directory.FullName.Equals(Mapping.LocalDirectory.FullName, StringComparison.InvariantCultureIgnoreCase))
                {
                    bLogIsMapped = true;
                    break;
                }
            }
            if (!bLogIsMapped)
            {
                Mappings.Add(new RemoteMapping(RemoteLogFile.Directory, GetRemotePath(RemoteLogFile.Directory)));
            }

            // Compile the rules assembly
            RulesAssembly RulesAssembly = RulesCompiler.CreateTargetRulesAssembly(TargetDesc.ProjectFile, TargetDesc.Name, false, false, TargetDesc.ForeignPlugin);

            // Create the target rules
            TargetRules Rules = RulesAssembly.CreateTargetRules(TargetDesc.Name, TargetDesc.Platform, TargetDesc.Configuration, TargetDesc.Architecture, TargetDesc.ProjectFile, new ReadOnlyBuildVersion(BuildVersion.ReadDefault()), new string[0]);

            // Check if we need to enable a nativized plugin, and compile the assembly for that if we do
            FileReference NativizedPluginFile = Rules.GetNativizedPlugin();

            if (NativizedPluginFile != null)
            {
                RulesAssembly = RulesCompiler.CreatePluginRulesAssembly(NativizedPluginFile, false, RulesAssembly, false);
            }

            // Path to the local manifest file. This has to be translated from the remote format after the build is complete.
            List <FileReference> LocalManifestFiles = new List <FileReference>();

            // Path to the remote manifest file
            FileReference RemoteManifestFile = FileReference.Combine(TempDir, "Manifest.xml");

            // Prepare the arguments we will pass to the remote build
            List <string> RemoteArguments = new List <string>();

            RemoteArguments.Add(TargetDesc.Name);
            RemoteArguments.Add(TargetDesc.Platform.ToString());
            RemoteArguments.Add(TargetDesc.Configuration.ToString());
            RemoteArguments.Add("-SkipRulesCompile");                                                      // Use the rules assembly built locally
            RemoteArguments.Add(String.Format("-XmlConfigCache={0}", GetRemotePath(XmlConfig.CacheFile))); // Use the XML config cache built locally, since the remote won't have it
            RemoteArguments.Add(String.Format("-Log={0}", GetRemotePath(RemoteLogFile)));
            RemoteArguments.Add(String.Format("-Manifest={0}", GetRemotePath(RemoteManifestFile)));

            if (TargetDesc.ProjectFile != null)
            {
                RemoteArguments.Add(String.Format("-Project={0}", GetRemotePath(TargetDesc.ProjectFile)));
            }

            foreach (string LocalArgument in TargetDesc.AdditionalArguments)
            {
                int EqualsIdx = LocalArgument.IndexOf('=');
                if (EqualsIdx == -1)
                {
                    RemoteArguments.Add(LocalArgument);
                    continue;
                }

                string Key   = LocalArgument.Substring(0, EqualsIdx);
                string Value = LocalArgument.Substring(EqualsIdx + 1);

                if (Key.Equals("-Log", StringComparison.InvariantCultureIgnoreCase))
                {
                    // We are already writing to the local log file. The remote will produce a different log (RemoteLogFile)
                    continue;
                }
                if (Key.Equals("-Manifest", StringComparison.InvariantCultureIgnoreCase))
                {
                    LocalManifestFiles.Add(new FileReference(Value));
                    continue;
                }

                string RemoteArgument = LocalArgument;
                foreach (RemoteMapping Mapping in Mappings)
                {
                    if (Value.StartsWith(Mapping.LocalDirectory.FullName, StringComparison.InvariantCultureIgnoreCase))
                    {
                        RemoteArgument = String.Format("{0}={1}", Key, GetRemotePath(Value));
                        break;
                    }
                }
                RemoteArguments.Add(RemoteArgument);
            }

            // Handle any per-platform setup that is required
            if (TargetDesc.Platform == UnrealTargetPlatform.IOS || TargetDesc.Platform == UnrealTargetPlatform.TVOS)
            {
                // Always generate a .stub
                RemoteArguments.Add("-CreateStub");

                // Cannot use makefiles, since we need PostBuildSync() to generate the IPA (and that requires a TargetRules instance)
                RemoteArguments.Add("-NoUBTMakefiles");

                // Get the provisioning data for this project
                IOSProvisioningData ProvisioningData = ((IOSPlatform)UEBuildPlatform.GetBuildPlatform(TargetDesc.Platform)).ReadProvisioningData(TargetDesc.ProjectFile);
                if (ProvisioningData == null || ProvisioningData.MobileProvisionFile == null)
                {
                    throw new BuildException("Unable to find mobile provision for {0}. See log for more information.", TargetDesc.Name);
                }

                // Create a local copy of the provision
                FileReference MobileProvisionFile = FileReference.Combine(TempDir, ProvisioningData.MobileProvisionFile.GetFileName());
                if (FileReference.Exists(MobileProvisionFile))
                {
                    FileReference.SetAttributes(MobileProvisionFile, FileAttributes.Normal);
                }
                FileReference.Copy(ProvisioningData.MobileProvisionFile, MobileProvisionFile, true);
                Log.TraceInformation("[Remote] Uploading {0}", MobileProvisionFile);
                UploadFile(MobileProvisionFile);

                // Extract the certificate for the project. Try to avoid calling IPP if we already have it.
                FileReference CertificateFile = FileReference.Combine(TempDir, "Certificate.p12");

                FileReference CertificateInfoFile     = FileReference.Combine(TempDir, "Certificate.txt");
                string        CertificateInfoContents = String.Format("{0}\n{1}", ProvisioningData.MobileProvisionFile, FileReference.GetLastWriteTimeUtc(ProvisioningData.MobileProvisionFile).Ticks);

                if (!FileReference.Exists(CertificateFile) || !FileReference.Exists(CertificateInfoFile) || FileReference.ReadAllText(CertificateInfoFile) != CertificateInfoContents)
                {
                    Log.TraceInformation("[Remote] Exporting certificate for {0}...", ProvisioningData.MobileProvisionFile);

                    StringBuilder Arguments = new StringBuilder("ExportCertificate");
                    if (TargetDesc.ProjectFile == null)
                    {
                        Arguments.AppendFormat(" \"{0}\"", UnrealBuildTool.EngineSourceDirectory);
                    }
                    else
                    {
                        Arguments.AppendFormat(" \"{0}\"", TargetDesc.ProjectFile.Directory);
                    }
                    Arguments.AppendFormat(" -provisionfile \"{0}\"", ProvisioningData.MobileProvisionFile);
                    Arguments.AppendFormat(" -outputcertificate \"{0}\"", CertificateFile);
                    if (TargetDesc.Platform == UnrealTargetPlatform.TVOS)
                    {
                        Arguments.Append(" -tvos");
                    }

                    ProcessStartInfo StartInfo = new ProcessStartInfo();
                    StartInfo.FileName  = FileReference.Combine(UnrealBuildTool.EngineDirectory, "Binaries", "DotNET", "IOS", "IPhonePackager.exe").FullName;
                    StartInfo.Arguments = Arguments.ToString();
                    if (Utils.RunLocalProcessAndLogOutput(StartInfo) != 0)
                    {
                        throw new BuildException("IphonePackager failed.");
                    }

                    FileReference.WriteAllText(CertificateInfoFile, CertificateInfoContents);
                }

                // Upload the certificate to the remote
                Log.TraceInformation("[Remote] Uploading {0}", CertificateFile);
                UploadFile(CertificateFile);

                // Tell the remote UBT instance to use them
                RemoteArguments.Add(String.Format("-ImportProvision={0}", GetRemotePath(MobileProvisionFile)));
                RemoteArguments.Add(String.Format("-ImportCertificate={0}", GetRemotePath(CertificateFile)));
                RemoteArguments.Add(String.Format("-ImportCertificatePassword=A"));
            }

            // Upload the workspace files
            UploadWorkspace(TempDir);

            // Fixup permissions on any shell scripts
            Execute(RemoteBaseDir, String.Format("chmod +x {0}/Build/BatchFiles/Mac/*.sh", EscapeShellArgument(GetRemotePath(UnrealBuildTool.EngineDirectory))));

            // Execute the compile
            Log.TraceInformation("[Remote] Executing build");

            StringBuilder BuildCommandLine = new StringBuilder("Engine/Build/BatchFiles/Mac/Build.sh");

            foreach (string RemoteArgument in RemoteArguments)
            {
                BuildCommandLine.AppendFormat(" {0}", EscapeShellArgument(RemoteArgument));
            }

            int Result = Execute(GetRemotePath(UnrealBuildTool.RootDirectory), BuildCommandLine.ToString());

            if (Result != 0)
            {
                if (RemoteLogFile != null)
                {
                    Log.TraceInformation("[Remote] Downloading {0}", RemoteLogFile);
                    DownloadFile(RemoteLogFile);
                }
                return(false);
            }

            // Download the manifest
            Log.TraceInformation("[Remote] Downloading {0}", RemoteManifestFile);
            DownloadFile(RemoteManifestFile);

            // Convert the manifest to local form
            BuildManifest Manifest = Utils.ReadClass <BuildManifest>(RemoteManifestFile.FullName);

            for (int Idx = 0; Idx < Manifest.BuildProducts.Count; Idx++)
            {
                Manifest.BuildProducts[Idx] = GetLocalPath(Manifest.BuildProducts[Idx]).FullName;
            }

            // Download the files from the remote
            if (TargetDesc.AdditionalArguments.Any(x => x.Equals("-GenerateManifest", StringComparison.InvariantCultureIgnoreCase)))
            {
                LocalManifestFiles.Add(FileReference.Combine(UnrealBuildTool.EngineDirectory, "Intermediate", "Build", "Manifest.xml"));
            }
            else
            {
                Log.TraceInformation("[Remote] Downloading build products");

                List <FileReference> FilesToDownload = new List <FileReference>();
                FilesToDownload.Add(RemoteLogFile);
                FilesToDownload.AddRange(Manifest.BuildProducts.Select(x => new FileReference(x)));
                DownloadFiles(FilesToDownload);
            }

            // Write out all the local manifests
            foreach (FileReference LocalManifestFile in LocalManifestFiles)
            {
                Log.TraceInformation("[Remote] Writing {0}", LocalManifestFile);
                Utils.WriteClass <BuildManifest>(Manifest, LocalManifestFile.FullName, "");
            }
            return(true);
        }
Beispiel #7
0
        private void AddProjectsForAllTargets(
            PlatformProjectGeneratorCollection PlatformProjectGenerators,
            List <FileReference> AllGames,
            out ProjectFile EngineProject,
            out List <ProjectFile> GameProjects,
            out Dictionary <FileReference, ProjectFile> ProgramProjects)
        {
            // As we're creating project files, we'll also keep track of whether we created an "engine" project and return that if we have one
            EngineProject   = null;
            GameProjects    = new List <ProjectFile>();
            ProgramProjects = new Dictionary <FileReference, ProjectFile>();

            // Find all of the target files.  This will filter out any modules or targets that don't
            // belong to platforms we're generating project files for.
            List <FileReference> AllTargetFiles = DiscoverTargets(AllGames);

            // Sort the targets by name. When we have multiple targets of a given type for a project, we'll use the order to determine which goes in the primary project file (so that client names with a suffix will go into their own project).
            AllTargetFiles = AllTargetFiles.OrderBy(x => x.FullName, StringComparer.OrdinalIgnoreCase).ToList();

            foreach (FileReference TargetFilePath in AllTargetFiles)
            {
                string TargetName = TargetFilePath.GetFileNameWithoutAnyExtensions();

                // Check to see if this is an Engine target.  That is, the target is located under the "Engine" folder
                bool IsEngineTarget           = false;
                bool IsEnterpriseTarget       = false;
                bool WantProjectFileForTarget = true;
                if (TargetFilePath.IsUnderDirectory(UnrealBuildTool.EngineDirectory))
                {
                    // This is an engine target
                    IsEngineTarget = true;

                    if (TargetFilePath.IsUnderDirectory(EngineSourceProgramsDirectory))
                    {
                        WantProjectFileForTarget = IncludeEnginePrograms;
                    }
                    else if (TargetFilePath.IsUnderDirectory(UnrealBuildTool.EngineSourceDirectory))
                    {
                        WantProjectFileForTarget = bIncludeEngineSource;
                    }
                }
                else if (TargetFilePath.IsUnderDirectory(UnrealBuildTool.EnterpriseSourceDirectory))
                {
                    // This is an enterprise target
                    IsEnterpriseTarget = true;

                    if (TargetFilePath.IsUnderDirectory(EnterpriseSourceProgramsDirectory))
                    {
                        WantProjectFileForTarget = bIncludeEnterpriseSource && IncludeEnginePrograms;
                    }
                    else
                    {
                        WantProjectFileForTarget = bIncludeEnterpriseSource;
                    }
                }

                if (WantProjectFileForTarget)
                {
                    RulesAssembly RulesAssembly;

                    FileReference CheckProjectFile =
                        AllGames.FirstOrDefault(x => TargetFilePath.IsUnderDirectory(x.Directory));
                    if (CheckProjectFile == null)
                    {
                        if (TargetFilePath.IsUnderDirectory(UnrealBuildTool.EnterpriseDirectory))
                        {
                            RulesAssembly = RulesCompiler.CreateEnterpriseRulesAssembly(false, false);
                        }
                        else
                        {
                            RulesAssembly = RulesCompiler.CreateEngineRulesAssembly(false, false);
                        }
                    }
                    else
                    {
                        RulesAssembly = RulesCompiler.CreateProjectRulesAssembly(CheckProjectFile, false, false);
                    }

                    // Create target rules for all of the platforms and configuration combinations that we want to enable support for.
                    // Just use the current platform as we only need to recover the target type and both should be supported for all targets...
                    TargetRules TargetRulesObject = RulesAssembly.CreateTargetRules(TargetName,
                                                                                    BuildHostPlatform.Current.Platform, UnrealTargetConfiguration.Development, "", CheckProjectFile,
                                                                                    null);

                    bool IsProgramTarget = false;

                    DirectoryReference GameFolder = null;
                    string             ProjectFileNameBase;
                    if (TargetRulesObject.Type == TargetType.Program)
                    {
                        IsProgramTarget     = true;
                        ProjectFileNameBase = TargetName;
                    }
                    else if (IsEngineTarget)
                    {
                        ProjectFileNameBase = EngineProjectFileNameBase;
                    }
                    else if (IsEnterpriseTarget)
                    {
                        ProjectFileNameBase = EnterpriseProjectFileNameBase;
                    }
                    else
                    {
                        // Figure out which game project this target belongs to
                        FileReference ProjectInfo = FindGameContainingFile(AllGames, TargetFilePath);
                        if (ProjectInfo == null)
                        {
                            throw new BuildException("Found a non-engine target file (" + TargetFilePath +
                                                     ") that did not exist within any of the known game folders");
                        }

                        GameFolder          = ProjectInfo.Directory;
                        ProjectFileNameBase = ProjectInfo.GetFileNameWithoutExtension();
                    }

                    // Get the suffix to use for this project file. If we have multiple targets of the same type, we'll have to split them out into separate IDE project files.
                    string GeneratedProjectName = TargetRulesObject.GeneratedProjectName;
                    if (GeneratedProjectName == null)
                    {
                        ProjectFile ExistingProjectFile;
                        if (ProjectFileMap.TryGetValue(GetRiderProjectLocation(ProjectFileNameBase), out ExistingProjectFile) &&
                            ExistingProjectFile.ProjectTargets.Any(x => x.TargetRules.Type == TargetRulesObject.Type))
                        {
                            GeneratedProjectName = TargetRulesObject.Name;
                        }
                        else
                        {
                            GeneratedProjectName = ProjectFileNameBase;
                        }
                    }

                    FileReference ProjectFilePath = GetRiderProjectLocation(GeneratedProjectName);
                    if (TargetRulesObject.Type == TargetType.Game || TargetRulesObject.Type == TargetType.Client ||
                        TargetRulesObject.Type == TargetType.Server)
                    {
                        // Allow platforms to generate stub projects here...
                        PlatformProjectGenerators.GenerateGameProjectStubs(
                            InGenerator: this,
                            InTargetName: TargetName,
                            InTargetFilepath: TargetFilePath.FullName,
                            InTargetRules: TargetRulesObject,
                            InPlatforms: SupportedPlatforms,
                            InConfigurations: SupportedConfigurations);
                    }

                    DirectoryReference BaseFolder;
                    if (IsProgramTarget)
                    {
                        BaseFolder = TargetFilePath.Directory;
                    }
                    else if (IsEngineTarget)
                    {
                        BaseFolder = UnrealBuildTool.EngineDirectory;
                    }
                    else if (IsEnterpriseTarget)
                    {
                        BaseFolder = UnrealBuildTool.EnterpriseDirectory;
                    }
                    else
                    {
                        BaseFolder = GameFolder;
                    }

                    bool        bProjectAlreadyExisted;
                    ProjectFile ProjectFile = FindOrAddProject(ProjectFilePath, BaseFolder,
                                                               true, out bProjectAlreadyExisted);
                    ProjectFile.IsForeignProject =
                        CheckProjectFile != null && !NativeProjects.IsNativeProject(CheckProjectFile);
                    ProjectFile.IsGeneratedProject = true;
                    ProjectFile.IsStubProject      = UnrealBuildTool.IsProjectInstalled();
                    if (TargetRulesObject.bBuildInSolutionByDefault.HasValue)
                    {
                        ProjectFile.ShouldBuildByDefaultForSolutionTargets =
                            TargetRulesObject.bBuildInSolutionByDefault.Value;
                    }

                    // Add the project to the right output list
                    if (IsProgramTarget)
                    {
                        ProgramProjects[TargetFilePath] = ProjectFile;
                    }
                    else if (IsEngineTarget)
                    {
                        EngineProject = ProjectFile;
                        if (UnrealBuildTool.IsEngineInstalled())
                        {
                            // Allow engine projects to be created but not built for Installed Engine builds
                            EngineProject.IsForeignProject   = false;
                            EngineProject.IsGeneratedProject = true;
                            EngineProject.IsStubProject      = true;
                        }
                    }
                    else if (IsEnterpriseTarget)
                    {
                        ProjectFile EnterpriseProject = ProjectFile;
                        if (UnrealBuildTool.IsEnterpriseInstalled())
                        {
                            // Allow enterprise projects to be created but not built for Installed Engine builds
                            EnterpriseProject.IsForeignProject   = false;
                            EnterpriseProject.IsGeneratedProject = true;
                            EnterpriseProject.IsStubProject      = true;
                        }
                    }
                    else
                    {
                        if (!bProjectAlreadyExisted)
                        {
                            GameProjects.Add(ProjectFile);

                            // Add the .uproject file for this game/template
                            FileReference UProjectFilePath =
                                FileReference.Combine(BaseFolder, ProjectFileNameBase + ".uproject");
                            if (FileReference.Exists(UProjectFilePath))
                            {
                                ProjectFile.AddFileToProject(UProjectFilePath, BaseFolder);
                            }
                            else
                            {
                                throw new BuildException(
                                          "Not expecting to find a game with no .uproject file.  File '{0}' doesn't exist",
                                          UProjectFilePath);
                            }
                        }
                    }

                    foreach (ProjectTarget ExistingProjectTarget in ProjectFile.ProjectTargets)
                    {
                        if (ExistingProjectTarget.TargetRules.Type == TargetRulesObject.Type)
                        {
                            throw new BuildException(
                                      "Not expecting project {0} to already have a target rules of with configuration name {1} ({2}) while trying to add: {3}",
                                      ProjectFilePath, TargetRulesObject.Type.ToString(),
                                      ExistingProjectTarget.TargetRules.ToString(), TargetRulesObject.ToString());
                        }

                        // Not expecting to have both a game and a program in the same project.  These would alias because we share the project and solution configuration names (just because it makes sense to)
                        if ((ExistingProjectTarget.TargetRules.Type == TargetType.Game &&
                             TargetRulesObject.Type == TargetType.Program) ||
                            (ExistingProjectTarget.TargetRules.Type == TargetType.Program &&
                             TargetRulesObject.Type == TargetType.Game))
                        {
                            throw new BuildException(
                                      "Not expecting project {0} to already have a Game/Program target ({1}) associated with it while trying to add: {2}",
                                      ProjectFilePath, ExistingProjectTarget.TargetRules.ToString(),
                                      TargetRulesObject.ToString());
                        }
                    }

                    ProjectTarget ProjectTarget = new ProjectTarget()
                    {
                        TargetRules           = TargetRulesObject,
                        TargetFilePath        = TargetFilePath,
                        ProjectFilePath       = ProjectFilePath,
                        UnrealProjectFilePath = CheckProjectFile,
                        SupportedPlatforms    = TargetRulesObject.GetSupportedPlatforms()
                                                .Where(x => UEBuildPlatform.GetBuildPlatform(x, true) != null).ToArray(),
                        CreateRulesDelegate = (Platform, Configuration) =>
                                              RulesAssembly.CreateTargetRules(TargetName, Platform, Configuration, "", CheckProjectFile,
                                                                              null)
                    };

                    ProjectFile.ProjectTargets.Add(ProjectTarget);

                    // Make sure the *.Target.cs file is in the project.
                    ProjectFile.AddFileToProject(TargetFilePath, BaseFolder);

                    Log.TraceVerbose("Generating target {0} for {1}", TargetRulesObject.Type.ToString(),
                                     ProjectFilePath);
                }
            }
        }