/// <summary> /// Execute the mode /// </summary> /// <param name="Arguments">Command line arguments</param> /// <returns></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); // Ensure the path to the output file is valid if (OutputFile == null) { OutputFile = GetDefaultOutputFile(ProjectFile); } // Create the rules assembly RulesAssembly Assembly; if (ProjectFile == null) { Assembly = RulesCompiler.CreateEnterpriseRulesAssembly(BuildConfiguration.bUsePrecompiled, BuildConfiguration.bSkipRulesCompile); } else { Assembly = RulesCompiler.CreateProjectRulesAssembly(ProjectFile, BuildConfiguration.bUsePrecompiled, BuildConfiguration.bSkipRulesCompile); } // Write information about these targets WriteTargetInfo(ProjectFile, Assembly, OutputFile, Arguments); Log.TraceInformation("Written {0}", OutputFile); return(0); }
public override bool PrepTargetForDeployment(UEBuildTarget InTarget) { string InAppName = InTarget.AppName; Log.TraceInformation("Prepping {0} for deployment to {1}", InAppName, InTarget.Platform.ToString()); System.DateTime PrepDeployStartTime = DateTime.UtcNow; string TargetFilename = RulesCompiler.GetTargetFilename(InAppName); string ProjectSourceFolder = new FileInfo(TargetFilename).DirectoryName + "/"; string RelativeTargetDirectory; string EngineSourceRelativeBinaryPath; UWPProjectGenerator.GetTargetUWPPaths(InAppName, InTarget.Rules, out EngineSourceRelativeBinaryPath, out RelativeTargetDirectory); PrepForUATPackageOrDeploy(InAppName, InTarget.ProjectDirectory, InTarget.OutputPath, BuildConfiguration.RelativeEnginePath, false, ""); // TODO - richiem - restore this if we find that it's needed. //Log.TraceInformation("...copying the CELL dll..."); //string CELLPath = "../../../Engine/Source/" + UEBuildConfiguration.UEThirdPartySourceDirectory + "CELL/lib/win64/"; //string CELLPathRelease = CELLPath + "Release/"; //string CELLDllRelease = "CommonEventLoggingLibrary.dll"; //string CELLPathDebug = CELLPath + "Debug/"; //string CELLDllDebug = "CommonEventLoggingLibraryd.dll"; //CopyFile(EngineSourceRelativeBinaryPath + CELLPathRelease + CELLDllRelease, EngineSourceRelativeBinaryPath + CELLDllRelease, true); //CopyFile(EngineSourceRelativeBinaryPath + CELLPathDebug + CELLDllDebug, EngineSourceRelativeBinaryPath + CELLDllDebug, true); //string XSAPIPath = EngineSourceRelativeBinaryPath + "../../../Engine/Source/ThirdParty/XSAPI/lib/"; //string XboxServicesConfig = "xboxservices.config"; //string DesktopLogin = "******"; //Log.TraceInformation("...copying xboxservices.config"); //CopyFile(XSAPIPath + XboxServicesConfig, EngineSourceRelativeBinaryPath + XboxServicesConfig, true); //Log.TraceInformation("...copying DesktopLogin.exe..."); //CopyFile(XSAPIPath + DesktopLogin, EngineSourceRelativeBinaryPath + DesktopLogin, true); // TODO - richiem - restore this if we find that it's needed. //if (InTarget.Configuration == UnrealTargetConfiguration.Development) //{ // Log.TraceInformation("...copying AutoLogin..."); // string AutoLoginPath = EngineSourceRelativeBinaryPath + "../../../Engine/Source/Tools/AutoLogin/"; // string AutoLoginDLL = "AutoLogin.dll"; // string AutoLoginBat = "AutoLogin.bat"; // CopyFile(AutoLoginPath + "bin/Debug/" + AutoLoginDLL, EngineSourceRelativeBinaryPath + AutoLoginDLL, true); // CopyFile(AutoLoginPath + AutoLoginBat, EngineSourceRelativeBinaryPath + AutoLoginBat, true); //} // Log out the time taken to deploy... double PrepDeployDuration = (DateTime.UtcNow - PrepDeployStartTime).TotalSeconds; Log.TraceInformation("UWP deployment preparation took {0:0.00} seconds", PrepDeployDuration); return(true); }
public static void GetTargetUWPPaths(string InTargetName, TargetRules InTargetRules, out string OutEngineSourceRelativeBinaryPath, out string OutRelativeTargetPath) { OutEngineSourceRelativeBinaryPath = ""; OutRelativeTargetPath = ""; string TargetFilename = RulesCompiler.GetTargetFilename(InTargetName); string ProjectSourceFolder = new FileInfo(TargetFilename).DirectoryName; string EnginePath = Path.Combine(ProjectFileGenerator.EngineRelativePath); string EngineSourcePath = Path.Combine(EnginePath, "Source"); string RelativeTargetFilename = Utils.MakePathRelativeTo(TargetFilename, EngineSourcePath); if ((RelativeTargetFilename.StartsWith("..") == false) && (RelativeTargetFilename.Contains(":") == false)) { // This target must be UNDER Engine/Source... RelativeTargetFilename = Path.Combine(EngineSourcePath, RelativeTargetFilename); } RelativeTargetFilename = RelativeTargetFilename.Replace("\\", "/"); EnginePath = EnginePath.Replace("\\", "/"); Int32 LastSourceIdx = RelativeTargetFilename.LastIndexOf("Source"); if (LastSourceIdx != -1) { RelativeTargetFilename = RelativeTargetFilename.Substring(0, LastSourceIdx); } else { RelativeTargetFilename = ""; } OutRelativeTargetPath = RelativeTargetFilename; if (InTargetRules.bOutputToEngineBinaries) { RelativeTargetFilename = EnginePath; } OutEngineSourceRelativeBinaryPath = Path.Combine(RelativeTargetFilename, "Binaries/UWP/"); OutEngineSourceRelativeBinaryPath = OutEngineSourceRelativeBinaryPath.Replace("\\", "/"); }
/// <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> /// 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); // Compile the rules assembly RulesCompiler.CreateTargetRulesAssembly(TargetDesc.ProjectFile, TargetDesc.Name, false, false, TargetDesc.ForeignPlugin); // 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("-ForceXmlConfigCache"); // 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"); // 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 FileReference CertificateFile = FileReference.Combine(TempDir, "Certificate.p12"); if (!FileReference.Exists(CertificateFile)) { StringBuilder Arguments = new StringBuilder("ExportCertificate"); if (TargetDesc.ProjectFile == null) { Arguments.AppendFormat(" \"{0}\"", UnrealBuildTool.EngineSourceDirectory); } else { Arguments.AppendFormat(" \"{0}\"", TargetDesc.ProjectFile.Directory); } Arguments.AppendFormat(" -certificate \"{0}\"", CertificateFile); 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."); } } // 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 Log.TraceInformation("[Remote] Uploading 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); }
/// <summary> /// Parse a list of target descriptors from the command line /// </summary> /// <param name="Arguments">Command-line arguments</param> /// <param name="ProjectFile">The project file, if already set. May be updated if not.</param> /// <returns>List of target descriptors</returns> public static List <TargetDescriptor> ParseCommandLine(string[] Arguments, ref FileReference ProjectFile) { UnrealTargetPlatform Platform = UnrealTargetPlatform.Unknown; UnrealTargetConfiguration Configuration = UnrealTargetConfiguration.Unknown; List <string> TargetNames = new List <string>(); List <TargetType> TargetTypes = new List <TargetType>(); string Architecture = null; List <OnlyModule> OnlyModules = new List <OnlyModule>(); FileReference ForeignPlugin = null; string ForceReceiptFileName = null; // Settings for creating/using static libraries for the engine for (int ArgumentIndex = 0; ArgumentIndex < Arguments.Length; ArgumentIndex++) { string Argument = Arguments[ArgumentIndex]; if (!Argument.StartsWith("-")) { UnrealTargetPlatform ParsedPlatform; if (Enum.TryParse(Argument, true, out ParsedPlatform) && ParsedPlatform != UnrealTargetPlatform.Unknown) { if (Platform != UnrealTargetPlatform.Unknown) { throw new BuildException("Multiple platforms specified on command line (first {0}, then {1})", Platform, ParsedPlatform); } Platform = ParsedPlatform; continue; } UnrealTargetConfiguration ParsedConfiguration; if (Enum.TryParse(Argument, true, out ParsedConfiguration) && ParsedConfiguration != UnrealTargetConfiguration.Unknown) { if (Configuration != UnrealTargetConfiguration.Unknown) { throw new BuildException("Multiple configurations specified on command line (first {0}, then {1})", Configuration, ParsedConfiguration); } Configuration = ParsedConfiguration; continue; } // Make sure the target name is valid. It may be the path to a project file. if (Argument.IndexOfAny(new char[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar, '.' }) == -1) { TargetNames.Add(Argument); } } else { string Value; if (ParseArgumentValue(Argument, "-TargetType=", out Value)) { TargetType Type; if (!Enum.TryParse(Value, true, out Type)) { throw new BuildException("Invalid target type: '{0}'", Value); } TargetTypes.Add(Type); } else if (ParseArgumentValue(Argument, "-Module=", out Value)) { OnlyModules.Add(new OnlyModule(Value)); } else if (ParseArgumentValue(Argument, "-ModuleWithSuffix=", out Value)) { int SuffixIdx = Value.LastIndexOf(','); if (SuffixIdx == -1) { throw new BuildException("Missing suffix argument from -ModuleWithSuffix=Name,Suffix"); } OnlyModules.Add(new OnlyModule(Value.Substring(0, SuffixIdx), Value.Substring(SuffixIdx + 1))); } else if (ParseArgumentValue(Argument, "-Plugin=", out Value)) { if (ForeignPlugin != null) { throw new BuildException("Only one foreign plugin to compile may be specified per invocation"); } ForeignPlugin = new FileReference(Value); } else if (ParseArgumentValue(Argument, "-Receipt=", out Value)) { ForceReceiptFileName = Value; } else { switch (Arguments[ArgumentIndex].ToUpperInvariant()) { case "-MODULE": throw new BuildException("'-Module <Name>' syntax is no longer supported on the command line. Use '-Module=<Name>' instead."); case "-MODULEWITHSUFFIX": throw new BuildException("'-ModuleWithSuffix <Name> <Suffix>' syntax is no longer supported on the command line. Use '-Module=<Name>,<Suffix>' instead."); case "-PLUGIN": throw new BuildException("'-Plugin <Path>' syntax is no longer supported on the command line. Use '-Plugin=<Path>' instead."); case "-RECEIPT": throw new BuildException("'-Receipt <Path>' syntax is no longer supported on the command line. Use '-Receipt=<Path>' instead."); } } } } if (Platform == UnrealTargetPlatform.Unknown) { throw new BuildException("Couldn't find platform name."); } if (Configuration == UnrealTargetConfiguration.Unknown) { throw new BuildException("Couldn't determine configuration name."); } if (Architecture == null) { Architecture = UEBuildPlatform.GetBuildPlatform(Platform).GetDefaultArchitecture(ProjectFile); } // Create all the target descriptors for targets specified by type foreach (TargetType Type in TargetTypes) { if (ProjectFile == null) { throw new BuildException("-TargetType=... requires a project file to be specified"); } else { TargetNames.Add(RulesCompiler.CreateProjectRulesAssembly(ProjectFile).GetTargetNameByType(Type, Platform, Configuration, Architecture, ProjectFile, new ReadOnlyBuildVersion(BuildVersion.ReadDefault()))); } } // Create all the target descriptor List <TargetDescriptor> Targets = new List <TargetDescriptor>(); foreach (string TargetName in TargetNames) { // If a project file was not specified see if we can find one if (ProjectFile == null && UProjectInfo.TryGetProjectForTarget(TargetName, out ProjectFile)) { Log.TraceVerbose("Found project file for {0} - {1}", TargetName, ProjectFile); } TargetDescriptor Target = new TargetDescriptor(ProjectFile, TargetName, Platform, Configuration, Architecture); Target.OnlyModules = OnlyModules; Target.ForeignPlugin = ForeignPlugin; Target.ForceReceiptFileName = ForceReceiptFileName; Targets.Add(Target); } // Make sure we could parse something if (Targets.Count == 0) { throw new BuildException("No target name was specified on the command-line."); } return(Targets); }
/// <summary> /// Parse a list of target descriptors from the command line /// </summary> /// <param name="Arguments">Command-line arguments</param> /// <param name="bUsePrecompiled">Whether to use a precompiled engine distribution</param> /// <param name="bSkipRulesCompile">Whether to skip compiling rules assemblies</param> /// <param name="TargetDescriptors">List of target descriptors</param> public static void ParseSingleCommandLine(CommandLineArguments Arguments, bool bUsePrecompiled, bool bSkipRulesCompile, List <TargetDescriptor> TargetDescriptors) { List <UnrealTargetPlatform> Platforms = new List <UnrealTargetPlatform>(); List <UnrealTargetConfiguration> Configurations = new List <UnrealTargetConfiguration>(); List <string> TargetNames = new List <string>(); FileReference ProjectFile = Arguments.GetFileReferenceOrDefault("-Project=", null); // Settings for creating/using static libraries for the engine for (int ArgumentIndex = 0; ArgumentIndex < Arguments.Count; ArgumentIndex++) { string Argument = Arguments[ArgumentIndex]; if (Argument.Length > 0 && Argument[0] != '-') { // Mark this argument as used. We'll interpret it as one thing or another. Arguments.MarkAsUsed(ArgumentIndex); // Check if it's a project file argument if (Argument.EndsWith(".uproject", StringComparison.OrdinalIgnoreCase)) { FileReference NewProjectFile = new FileReference(Argument); if (ProjectFile != null && ProjectFile != NewProjectFile) { throw new BuildException("Multiple project files specified on command line (first {0}, then {1})", ProjectFile, NewProjectFile); } ProjectFile = new FileReference(Argument); continue; } // Split it into separate arguments string[] InlineArguments = Argument.Split('+'); // Try to parse them as platforms UnrealTargetPlatform ParsedPlatform; if (UnrealTargetPlatform.TryParse(InlineArguments[0], out ParsedPlatform)) { Platforms.Add(ParsedPlatform); for (int InlineArgumentIdx = 1; InlineArgumentIdx < InlineArguments.Length; InlineArgumentIdx++) { Platforms.Add(UnrealTargetPlatform.Parse(InlineArguments[InlineArgumentIdx])); } continue; } // Try to parse them as configurations UnrealTargetConfiguration ParsedConfiguration; if (Enum.TryParse(InlineArguments[0], true, out ParsedConfiguration)) { Configurations.Add(ParsedConfiguration); for (int InlineArgumentIdx = 1; InlineArgumentIdx < InlineArguments.Length; InlineArgumentIdx++) { string InlineArgument = InlineArguments[InlineArgumentIdx]; if (!Enum.TryParse(InlineArgument, true, out ParsedConfiguration)) { throw new BuildException("Invalid configuration '{0}'", InlineArgument); } Configurations.Add(ParsedConfiguration); } continue; } // Otherwise assume they are target names TargetNames.AddRange(InlineArguments); } } if (Platforms.Count == 0) { throw new BuildException("No platforms specified for target"); } if (Configurations.Count == 0) { throw new BuildException("No configurations specified for target"); } // Make sure the project file exists, and make sure we're using the correct case. if (ProjectFile != null) { FileInfo ProjectFileInfo = FileUtils.FindCorrectCase(ProjectFile.ToFileInfo()); if (!ProjectFileInfo.Exists) { throw new BuildException("Unable to find project '{0}'.", ProjectFile); } ProjectFile = new FileReference(ProjectFileInfo); } // Expand all the platforms, architectures and configurations foreach (UnrealTargetPlatform Platform in Platforms) { // Make sure the platform is valid if (!InstalledPlatformInfo.IsValid(null, Platform, null, EProjectType.Code, InstalledPlatformState.Downloaded)) { if (!InstalledPlatformInfo.IsValid(null, Platform, null, EProjectType.Code, InstalledPlatformState.Supported)) { throw new BuildException("The {0} platform is not supported from this engine distribution.", Platform); } else { throw new BuildException("Missing files required to build {0} targets. Enable {0} as an optional download component in the Epic Games Launcher.", Platform); } } // Parse the architecture parameter, or get the default for the platform List <string> Architectures = new List <string>(Arguments.GetValues("-Architecture=", '+')); if (Architectures.Count == 0) { Architectures.Add(UEBuildPlatform.GetBuildPlatform(Platform).GetDefaultArchitecture(ProjectFile)); } foreach (string Architecture in Architectures) { foreach (UnrealTargetConfiguration Configuration in Configurations) { // Create all the target descriptors for targets specified by type foreach (string TargetTypeString in Arguments.GetValues("-TargetType=")) { TargetType TargetType; if (!Enum.TryParse(TargetTypeString, out TargetType)) { throw new BuildException("Invalid target type '{0}'", TargetTypeString); } if (ProjectFile == null) { throw new BuildException("-TargetType=... requires a project file to be specified"); } else { TargetNames.Add(RulesCompiler.CreateProjectRulesAssembly(ProjectFile, bUsePrecompiled, bSkipRulesCompile).GetTargetNameByType(TargetType, Platform, Configuration, Architecture, ProjectFile)); } } // Make sure we could parse something if (TargetNames.Count == 0) { throw new BuildException("No target name was specified on the command-line."); } // Create all the target descriptors foreach (string TargetName in TargetNames) { // If a project file was not specified see if we can find one if (ProjectFile == null && NativeProjects.TryGetProjectForTarget(TargetName, out ProjectFile)) { Log.TraceVerbose("Found project file for {0} - {1}", TargetName, ProjectFile); } // Create the target descriptor TargetDescriptors.Add(new TargetDescriptor(ProjectFile, TargetName, Platform, Configuration, Architecture, Arguments)); } } } } }
/** * Find all third party and private header includes in public engine headers. **/ public static void FindThirdPartyIncludes(UnrealTargetPlatform Platform, UnrealTargetConfiguration Configuration) { Log.TraceInformation("Looking for third party header includes in public engine header files (this may take a few minutes)..."); TargetInfo Target = new TargetInfo(Platform, Configuration); List <string> UncheckedModules = new List <string>(); EngineHeaders = new List <Header>(); ThirdPartyHeaders = new List <Header>(); // Find all modules referenced by the current target List <string> ModuleFileNames = RulesCompiler.FindAllRulesSourceFiles(RulesCompiler.RulesFileType.Module, AdditionalSearchPaths: null); foreach (string ModuleFileName in ModuleFileNames) { string ModuleName = Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(ModuleFileName)); try { string UnusedModuleFilename; ModuleRules RulesObject = RulesCompiler.CreateModuleRules(ModuleName, Target, out UnusedModuleFilename); bool bEngineHeaders = RulesObject.Type != ModuleRules.ModuleType.External; foreach (string SystemIncludePath in RulesObject.PublicSystemIncludePaths) { FindHeaders(SystemIncludePath, bEngineHeaders ? EngineHeaders : ThirdPartyHeaders, bEngineHeaders); } foreach (string PublicIncludePath in RulesObject.PublicIncludePaths) { FindHeaders(PublicIncludePath, bEngineHeaders ? EngineHeaders : ThirdPartyHeaders, bEngineHeaders); } } catch (Exception) { // Ignore, some modules may fail here. UncheckedModules.Add(ModuleName); } } // Search for illegal includes. List <IncludePath> ThirdPartyIncludes = new List <IncludePath>(); List <IncludePath> PrivateIncludes = new List <IncludePath>(); CheckIfThirdPartyHeadersAreIncluded(ThirdPartyIncludes, PrivateIncludes); // List all of the included 3rd party headers unless their name matches with any of the engine header. if (ThirdPartyIncludes.Count > 0) { // Remove ambiguous headers for (int IncludeIndex = ThirdPartyIncludes.Count - 1; IncludeIndex >= 0; --IncludeIndex) { if (FindHeader(EngineHeaders, ThirdPartyIncludes[IncludeIndex].OtherHeader.Name) != null) { ThirdPartyIncludes.RemoveAt(IncludeIndex); } } if (ThirdPartyIncludes.Count > 0) { Log.TraceInformation("Warning: Found {0} third party header includes in public engine headers. Third party headers should only be included in private engine headers.", ThirdPartyIncludes.Count); foreach (IncludePath HeaderPath in ThirdPartyIncludes) { if (FindHeader(EngineHeaders, HeaderPath.OtherHeader.Name) == null) { Log.TraceInformation("{0} includes {1}.", HeaderPath.PublicHeaderPath, HeaderPath.OtherHeader.Path); } } } } // List all private engine headers included from public engine headers if (PrivateIncludes.Count > 0) { Log.TraceInformation("Warning: Found {0} private engine header includes in public engine headers. Private engine headers should not be included in public engine headers.", PrivateIncludes.Count); } foreach (IncludePath HeaderPath in PrivateIncludes) { Log.TraceInformation("{0} includes {1}.", HeaderPath.PublicHeaderPath, HeaderPath.OtherHeader.Path); } if (PrivateIncludes.Count == 0 && ThirdPartyIncludes.Count == 0) { Log.TraceInformation("Finished looking for third party includes. Nothing found."); } if (UncheckedModules.Count > 0) { Log.TraceInformation("Warning: The following modules could not be checked (exception while trying to create ModuleRules object):"); for (int ModuleIndex = 0; ModuleIndex < UncheckedModules.Count; ++ModuleIndex) { Log.TraceInformation(" {0}", UncheckedModules[ModuleIndex]); } } }
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); } } }