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