/// <summary> /// Deploys the given target /// </summary> /// <param name="Receipt">Receipt for the target being deployed</param> public override void Deploy(TargetReceipt Receipt) { // do not package data if building via UBT new UEDeployAndroid(Receipt.ProjectFile, false).PrepTargetForDeployment(Receipt); }
/// <summary> /// Creates a receipt for this binary. /// </summary> /// <param name="ToolChain">Toolchain for the target platform</param> /// <param name="BuildPlatform">Platform that we're building for</param> public virtual TargetReceipt MakeReceipt(IUEToolChain ToolChain) { TargetReceipt Receipt = new TargetReceipt(); // Get the type of build products we're creating BuildProductType Type = BuildProductType.RequiredResource; switch(Config.Type) { case UEBuildBinaryType.Executable: Type = BuildProductType.Executable; break; case UEBuildBinaryType.DynamicLinkLibrary: Type = BuildProductType.DynamicLibrary; break; case UEBuildBinaryType.StaticLibrary: Type = BuildProductType.StaticLibrary; break; } // Add the primary build products string DebugExtension = UEBuildPlatform.GetBuildPlatform(Target.Platform).GetDebugInfoExtension(Config.Type); foreach (string OutputFilePath in Config.OutputFilePaths) { AddBuildProductAndDebugFile(OutputFilePath, Type, DebugExtension, Receipt, ToolChain); } // Add the console app, if there is one if (Config.Type == UEBuildBinaryType.Executable && Config.bBuildAdditionalConsoleApp) { foreach (string OutputFilePath in Config.OutputFilePaths) { AddBuildProductAndDebugFile(GetAdditionalConsoleAppPath(OutputFilePath), Type, DebugExtension, Receipt, ToolChain); } } // Add any extra files from the toolchain ToolChain.AddFilesToReceipt(Receipt, this); return Receipt; }
public override bool PrepTargetForDeployment(TargetReceipt Receipt) { Log.TraceInformation("Deploying now!"); return(true); }
public void StageRuntimeDependenciesFromReceipt(TargetReceipt Receipt, bool RequireDependenciesToExist, bool bUsingPakFile) { // Patterns to exclude from wildcard searches. Any maps and assets must be cooked. List<string> ExcludePatterns = new List<string>(); ExcludePatterns.Add(".../*.umap"); ExcludePatterns.Add(".../*.uasset"); // Also stage any additional runtime dependencies, like ThirdParty DLLs foreach(RuntimeDependency RuntimeDependency in Receipt.RuntimeDependencies) { foreach(FileReference File in CommandUtils.ResolveFilespec(CommandUtils.RootDirectory, RuntimeDependency.Path, ExcludePatterns)) { // allow missing files if needed if ((RequireDependenciesToExist && RuntimeDependency.Type != StagedFileType.DebugNonUFS) || File.Exists()) { bool bRemap = RuntimeDependency.Type != StagedFileType.UFS || !bUsingPakFile; StageFile(RuntimeDependency.Type, File.FullName, bRemap: bRemap); } } } }
/// <summary> /// Deploys the given target /// </summary> /// <param name="Receipt">Receipt for the target being deployed</param> public override void Deploy(TargetReceipt Receipt) { }
/// <summary> /// Merges another receipt to this one. /// </summary> /// <param name="Other">Receipt which should be merged</param> public void Merge(TargetReceipt Other) { foreach(BuildProduct OtherBuildProduct in Other.BuildProducts) { BuildProducts.Add(OtherBuildProduct); } foreach(RuntimeDependency OtherRuntimeDependency in Other.RuntimeDependencies) { if(!RuntimeDependencies.Any(x => x.Path == OtherRuntimeDependency.Path && x.StagePath == OtherRuntimeDependency.StagePath)) { RuntimeDependencies.Add(OtherRuntimeDependency); } } }
public override void AddFilesToReceipt(TargetReceipt Receipt, UEBuildBinary Binary) { // we need to include the generated .mem and .symbols file. if(Binary.Config.Type != UEBuildBinaryType.StaticLibrary) { Receipt.AddBuildProduct(Binary.Config.OutputFilePath + ".mem", BuildProductType.RequiredResource); Receipt.AddBuildProduct(Binary.Config.OutputFilePath + ".symbols", BuildProductType.RequiredResource); } }
/// <summary> /// Build a list of targets /// </summary> /// <param name="TargetDescriptors">Target descriptors</param> /// <param name="BuildConfiguration">Current build configuration</param> /// <param name="WorkingSet">The source file working set</param> /// <param name="Options">Additional options for the build</param> /// <param name="WriteOutdatedActionsFile">Files to write the list of outdated actions to (rather than building them)</param> /// <returns>Result from the compilation</returns> public static void Build(List <TargetDescriptor> TargetDescriptors, BuildConfiguration BuildConfiguration, ISourceFileWorkingSet WorkingSet, BuildOptions Options, FileReference WriteOutdatedActionsFile) { // Create a makefile for each target TargetMakefile[] Makefiles = new TargetMakefile[TargetDescriptors.Count]; for (int TargetIdx = 0; TargetIdx < TargetDescriptors.Count; TargetIdx++) { Makefiles[TargetIdx] = CreateMakefile(BuildConfiguration, TargetDescriptors[TargetIdx], WorkingSet); } // Export the actions for each target for (int TargetIdx = 0; TargetIdx < TargetDescriptors.Count; TargetIdx++) { TargetDescriptor TargetDescriptor = TargetDescriptors[TargetIdx]; foreach (FileReference WriteActionFile in TargetDescriptor.WriteActionFiles) { Log.TraceInformation("Writing actions to {0}", WriteActionFile); ActionGraph.ExportJson(Makefiles[TargetIdx].Actions, WriteActionFile); } } // Execute the build if ((Options & BuildOptions.SkipBuild) == 0) { // Make sure that none of the actions conflict with any other (producing output files differently, etc...) ActionGraph.CheckForConflicts(Makefiles.SelectMany(x => x.Actions)); // Check we don't exceed the nominal max path length using (Timeline.ScopeEvent("ActionGraph.CheckPathLengths")) { ActionGraph.CheckPathLengths(BuildConfiguration, Makefiles.SelectMany(x => x.Actions)); } // Find all the actions to be executed HashSet <Action>[] ActionsToExecute = new HashSet <Action> [TargetDescriptors.Count]; for (int TargetIdx = 0; TargetIdx < TargetDescriptors.Count; TargetIdx++) { ActionsToExecute[TargetIdx] = GetActionsForTarget(BuildConfiguration, TargetDescriptors[TargetIdx], Makefiles[TargetIdx]); } // If there are multiple targets being built, merge the actions together List <Action> MergedActionsToExecute; if (TargetDescriptors.Count == 1) { MergedActionsToExecute = new List <Action>(ActionsToExecute[0]); } else { MergedActionsToExecute = MergeActionGraphs(TargetDescriptors, ActionsToExecute); } // Link all the actions together ActionGraph.Link(MergedActionsToExecute); // Make sure we're not modifying any engine files if ((Options & BuildOptions.NoEngineChanges) != 0) { List <FileItem> EngineChanges = MergedActionsToExecute.SelectMany(x => x.ProducedItems).Where(x => x.Location.IsUnderDirectory(UnrealBuildTool.EngineDirectory)).Distinct().OrderBy(x => x.FullName).ToList(); if (EngineChanges.Count > 0) { StringBuilder Result = new StringBuilder("Building would modify the following engine files:\n"); foreach (FileItem EngineChange in EngineChanges) { Result.AppendFormat("\n{0}", EngineChange.FullName); } Result.Append("\n\nPlease rebuild from an IDE instead."); Log.TraceError("{0}", Result.ToString()); throw new CompilationResultException(CompilationResult.FailedDueToEngineChange); } } // Make sure the appropriate executor is selected foreach (TargetDescriptor TargetDescriptor in TargetDescriptors) { UEBuildPlatform BuildPlatform = UEBuildPlatform.GetBuildPlatform(TargetDescriptor.Platform); BuildConfiguration.bAllowXGE &= BuildPlatform.CanUseXGE(); BuildConfiguration.bAllowDistcc &= BuildPlatform.CanUseDistcc(); BuildConfiguration.bAllowSNDBS &= BuildPlatform.CanUseSNDBS(); } // Delete produced items that are outdated. ActionGraph.DeleteOutdatedProducedItems(MergedActionsToExecute); // Save all the action histories now that files have been removed. We have to do this after deleting produced items to ensure that any // items created during the build don't have the wrong command line. ActionHistory.SaveAll(); // Create directories for the outdated produced items. ActionGraph.CreateDirectoriesForProducedItems(MergedActionsToExecute); // Execute the actions if ((Options & BuildOptions.XGEExport) != 0) { OutputToolchainInfo(TargetDescriptors, Makefiles); // Just export to an XML file using (Timeline.ScopeEvent("XGE.ExportActions()")) { XGE.ExportActions(MergedActionsToExecute); } } else if (WriteOutdatedActionsFile != null) { OutputToolchainInfo(TargetDescriptors, Makefiles); // Write actions to an output file using (Timeline.ScopeEvent("ActionGraph.WriteActions")) { ActionGraph.ExportJson(MergedActionsToExecute, WriteOutdatedActionsFile); } } else { // Execute the actions if (MergedActionsToExecute.Count == 0) { if (TargetDescriptors.Any(x => !x.bQuiet)) { Log.TraceInformation((TargetDescriptors.Count == 1)? "Target is up to date" : "Targets are up to date"); } } else { if (TargetDescriptors.Any(x => !x.bQuiet)) { Log.TraceInformation("Building {0}...", StringUtils.FormatList(TargetDescriptors.Select(x => x.Name).Distinct())); } OutputToolchainInfo(TargetDescriptors, Makefiles); using (Timeline.ScopeEvent("ActionGraph.ExecuteActions()")) { ActionGraph.ExecuteActions(BuildConfiguration, MergedActionsToExecute); } } // Run the deployment steps foreach (TargetMakefile Makefile in Makefiles) { if (Makefile.bDeployAfterCompile) { TargetReceipt Receipt = TargetReceipt.Read(Makefile.ReceiptFile); Log.TraceInformation("Deploying {0} {1} {2}...", Receipt.TargetName, Receipt.Platform, Receipt.Configuration); UEBuildPlatform.GetBuildPlatform(Receipt.Platform).Deploy(Receipt); } } } } }
private List<string> CollectPluginDataPaths(TargetReceipt Receipt) { List<string> PluginExtras = new List<string>(); if (Receipt == null) { Console.WriteLine("Receipt is NULL"); //Log.TraceInformation("Receipt is NULL"); return PluginExtras; } // collect plugin extra data paths from target receipt var Results = Receipt.AdditionalProperties.Where(x => x.Name == "IOSPlugin"); foreach (var Property in Results) { // Keep only unique paths string PluginPath = Property.Value; if (PluginExtras.FirstOrDefault(x => x == PluginPath) == null) { PluginExtras.Add(PluginPath); Log.TraceInformation("IOSPlugin: {0}", PluginPath); } } return PluginExtras; }
public override void AddFilesToReceipt(TargetReceipt Receipt, UEBuildBinary Binary) { // The cross-platform code adds .dSYMs for static libraries, which is just wrong, so // eliminate them here for now. string DebugExtension = UEBuildPlatform.GetBuildPlatform(Binary.Target.Platform).GetDebugInfoExtension(Binary.Config.Type); if(DebugExtension == ".dsym") { for (int i = 0; i < Receipt.BuildProducts.Count; i++) { if(Path.GetExtension(Receipt.BuildProducts[i].Path) == DebugExtension) { Receipt.BuildProducts.RemoveAt(i--); } } for (int i = 0; i < Receipt.BuildProducts.Count; i++) { if(Receipt.BuildProducts[i].Type == BuildProductType.Executable || Receipt.BuildProducts[i].Type == BuildProductType.DynamicLibrary) { Receipt.AddBuildProduct(Path.ChangeExtension(Receipt.BuildProducts[i].Path, DebugExtension), BuildProductType.SymbolFile); } } } if (Binary.Target.GlobalLinkEnvironment.Config.bIsBuildingConsoleApplication) { return; } if (BundleContentsDirectory == "" && Binary.Config.Type == UEBuildBinaryType.Executable) { BundleContentsDirectory = Path.GetDirectoryName(Path.GetDirectoryName(Binary.Config.OutputFilePath)) + "/"; } // We need to know what third party dylibs would be copied to the bundle if(Binary.Config.Type != UEBuildBinaryType.StaticLibrary) { var Modules = Binary.GetAllDependencyModules(bIncludeDynamicallyLoaded: false, bForceCircular: false); var BinaryLinkEnvironment = Binary.Target.GlobalLinkEnvironment.DeepCopy(); var BinaryDependencies = new List<UEBuildBinary>(); var LinkEnvironmentVisitedModules = new Dictionary<UEBuildModule, bool>(); foreach (var Module in Modules) { Module.SetupPrivateLinkEnvironment(Binary, BinaryLinkEnvironment, BinaryDependencies, LinkEnvironmentVisitedModules); } foreach (string AdditionalLibrary in BinaryLinkEnvironment.Config.AdditionalLibraries) { string LibName = Path.GetFileName(AdditionalLibrary); if (LibName.StartsWith("lib")) { if (Path.GetExtension(AdditionalLibrary) == ".dylib" && !String.IsNullOrEmpty(BundleContentsDirectory)) { string Entry = BundleContentsDirectory + "MacOS/" + LibName; Receipt.AddBuildProduct(Entry, BuildProductType.DynamicLibrary); } } } foreach (UEBuildBundleResource Resource in BinaryLinkEnvironment.Config.AdditionalBundleResources) { if (Directory.Exists(Resource.ResourcePath)) { foreach (string ResourceFile in Directory.GetFiles(Resource.ResourcePath, "*", SearchOption.AllDirectories)) { Receipt.AddBuildProduct(Path.Combine(BundleContentsDirectory, Resource.BundleContentsSubdir, ResourceFile.Substring(Path.GetDirectoryName(Resource.ResourcePath).Length + 1)), BuildProductType.RequiredResource); } } else { Receipt.AddBuildProduct(Path.Combine(BundleContentsDirectory, Resource.BundleContentsSubdir, Path.GetFileName(Resource.ResourcePath)), BuildProductType.RequiredResource); } } } if (Binary.Config.Type == UEBuildBinaryType.Executable) { // And we also need all the resources Receipt.AddBuildProduct(BundleContentsDirectory + "Info.plist", BuildProductType.RequiredResource); Receipt.AddBuildProduct(BundleContentsDirectory + "PkgInfo", BuildProductType.RequiredResource); Receipt.AddBuildProduct(BundleContentsDirectory + "Resources/UE4.icns", BuildProductType.RequiredResource); if (Binary.Target.AppName.StartsWith("UE4Editor")) { Receipt.AddBuildProduct(BundleContentsDirectory + "Resources/UProject.icns", BuildProductType.RequiredResource); } } }
public override bool PrepTargetForDeployment(TargetReceipt Receipt) { // Use the project name if possible - InTarget.AppName changes for 'Client'/'Server' builds string ProjectName = Receipt.ProjectFile != null?Receipt.ProjectFile.GetFileNameWithoutAnyExtensions() : Receipt.Launch.GetFileNameWithoutExtension(); Log.TraceInformation("Prepping {0} for deployment to {1}", ProjectName, Receipt.Platform.ToString()); System.DateTime PrepDeployStartTime = DateTime.UtcNow; // Note: TargetReceipt.Read now expands path variables internally. TargetReceipt NewReceipt = null; FileReference ReceiptFileName = TargetReceipt.GetDefaultPath(Receipt.ProjectDir != null ? Receipt.ProjectDir : UnrealBuildTool.EngineDirectory, Receipt.TargetName, Receipt.Platform, Receipt.Configuration, "Multi"); if (!TargetReceipt.TryRead(ReceiptFileName, UnrealBuildTool.EngineDirectory, out NewReceipt)) { NewReceipt = new TargetReceipt(Receipt.ProjectFile, Receipt.TargetName, Receipt.TargetType, Receipt.Platform, Receipt.Configuration, Receipt.Version, "Multi"); } AddWinMDReferencesFromReceipt(Receipt, Receipt.ProjectDir != null ? Receipt.ProjectDir : UnrealBuildTool.EngineDirectory, UnrealBuildTool.EngineDirectory.ParentDirectory.FullName); //PrepForUATPackageOrDeploy(InTarget.ProjectFile, InAppName, InTarget.ProjectDirectory.FullName, InTarget.OutputPath.FullName, TargetBuildEnvironment.RelativeEnginePath, false, "", false); List <UnrealTargetConfiguration> TargetConfigs = new List <UnrealTargetConfiguration> { Receipt.Configuration }; List <string> ExePaths = new List <string> { Receipt.Launch.FullName }; string RelativeEnginePath = UnrealBuildTool.EngineDirectory.MakeRelativeTo(DirectoryReference.GetCurrentDirectory()); WindowsArchitecture Arch = WindowsArchitecture.ARM64; if (Receipt.Architecture.ToLower() == "x64") { Arch = WindowsArchitecture.x64; } string SDK = ""; var Results = Receipt.AdditionalProperties.Where(x => x.Name == "SDK"); if (Results.Any()) { SDK = Results.First().Value; } HoloLensExports.InitWindowsSdkToolPath(SDK); string AbsoluteExeDirectory = Path.GetDirectoryName(ExePaths[0]); UnrealTargetPlatform Platform = UnrealTargetPlatform.HoloLens; string IntermediateDirectory = Path.Combine(Receipt.ProjectDir != null ? Receipt.ProjectDir.FullName : UnrealBuildTool.EngineDirectory.FullName, "Intermediate", "Deploy", WindowsExports.GetArchitectureSubpath(Arch)); List <string> UpdatedFiles = new HoloLensManifestGenerator().CreateManifest(Platform, Arch, AbsoluteExeDirectory, IntermediateDirectory, Receipt.ProjectFile, Receipt.ProjectDir != null ? Receipt.ProjectDir.FullName : UnrealBuildTool.EngineDirectory.FullName, TargetConfigs, ExePaths, WinMDReferences); PrepForUATPackageOrDeploy(Receipt.ProjectFile, ProjectName, Receipt.ProjectDir != null ? Receipt.ProjectDir.FullName : UnrealBuildTool.EngineDirectory.FullName, Arch, TargetConfigs, ExePaths, RelativeEnginePath, false, "", false); MakePackage(Receipt, NewReceipt, Arch, UpdatedFiles); CopyDataAndSymbolsBetweenReceipts(Receipt, NewReceipt, Arch); NewReceipt.Write(ReceiptFileName, UnrealBuildTool.EngineDirectory); // Log out the time taken to deploy... double PrepDeployDuration = (DateTime.UtcNow - PrepDeployStartTime).TotalSeconds; Log.TraceInformation("HoloLens deployment preparation took {0:0.00} seconds", PrepDeployDuration); return(true); }
private void MakePackage(TargetReceipt Receipt, TargetReceipt NewReceipt, WindowsArchitecture Architecture, List <string> UpdatedFiles) { string OutputName = String.Format("{0}_{1}_{2}_{3}", Receipt.TargetName, Receipt.Platform, Receipt.Configuration, WindowsExports.GetArchitectureSubpath(Architecture)); string IntermediateDirectory = Path.Combine(Receipt.ProjectDir != null ? Receipt.ProjectDir.FullName : UnrealBuildTool.EngineDirectory.FullName, "Intermediate", "Deploy", WindowsExports.GetArchitectureSubpath(Architecture)); string OutputDirectory = Receipt.Launch.Directory.FullName; string OutputAppX = Path.Combine(OutputDirectory, OutputName + ".appx"); string SigningCertificate = @"Build\HoloLens\SigningCertificate.pfx"; string SigningCertificatePath = Path.Combine(Receipt.ProjectDir != null ? Receipt.ProjectDir.FullName : UnrealBuildTool.EngineDirectory.FullName, SigningCertificate); string MapFilename = Path.Combine(IntermediateDirectory, OutputName + ".pkgmap"); var LocalRoot = Receipt.ProjectDir; var EngineRoot = UnrealBuildTool.RootDirectory; var AddedFiles = new Dictionary <string, string>(); bool PackageFileNeedToBeUpdated = !File.Exists(OutputAppX); DateTime AppXTime = DateTime.Now; PackageFileNeedToBeUpdated = true; if (!PackageFileNeedToBeUpdated) { AppXTime = File.GetLastWriteTimeUtc(OutputAppX); } { foreach (var Product in Receipt.BuildProducts) { if (Product.Type == BuildProductType.Executable || Product.Type == BuildProductType.DynamicLibrary || Product.Type == BuildProductType.RequiredResource) { string Filename; if (AddedFiles.ContainsKey(Product.Path.FullName)) { continue; } if (LocalRoot != null && Product.Path.IsUnderDirectory(LocalRoot)) { Filename = Product.Path.MakeRelativeTo(LocalRoot.ParentDirectory); } else if (Product.Path.IsUnderDirectory(EngineRoot)) { Filename = Product.Path.MakeRelativeTo(EngineRoot); } else { throw new BuildException("Failed to parse target receipt file. See log for details."); } AddedFiles.Add(Product.Path.FullName, Filename); } } foreach (var Dep in Receipt.RuntimeDependencies) { if (Dep.Type == StagedFileType.NonUFS) { if (AddedFiles.ContainsKey(Dep.Path.FullName)) { continue; } string Filename; if (LocalRoot != null && Dep.Path.IsUnderDirectory(LocalRoot)) { Filename = Dep.Path.MakeRelativeTo(LocalRoot.ParentDirectory); } else if (Dep.Path.IsUnderDirectory(EngineRoot)) { Filename = Dep.Path.MakeRelativeTo(EngineRoot); } else { throw new BuildException("Failed to parse target receipt file. See log for details."); } AddedFiles.Add(Dep.Path.FullName, Filename); } } } string ManifestName = String.Format("AppxManifest_{0}.xml", WindowsExports.GetArchitectureSubpath(Architecture)); AddedFiles.Add(Path.Combine(OutputDirectory, ManifestName), "AppxManifest.xml"); //manually add resources string PriFileName = String.Format("resources_{0}.pri", WindowsExports.GetArchitectureSubpath(Architecture)); AddedFiles.Add(Path.Combine(OutputDirectory, PriFileName), "resources.pri"); { DirectoryReference ResourceFolder = DirectoryReference.Combine(Receipt.Launch.Directory, WindowsExports.GetArchitectureSubpath(Architecture)); foreach (var ResourcePath in UpdatedFiles) { var ResourceFile = new FileReference(ResourcePath); if (ResourceFile.IsUnderDirectory(ResourceFolder)) { AddedFiles.Add(ResourceFile.FullName, ResourceFile.MakeRelativeTo(ResourceFolder)); } else { Log.TraceError("Wrong path to resource \'{0}\', the resource should be in \'{1}\'", ResourceFile.FullName, ResourceFolder.FullName); throw new BuildException("Failed to generate AppX file. See log for details."); } } } FileReference SourceNetworkManifestPath = new FileReference(Path.Combine(OutputDirectory, "NetworkManifest.xml")); if (FileReference.Exists(SourceNetworkManifestPath)) { AddedFiles.Add(SourceNetworkManifestPath.FullName, "NetworkManifest.xml"); } FileReference SourceXboxConfigPath = new FileReference(Path.Combine(OutputDirectory, "xboxservices.config")); if (FileReference.Exists(SourceXboxConfigPath)) { AddedFiles.Add(SourceXboxConfigPath.FullName, "xboxservices.config"); } do { if (PackageFileNeedToBeUpdated) { break; } if (!File.Exists(MapFilename)) { PackageFileNeedToBeUpdated = true; break; } string[] lines = File.ReadAllLines(MapFilename, Encoding.UTF8); int filesCount = 0; foreach (var line in lines) { if (line[0] == '[') { continue; } string[] files = line.Split('\t'); if (files.Length != 2) { PackageFileNeedToBeUpdated = true; break; } files[0] = files[0].Trim('\"'); files[1] = files[1].Trim('\"'); if (!AddedFiles.ContainsKey(files[0])) { PackageFileNeedToBeUpdated = true; break; } if (AddedFiles[files[0]] != files[1]) { PackageFileNeedToBeUpdated = true; break; } if (File.GetLastWriteTimeUtc(files[0]).CompareTo(AppXTime) >= 0) { PackageFileNeedToBeUpdated = true; break; } ++filesCount; } if (PackageFileNeedToBeUpdated) { break; } if (filesCount != AddedFiles.Count) { PackageFileNeedToBeUpdated = true; break; } if (File.Exists(SigningCertificatePath) && File.GetLastWriteTimeUtc(SigningCertificatePath).CompareTo(AppXTime) >= 0) { PackageFileNeedToBeUpdated = true; break; } }while(false); if (!PackageFileNeedToBeUpdated) { NewReceipt.BuildProducts.Add(new BuildProduct(new FileReference(OutputAppX), BuildProductType.Package)); return; } try { DeployHelper_DeleteFile(OutputAppX); } catch (Exception exceptionMessage) { Log.TraceError("Failed to delete {0} from deployment: {1}", OutputAppX, exceptionMessage); throw new BuildException("Failed to generate AppX file. See log for details."); } var AppXRecipeBuiltFiles = new StringBuilder(); AppXRecipeBuiltFiles.AppendLine(@"[Files]"); foreach (var f in AddedFiles) { AppXRecipeBuiltFiles.AppendLine(String.Format("\"{0}\"\t\"{1}\"", f.Key, f.Value)); } File.WriteAllText(MapFilename, AppXRecipeBuiltFiles.ToString(), Encoding.UTF8); NewReceipt.BuildProducts.Add(new BuildProduct(new FileReference(MapFilename), BuildProductType.MapFile)); }
/// <summary> /// Read a receipt from disk. /// </summary> /// <param name="FileName">Filename to read from</param> public static bool TryRead(string FileName, out TargetReceipt Receipt) { if (!File.Exists(FileName)) { Receipt = null; return false; } try { using (StreamReader Reader = new StreamReader(FileName)) { Receipt = (TargetReceipt)Serializer.Deserialize(Reader); return true; } } catch(Exception) { Receipt = null; return false; } }
/// <summary> /// Deploys the given target /// </summary> /// <param name="Receipt">Receipt for the target being deployed</param> public override void Deploy(TargetReceipt Receipt) { new UEDeployLumin(Receipt.ProjectFile).PrepTargetForDeployment(Receipt); }
/// <summary> /// Read a receipt from disk. /// </summary> /// <param name="FileName">Filename to read from</param> public static TargetReceipt Read(string FileName) { JsonObject RawObject = JsonObject.Read(FileName); // Read the initial fields string TargetName = RawObject.GetStringField("TargetName"); UnrealTargetPlatform Platform = RawObject.GetEnumField <UnrealTargetPlatform>("Platform"); UnrealTargetConfiguration Configuration = RawObject.GetEnumField <UnrealTargetConfiguration>("Configuration"); string BuildId = RawObject.GetStringField("BuildId"); // Try to read the build version BuildVersion Version; if (!BuildVersion.TryParse(RawObject.GetObjectField("Version"), out Version)) { throw new JsonParseException("Invalid 'Version' field"); } // Create the receipt TargetReceipt Receipt = new TargetReceipt(TargetName, Platform, Configuration, BuildId, Version); // Read the build products JsonObject[] BuildProductObjects; if (RawObject.TryGetObjectArrayField("BuildProducts", out BuildProductObjects)) { foreach (JsonObject BuildProductObject in BuildProductObjects) { string Path; BuildProductType Type; if (BuildProductObject.TryGetStringField("Path", out Path) && BuildProductObject.TryGetEnumField("Type", out Type)) { string Module; BuildProductObject.TryGetStringField("Module", out Module); BuildProduct NewBuildProduct = Receipt.AddBuildProduct(Path, Type); bool IsPrecompiled; if (BuildProductObject.TryGetBoolField("IsPrecompiled", out IsPrecompiled)) { NewBuildProduct.IsPrecompiled = IsPrecompiled; } } } } // Read the runtime dependencies JsonObject[] RuntimeDependencyObjects; if (RawObject.TryGetObjectArrayField("RuntimeDependencies", out RuntimeDependencyObjects)) { foreach (JsonObject RuntimeDependencyObject in RuntimeDependencyObjects) { string Path; if (RuntimeDependencyObject.TryGetStringField("Path", out Path)) { string StagePath; if (!RuntimeDependencyObject.TryGetStringField("StagePath", out StagePath)) { StagePath = null; } bool bIgnoreIfMissing; if (!RuntimeDependencyObject.TryGetBoolField("IgnoreIfMissing", out bIgnoreIfMissing)) { bIgnoreIfMissing = false; } Receipt.AddRuntimeDependency(Path, StagePath, bIgnoreIfMissing); } } } // Read the additional properties JsonObject[] AdditionalPropertyObjects; if (RawObject.TryGetObjectArrayField("AdditionalProperties", out AdditionalPropertyObjects)) { foreach (JsonObject AdditionalPropertyObject in AdditionalPropertyObjects) { string Name; if (AdditionalPropertyObject.TryGetStringField("Name", out Name)) { string Value; if (AdditionalPropertyObject.TryGetStringField("Value", out Value)) { Receipt.AdditionalProperties.Add(new ReceiptProperty(Name, Value)); } } } } return(Receipt); }
/// <summary> /// /// </summary> /// <param name="Config"></param> /// <param name="ProjectFile"></param> /// <param name="InProjectName"></param> /// <param name="InProjectDirectory"></param> /// <param name="InExecutablePath"></param> /// <param name="InEngineDir"></param> /// <param name="bForDistribution"></param> /// <param name="CookFlavor"></param> /// <param name="bIsDataDeploy"></param> /// <param name="bCreateStubIPA"></param> /// <param name="BuildReceiptFileName"></param> /// <returns></returns> public static bool PrepForUATPackageOrDeploy(UnrealTargetConfiguration Config, FileReference ProjectFile, string InProjectName, DirectoryReference InProjectDirectory, string InExecutablePath, DirectoryReference InEngineDir, bool bForDistribution, string CookFlavor, bool bIsDataDeploy, bool bCreateStubIPA, FileReference BuildReceiptFileName) { TargetReceipt Receipt = TargetReceipt.Read(BuildReceiptFileName); return(new UEDeployIOS().PrepForUATPackageOrDeploy(Config, ProjectFile, InProjectName, InProjectDirectory.FullName, InExecutablePath, InEngineDir.FullName, bForDistribution, CookFlavor, bIsDataDeploy, bCreateStubIPA, Receipt)); }
/// <summary> /// Build a list of targets with a given set of makefiles. /// </summary> /// <param name="Makefiles">Makefiles created with CreateMakefiles</param> /// <param name="TargetDescriptors">Target descriptors</param> /// <param name="BuildConfiguration">Current build configuration</param> /// <param name="WorkingSet">The source file working set</param> /// <param name="Options">Additional options for the build</param> /// <param name="WriteOutdatedActionsFile">Files to write the list of outdated actions to (rather than building them)</param> /// <returns>Result from the compilation</returns> static void Build(TargetMakefile[] Makefiles, List <TargetDescriptor> TargetDescriptors, BuildConfiguration BuildConfiguration, ISourceFileWorkingSet WorkingSet, BuildOptions Options, FileReference WriteOutdatedActionsFile) { // Export the actions for each target for (int TargetIdx = 0; TargetIdx < TargetDescriptors.Count; TargetIdx++) { TargetDescriptor TargetDescriptor = TargetDescriptors[TargetIdx]; foreach (FileReference WriteActionFile in TargetDescriptor.WriteActionFiles) { Log.TraceInformation("Writing actions to {0}", WriteActionFile); ActionGraph.ExportJson(Makefiles[TargetIdx].Actions, WriteActionFile); } } // Execute the build if ((Options & BuildOptions.SkipBuild) == 0) { // Make sure that none of the actions conflict with any other (producing output files differently, etc...) ActionGraph.CheckForConflicts(Makefiles.SelectMany(x => x.Actions)); // Check we don't exceed the nominal max path length using (Timeline.ScopeEvent("ActionGraph.CheckPathLengths")) { ActionGraph.CheckPathLengths(BuildConfiguration, Makefiles.SelectMany(x => x.Actions)); } // Clean up any previous hot reload runs, and reapply the current state if it's already active for (int TargetIdx = 0; TargetIdx < TargetDescriptors.Count; TargetIdx++) { HotReload.Setup(TargetDescriptors[TargetIdx], Makefiles[TargetIdx], BuildConfiguration); } // Merge the action graphs together List <Action> MergedActions; if (TargetDescriptors.Count == 1) { MergedActions = new List <Action>(Makefiles[0].Actions); } else { MergedActions = MergeActionGraphs(TargetDescriptors, Makefiles); } // Gather all the prerequisite actions that are part of the targets HashSet <FileItem> MergedOutputItems = new HashSet <FileItem>(); for (int TargetIdx = 0; TargetIdx < TargetDescriptors.Count; TargetIdx++) { GatherOutputItems(TargetDescriptors[TargetIdx], Makefiles[TargetIdx], MergedOutputItems); } // Link all the actions together ActionGraph.Link(MergedActions); // Get all the actions that are prerequisites for these targets. This forms the list of actions that we want executed. List <Action> PrerequisiteActions = ActionGraph.GatherPrerequisiteActions(MergedActions, MergedOutputItems); // Create the action history ActionHistory History = new ActionHistory(); for (int TargetIdx = 0; TargetIdx < TargetDescriptors.Count; TargetIdx++) { using (Timeline.ScopeEvent("Reading action history")) { TargetDescriptor TargetDescriptor = TargetDescriptors[TargetIdx]; if (TargetDescriptor.ProjectFile != null) { History.Mount(TargetDescriptor.ProjectFile.Directory); } } } // Figure out which actions need to be built Dictionary <Action, bool> ActionToOutdatedFlag = new Dictionary <Action, bool>(); for (int TargetIdx = 0; TargetIdx < TargetDescriptors.Count; TargetIdx++) { TargetDescriptor TargetDescriptor = TargetDescriptors[TargetIdx]; // Create the dependencies cache CppDependencyCache CppDependencies; using (Timeline.ScopeEvent("Reading dependency cache")) { CppDependencies = CppDependencyCache.CreateHierarchy(TargetDescriptor.ProjectFile, TargetDescriptor.Name, TargetDescriptor.Platform, TargetDescriptor.Configuration, Makefiles[TargetIdx].TargetType, TargetDescriptor.Architecture); } // Plan the actions to execute for the build. For single file compiles, always rebuild the source file regardless of whether it's out of date. if (TargetDescriptor.SpecificFilesToCompile.Count == 0) { ActionGraph.GatherAllOutdatedActions(PrerequisiteActions, History, ActionToOutdatedFlag, CppDependencies, BuildConfiguration.bIgnoreOutdatedImportLibraries); } else { foreach (FileReference SpecificFile in TargetDescriptor.SpecificFilesToCompile) { foreach (Action PrerequisiteAction in PrerequisiteActions.Where(x => x.PrerequisiteItems.Any(y => y.Location == SpecificFile))) { ActionToOutdatedFlag[PrerequisiteAction] = true; } } } } // Link the action graph again to sort it List <Action> MergedActionsToExecute = ActionToOutdatedFlag.Where(x => x.Value).Select(x => x.Key).ToList(); ActionGraph.Link(MergedActionsToExecute); // Allow hot reload to override the actions int HotReloadTargetIdx = -1; for (int Idx = 0; Idx < TargetDescriptors.Count; Idx++) { if (TargetDescriptors[Idx].HotReloadMode != HotReloadMode.Disabled) { if (HotReloadTargetIdx != -1) { throw new BuildException("Unable to perform hot reload with multiple targets."); } else { MergedActionsToExecute = HotReload.PatchActionsForTarget(BuildConfiguration, TargetDescriptors[Idx], Makefiles[Idx], PrerequisiteActions, MergedActionsToExecute); } HotReloadTargetIdx = Idx; } } // Make sure we're not modifying any engine files if ((Options & BuildOptions.NoEngineChanges) != 0) { List <FileItem> EngineChanges = MergedActionsToExecute.SelectMany(x => x.ProducedItems).Where(x => x.Location.IsUnderDirectory(UnrealBuildTool.EngineDirectory)).Distinct().OrderBy(x => x.FullName).ToList(); if (EngineChanges.Count > 0) { StringBuilder Result = new StringBuilder("Building would modify the following engine files:\n"); foreach (FileItem EngineChange in EngineChanges) { Result.AppendFormat("\n{0}", EngineChange.FullName); } Result.Append("\n\nPlease rebuild from an IDE instead."); Log.TraceError("{0}", Result.ToString()); throw new CompilationResultException(CompilationResult.FailedDueToEngineChange); } } // Make sure the appropriate executor is selected foreach (TargetDescriptor TargetDescriptor in TargetDescriptors) { UEBuildPlatform BuildPlatform = UEBuildPlatform.GetBuildPlatform(TargetDescriptor.Platform); BuildConfiguration.bAllowXGE &= BuildPlatform.CanUseXGE(); BuildConfiguration.bAllowDistcc &= BuildPlatform.CanUseDistcc(); BuildConfiguration.bAllowSNDBS &= BuildPlatform.CanUseSNDBS(); } // Delete produced items that are outdated. ActionGraph.DeleteOutdatedProducedItems(MergedActionsToExecute); // Save all the action histories now that files have been removed. We have to do this after deleting produced items to ensure that any // items created during the build don't have the wrong command line. History.Save(); // Create directories for the outdated produced items. ActionGraph.CreateDirectoriesForProducedItems(MergedActionsToExecute); // Execute the actions if ((Options & BuildOptions.XGEExport) != 0) { OutputToolchainInfo(TargetDescriptors, Makefiles); // Just export to an XML file using (Timeline.ScopeEvent("XGE.ExportActions()")) { XGE.ExportActions(MergedActionsToExecute); } } else if (WriteOutdatedActionsFile != null) { OutputToolchainInfo(TargetDescriptors, Makefiles); // Write actions to an output file using (Timeline.ScopeEvent("ActionGraph.WriteActions")) { ActionGraph.ExportJson(MergedActionsToExecute, WriteOutdatedActionsFile); } } else { // Execute the actions if (MergedActionsToExecute.Count == 0) { if (TargetDescriptors.Any(x => !x.bQuiet)) { Log.TraceInformation((TargetDescriptors.Count == 1)? "Target is up to date" : "Targets are up to date"); } } else { if (TargetDescriptors.Any(x => !x.bQuiet)) { Log.TraceInformation("Building {0}...", StringUtils.FormatList(TargetDescriptors.Select(x => x.Name).Distinct())); } OutputToolchainInfo(TargetDescriptors, Makefiles); using (Timeline.ScopeEvent("ActionGraph.ExecuteActions()")) { ActionGraph.ExecuteActions(BuildConfiguration, MergedActionsToExecute); } } // Run the deployment steps foreach (TargetMakefile Makefile in Makefiles) { if (Makefile.bDeployAfterCompile) { TargetReceipt Receipt = TargetReceipt.Read(Makefile.ReceiptFile); Log.TraceInformation("Deploying {0} {1} {2}...", Receipt.TargetName, Receipt.Platform, Receipt.Configuration); UEBuildPlatform.GetBuildPlatform(Receipt.Platform).Deploy(Receipt); } } } } }
/// <summary> /// Deploys the given target /// </summary> /// <param name="Receipt">Receipt for the target being deployed</param> public abstract void Deploy(TargetReceipt Receipt);
/// <summary> /// Collect all the WinMD references /// </summary> /// <param name="Receipt"></param> /// <param name="SourceProjectDir"></param> /// <param name="DestPackageRoot"></param> public void AddWinMDReferencesFromReceipt(TargetReceipt Receipt, DirectoryReference SourceProjectDir, string DestPackageRoot) { InnerDeploy.AddWinMDReferencesFromReceipt(Receipt, SourceProjectDir, DestPackageRoot); }
public override void AddFilesToReceipt(TargetReceipt Receipt, UEBuildBinary Binary) { if (Binary.Config.Type == UEBuildBinaryType.DynamicLinkLibrary) { Receipt.AddBuildProduct(Path.Combine(Binary.Config.IntermediateDirectory, Path.GetFileNameWithoutExtension(Binary.Config.OutputFilePath) + ".lib"), BuildProductType.ImportLibrary); } }
/// <summary> /// Read a receipt from disk. /// </summary> /// <param name="Location">Filename to read from</param> /// <param name="EngineDir">Engine directory for expanded variables</param> public static TargetReceipt Read(FileReference Location, DirectoryReference EngineDir) { JsonObject RawObject = JsonObject.Read(Location); // Read the initial fields string TargetName = RawObject.GetStringField("TargetName"); TargetType TargetType = RawObject.GetEnumField <TargetType>("TargetType"); UnrealTargetPlatform Platform = RawObject.GetEnumField <UnrealTargetPlatform>("Platform"); UnrealTargetConfiguration Configuration = RawObject.GetEnumField <UnrealTargetConfiguration>("Configuration"); // Try to read the build version BuildVersion Version; if (!BuildVersion.TryParse(RawObject.GetObjectField("Version"), out Version)) { throw new JsonParseException("Invalid 'Version' field"); } // Read the project path FileReference ProjectFile; string RelativeProjectFile; if (RawObject.TryGetStringField("Project", out RelativeProjectFile)) { ProjectFile = FileReference.Combine(Location.Directory, RelativeProjectFile); } else { ProjectFile = null; } // Create the receipt TargetReceipt Receipt = new TargetReceipt(ProjectFile, TargetName, TargetType, Platform, Configuration, Version); // Get the project directory DirectoryReference ProjectDir = Receipt.ProjectDir; // Read the launch executable string Launch; if (RawObject.TryGetStringField("Launch", out Launch)) { Receipt.Launch = ExpandPathVariables(Launch, EngineDir, ProjectDir); } // Read the build products JsonObject[] BuildProductObjects; if (RawObject.TryGetObjectArrayField("BuildProducts", out BuildProductObjects)) { foreach (JsonObject BuildProductObject in BuildProductObjects) { string Path; BuildProductType Type; if (BuildProductObject.TryGetStringField("Path", out Path) && BuildProductObject.TryGetEnumField("Type", out Type)) { FileReference File = ExpandPathVariables(Path, EngineDir, ProjectDir); string Module; BuildProductObject.TryGetStringField("Module", out Module); Receipt.AddBuildProduct(File, Type); } } } // Read the runtime dependencies JsonObject[] RuntimeDependencyObjects; if (RawObject.TryGetObjectArrayField("RuntimeDependencies", out RuntimeDependencyObjects)) { foreach (JsonObject RuntimeDependencyObject in RuntimeDependencyObjects) { string Path; if (RuntimeDependencyObject.TryGetStringField("Path", out Path)) { FileReference File = ExpandPathVariables(Path, EngineDir, ProjectDir); StagedFileType Type; if (!RuntimeDependencyObject.TryGetEnumField("Type", out Type)) { // Previous format included an optional IgnoreIfMissing flag, which was only used for debug files. We can explicitly reference them as DebugNonUFS files now. bool bIgnoreIfMissing; if (RuntimeDependencyObject.TryGetBoolField("IgnoreIfMissing", out bIgnoreIfMissing)) { bIgnoreIfMissing = false; } Type = bIgnoreIfMissing? StagedFileType.DebugNonUFS : StagedFileType.NonUFS; } Receipt.RuntimeDependencies.Add(File, Type); } } } // Read the additional properties JsonObject[] AdditionalPropertyObjects; if (RawObject.TryGetObjectArrayField("AdditionalProperties", out AdditionalPropertyObjects)) { foreach (JsonObject AdditionalPropertyObject in AdditionalPropertyObjects) { string Name; if (AdditionalPropertyObject.TryGetStringField("Name", out Name)) { string Value; if (AdditionalPropertyObject.TryGetStringField("Value", out Value)) { Receipt.AdditionalProperties.Add(new ReceiptProperty(Name, Value)); } } } } return(Receipt); }
/// <summary> /// Checks if all the files in a receipt are present and that all the DLLs are at the same version /// </summary> /// <returns> /// True if all the files are valid. /// </returns> static DateTime GetTimestampFromBinaries(TargetReceipt Receipt) { DateTime LatestWriteTime = DateTime.MinValue; foreach(BuildProduct BuildProduct in Receipt.BuildProducts) { if(BuildProduct.Type == BuildProductType.Executable || BuildProduct.Type == BuildProductType.DynamicLibrary) { DateTime WriteTime = File.GetLastWriteTime(BuildProduct.Path); if(WriteTime > LatestWriteTime) { LatestWriteTime = WriteTime; } } } return LatestWriteTime; }
/// <summary> /// Try to read a receipt from disk, failing gracefully if it can't be read. /// </summary> /// <param name="Location">Filename to read from</param> /// <param name="Receipt">If successful, the receipt that was read</param> /// <returns>True if successful</returns> public static bool TryRead(FileReference Location, out TargetReceipt Receipt) { return(TryRead(Location, UnrealBuildTool.EngineDirectory, out Receipt)); }
public void StageBuildProductsFromReceipt(TargetReceipt Receipt, bool RequireDependenciesToExist, bool TreatNonShippingBinariesAsDebugFiles) { // Stage all the build products needed at runtime foreach(BuildProduct BuildProduct in Receipt.BuildProducts) { // allow missing files if needed if (RequireDependenciesToExist == false && File.Exists(BuildProduct.Path) == false) { continue; } if(BuildProduct.Type == BuildProductType.Executable || BuildProduct.Type == BuildProductType.DynamicLibrary || BuildProduct.Type == BuildProductType.RequiredResource) { StagedFileType FileTypeToUse = StagedFileType.NonUFS; if (TreatNonShippingBinariesAsDebugFiles && Receipt.Configuration != UnrealTargetConfiguration.Shipping) { FileTypeToUse = StagedFileType.DebugNonUFS; } StageFile(FileTypeToUse, BuildProduct.Path); } else if(BuildProduct.Type == BuildProductType.SymbolFile || BuildProduct.Type == BuildProductType.MapFile) { // Symbol files aren't true dependencies so we can skip if they don't exist if (File.Exists(BuildProduct.Path)) { StageFile(StagedFileType.DebugNonUFS, BuildProduct.Path); } } } }
/// <summary> /// Try to read a receipt from disk, failing gracefully if it can't be read. /// </summary> /// <param name="Location">Filename to read from</param> /// <param name="EngineDir">Engine directory for expanded paths</param> /// <param name="Receipt">If successful, the receipt that was read</param> /// <returns>True if successful</returns> public static bool TryRead(FileReference Location, DirectoryReference EngineDir, out TargetReceipt Receipt) { if (!FileReference.Exists(Location)) { Receipt = null; return(false); } try { Receipt = Read(Location, EngineDir); return(true); } catch (Exception) { Receipt = null; return(false); } }
public virtual void AddFilesToReceipt(TargetReceipt Receipt, UEBuildBinary Binary) { }
/// <summary> /// Deploys the given target /// </summary> /// <param name="Receipt">Information about the target being deployed</param> public override void Deploy(TargetReceipt Receipt) { new HoloLensDeploy().PrepTargetForDeployment(Receipt); }
/// <summary> /// Execute the command, having obtained the appropriate mutex /// </summary> /// <param name="Arguments">Command line arguments</param> /// <returns>Exit code</returns> private int ExecuteInternal(CommandLineArguments Arguments) { // Read the target info WriteMetadataTargetInfo TargetInfo = BinaryFormatterUtils.Load <WriteMetadataTargetInfo>(Arguments.GetFileReference("-Input=")); bool bNoManifestChanges = Arguments.HasOption("-NoManifestChanges"); int VersionNumber = Arguments.GetInteger("-Version="); Arguments.CheckAllArgumentsUsed(); // Make sure the version number is correct if (VersionNumber != CurrentVersionNumber) { throw new BuildException("Version number to WriteMetadataMode is incorrect (expected {0}, got {1})", CurrentVersionNumber, VersionNumber); } // Check if we need to set a build id TargetReceipt Receipt = TargetInfo.Receipt; if (Receipt.Version.BuildId == null) { // Check if there's an exist version file. If it exists, try to merge in any manifests that are valid (and reuse the existing build id) BuildVersion PreviousVersion; if (TargetInfo.VersionFile != null && BuildVersion.TryRead(TargetInfo.VersionFile, out PreviousVersion)) { // Check if we can reuse the existing manifests. This prevents unnecessary builds when switching between projects. Dictionary <FileReference, ModuleManifest> PreviousFileToManifest = new Dictionary <FileReference, ModuleManifest>(); if (TryRecyclingManifests(PreviousVersion.BuildId, TargetInfo.FileToManifest.Keys, PreviousFileToManifest)) { // Merge files from the existing manifests with the new ones foreach (KeyValuePair <FileReference, ModuleManifest> Pair in PreviousFileToManifest) { ModuleManifest TargetManifest = TargetInfo.FileToManifest[Pair.Key]; MergeManifests(Pair.Value, TargetManifest); } // Update the build id to use the current one Receipt.Version.BuildId = PreviousVersion.BuildId; } } // If the build id is still not set, generate a new one from a GUID if (Receipt.Version.BuildId == null) { Receipt.Version.BuildId = Guid.NewGuid().ToString(); } } else { // Read all the manifests and merge them into the new ones, if they have the same build id foreach (KeyValuePair <FileReference, ModuleManifest> Pair in TargetInfo.FileToManifest) { ModuleManifest SourceManifest; if (TryReadManifest(Pair.Key, out SourceManifest) && SourceManifest.BuildId == Receipt.Version.BuildId) { MergeManifests(SourceManifest, Pair.Value); } } } // Update the build id in all the manifests, and write them out foreach (KeyValuePair <FileReference, ModuleManifest> Pair in TargetInfo.FileToManifest) { FileReference ManifestFile = Pair.Key; if (!UnrealBuildTool.IsFileInstalled(ManifestFile)) { ModuleManifest Manifest = Pair.Value; Manifest.BuildId = Receipt.Version.BuildId; if (!FileReference.Exists(ManifestFile)) { // If the file doesn't already exist, just write it out DirectoryReference.CreateDirectory(ManifestFile.Directory); Manifest.Write(ManifestFile); } else { // Otherwise write it to a buffer first string OutputText; using (StringWriter Writer = new StringWriter()) { Manifest.Write(Writer); OutputText = Writer.ToString(); } // And only write it to disk if it's been modified. Note that if a manifest is out of date, we should have generated a new build id causing the contents to differ. string CurrentText = FileReference.ReadAllText(ManifestFile); if (CurrentText != OutputText) { if (bNoManifestChanges) { Log.TraceError("Build modifies {0}. This is not permitted. Before:\n {1}\nAfter:\n {2}", ManifestFile, CurrentText.Replace("\n", "\n "), OutputText.Replace("\n", "\n ")); } else { FileReference.WriteAllText(ManifestFile, OutputText); } } } } } // Write out the version file, if it's changed. Since this file is next to the executable, it may be used by multiple targets, and we should avoid modifying it unless necessary. if (TargetInfo.VersionFile != null && !UnrealBuildTool.IsFileInstalled(TargetInfo.VersionFile)) { DirectoryReference.CreateDirectory(TargetInfo.VersionFile.Directory); StringWriter Writer = new StringWriter(); Receipt.Version.Write(Writer); string Text = Writer.ToString(); if (!FileReference.Exists(TargetInfo.VersionFile) || File.ReadAllText(TargetInfo.VersionFile.FullName) != Text) { File.WriteAllText(TargetInfo.VersionFile.FullName, Text); } } // Write out the receipt if (!UnrealBuildTool.IsFileInstalled(TargetInfo.ReceiptFile)) { DirectoryReference.CreateDirectory(TargetInfo.ReceiptFile.Directory); Receipt.Write(TargetInfo.ReceiptFile); } return(0); }
public void StageBuildProductsFromReceipt(TargetReceipt Receipt) { // Stage all the build products needed at runtime foreach(BuildProduct BuildProduct in Receipt.BuildProducts) { // allow missing files if needed if (Receipt.bRequireDependenciesToExist == false && File.Exists(BuildProduct.Path) == false) { continue; } if(BuildProduct.Type == BuildProductType.Executable || BuildProduct.Type == BuildProductType.DynamicLibrary || BuildProduct.Type == BuildProductType.RequiredResource) { StageFile(StagedFileType.NonUFS, BuildProduct.Path); } else if(BuildProduct.Type == BuildProductType.SymbolFile) { StageFile(StagedFileType.DebugNonUFS, BuildProduct.Path); } } }
/// <summary> /// Adds a build product and its associated debug file to a receipt. /// </summary> /// <param name="OutputFile">Build product to add</param> /// <param name="DebugExtension">Extension for the matching debug file (may be null).</param> /// <param name="Receipt">Receipt to add to</param> static void AddBuildProductAndDebugFile(string OutputFile, BuildProductType OutputType, string DebugExtension, TargetReceipt Receipt, IUEToolChain ToolChain) { Receipt.AddBuildProduct(OutputFile, OutputType); if(!String.IsNullOrEmpty(DebugExtension) && ToolChain.ShouldAddDebugFileToReceipt(OutputFile, OutputType)) { Receipt.AddBuildProduct(Path.ChangeExtension(OutputFile, DebugExtension), BuildProductType.SymbolFile); } }
public void StageRuntimeDependenciesFromReceipt(TargetReceipt Receipt) { // Also stage any additional runtime dependencies, like ThirdParty DLLs foreach(RuntimeDependency RuntimeDependency in Receipt.RuntimeDependencies) { // allow missing files if needed if (Receipt.bRequireDependenciesToExist == false && File.Exists(RuntimeDependency.Path) == false) { continue; } StageFile(StagedFileType.NonUFS, RuntimeDependency.Path, RuntimeDependency.StagePath); } }
/// <summary> /// /// </summary> /// <param name="ProjectFile"></param> /// <param name="Config"></param> /// <param name="ProjectDirectory"></param> /// <param name="bIsUE4Game"></param> /// <param name="GameName"></param> /// <param name="ProjectName"></param> /// <param name="InEngineDir"></param> /// <param name="AppDirectory"></param> /// <param name="BuildReceiptFileName"></param> /// <param name="bSupportsPortrait"></param> /// <param name="bSupportsLandscape"></param> /// <param name="bSkipIcons"></param> /// <returns></returns> public static bool GeneratePList(FileReference ProjectFile, UnrealTargetConfiguration Config, DirectoryReference ProjectDirectory, bool bIsUE4Game, string GameName, string ProjectName, DirectoryReference InEngineDir, DirectoryReference AppDirectory, FileReference BuildReceiptFileName, out bool bSupportsPortrait, out bool bSupportsLandscape, out bool bSkipIcons) { TargetReceipt Receipt = TargetReceipt.Read(BuildReceiptFileName); return(new UEDeployIOS().GeneratePList(ProjectFile, Config, ProjectDirectory.FullName, bIsUE4Game, GameName, ProjectName, InEngineDir.FullName, AppDirectory.FullName, Receipt, out bSupportsPortrait, out bSupportsLandscape, out bSkipIcons)); }
public override void AddFilesToReceipt(TargetReceipt Receipt, UEBuildBinary Binary) { if (BuildConfiguration.bCreateStubIPA && Binary.Config.Type != UEBuildBinaryType.StaticLibrary) { string StubFile = Path.Combine (Path.GetDirectoryName (Binary.Config.OutputFilePath), Path.GetFileNameWithoutExtension (Binary.Config.OutputFilePath) + ".stub"); Receipt.AddBuildProduct(StubFile, BuildProductType.Executable); } }
/// <summary> /// Build a list of targets /// </summary> /// <param name="TargetDescriptors">Target descriptors</param> /// <param name="BuildConfiguration">Current build configuration</param> /// <param name="WorkingSet">The source file working set</param> /// <param name="Options">Additional options for the build</param> /// <returns>Result from the compilation</returns> public static void Build(List <TargetDescriptor> TargetDescriptors, BuildConfiguration BuildConfiguration, ISourceFileWorkingSet WorkingSet, BuildOptions Options) { // Create a makefile for each target TargetMakefile[] Makefiles = new TargetMakefile[TargetDescriptors.Count]; for (int TargetIdx = 0; TargetIdx < TargetDescriptors.Count; TargetIdx++) { Makefiles[TargetIdx] = CreateMakefile(BuildConfiguration, TargetDescriptors[TargetIdx], WorkingSet); } // Output the manifest for (int TargetIdx = 0; TargetIdx < TargetDescriptors.Count; TargetIdx++) { TargetDescriptor TargetDescriptor = TargetDescriptors[TargetIdx]; if (TargetDescriptor.LiveCodingManifest != null) { TargetMakefile Makefile = Makefiles[TargetIdx]; HotReload.WriteLiveCodingManifest(TargetDescriptor.LiveCodingManifest, Makefile.Actions); } } // Execute the build if ((Options & BuildOptions.SkipBuild) == 0) { // Make sure that none of the actions conflict with any other (producing output files differently, etc...) ActionGraph.CheckForConflicts(Makefiles.SelectMany(x => x.Actions)); // Find all the actions to be executed HashSet <Action>[] ActionsToExecute = new HashSet <Action> [TargetDescriptors.Count]; for (int TargetIdx = 0; TargetIdx < TargetDescriptors.Count; TargetIdx++) { ActionsToExecute[TargetIdx] = GetActionsForTarget(BuildConfiguration, TargetDescriptors[TargetIdx], Makefiles[TargetIdx]); } // If there are multiple targets being built, merge the actions together List <Action> MergedActionsToExecute; if (TargetDescriptors.Count == 1) { MergedActionsToExecute = new List <Action>(ActionsToExecute[0]); } else { MergedActionsToExecute = MergeActionGraphs(TargetDescriptors, ActionsToExecute); } // Link all the actions together ActionGraph.Link(MergedActionsToExecute); // Make sure the appropriate executor is selected foreach (TargetDescriptor TargetDescriptor in TargetDescriptors) { UEBuildPlatform BuildPlatform = UEBuildPlatform.GetBuildPlatform(TargetDescriptor.Platform); BuildConfiguration.bAllowXGE &= BuildPlatform.CanUseXGE(); BuildConfiguration.bAllowDistcc &= BuildPlatform.CanUseDistcc(); BuildConfiguration.bAllowSNDBS &= BuildPlatform.CanUseSNDBS(); } // Delete produced items that are outdated. ActionGraph.DeleteOutdatedProducedItems(MergedActionsToExecute); // Save all the action histories now that files have been removed. We have to do this after deleting produced items to ensure that any // items created during the build don't have the wrong command line. ActionHistory.SaveAll(); // Create directories for the outdated produced items. ActionGraph.CreateDirectoriesForProducedItems(MergedActionsToExecute); // Execute the actions if ((Options & BuildOptions.XGEExport) != 0) { // Just export to an XML file using (Timeline.ScopeEvent("XGE.ExportActions()")) { XGE.ExportActions(MergedActionsToExecute); } } else { // Execute the actions if (MergedActionsToExecute.Count == 0) { if ((Options & BuildOptions.Quiet) == 0) { Log.TraceInformation((TargetDescriptors.Count == 1)? "Target is up to date" : "Targets are up to date"); } } else { if ((Options & BuildOptions.Quiet) != 0) { Log.TraceInformation("Building {0}...", StringUtils.FormatList(TargetDescriptors.Select(x => x.Name).Distinct())); } OutputToolchainInfo(TargetDescriptors, Makefiles); using (Timeline.ScopeEvent("ActionGraph.ExecuteActions()")) { ActionGraph.ExecuteActions(BuildConfiguration, MergedActionsToExecute); } } // Run the deployment steps foreach (TargetMakefile Makefile in Makefiles) { if (Makefile.bDeployAfterCompile) { TargetReceipt Receipt = TargetReceipt.Read(Makefile.ReceiptFile); Log.TraceInformation("Deploying {0} {1} {2}...", Receipt.TargetName, Receipt.Platform, Receipt.Configuration); UEBuildPlatform.GetBuildPlatform(Receipt.Platform).Deploy(Receipt); } } } } }
/// <summary> /// Prepare the target for deployment /// </summary> /// <param name="Receipt">Receipt for the target being deployed</param> /// <returns>True if successful, false if not</returns> public virtual bool PrepTargetForDeployment(TargetReceipt Receipt) { return(true); }
/// <summary> /// Read a receipt from disk. /// </summary> /// <param name="FileName">Filename to read from</param> public static TargetReceipt Read(string FileName) { JsonObject RawObject = JsonObject.Read(FileName); // Read the initial fields string TargetName = RawObject.GetStringField("TargetName"); UnrealTargetPlatform Platform = RawObject.GetEnumField <UnrealTargetPlatform>("Platform"); UnrealTargetConfiguration Configuration = RawObject.GetEnumField <UnrealTargetConfiguration>("Configuration"); string BuildId = RawObject.GetStringField("BuildId"); // Try to read the build version BuildVersion Version; if (!BuildVersion.TryParse(RawObject.GetObjectField("Version"), out Version)) { throw new JsonParseException("Invalid 'Version' field"); } // Create the receipt TargetReceipt Receipt = new TargetReceipt(TargetName, Platform, Configuration, BuildId, Version); // Read the build products JsonObject[] BuildProductObjects; if (RawObject.TryGetObjectArrayField("BuildProducts", out BuildProductObjects)) { foreach (JsonObject BuildProductObject in BuildProductObjects) { string Path; BuildProductType Type; if (BuildProductObject.TryGetStringField("Path", out Path) && BuildProductObject.TryGetEnumField("Type", out Type)) { string Module; BuildProductObject.TryGetStringField("Module", out Module); BuildProduct NewBuildProduct = Receipt.AddBuildProduct(Path, Type); bool IsPrecompiled; if (BuildProductObject.TryGetBoolField("IsPrecompiled", out IsPrecompiled)) { NewBuildProduct.IsPrecompiled = IsPrecompiled; } } } } // Read the runtime dependencies JsonObject[] RuntimeDependencyObjects; if (RawObject.TryGetObjectArrayField("RuntimeDependencies", out RuntimeDependencyObjects)) { foreach (JsonObject RuntimeDependencyObject in RuntimeDependencyObjects) { string Path; if (RuntimeDependencyObject.TryGetStringField("Path", out Path)) { StagedFileType Type; if (!RuntimeDependencyObject.TryGetEnumField("Type", out Type)) { // Previous format included an optional IgnoreIfMissing flag, which was only used for debug files. We can explicitly reference them as DebugNonUFS files now. bool bIgnoreIfMissing; if (RuntimeDependencyObject.TryGetBoolField("IgnoreIfMissing", out bIgnoreIfMissing)) { bIgnoreIfMissing = false; } Type = bIgnoreIfMissing? StagedFileType.DebugNonUFS : StagedFileType.NonUFS; } Receipt.RuntimeDependencies.Add(Path, Type); } } } // Read the additional properties JsonObject[] AdditionalPropertyObjects; if (RawObject.TryGetObjectArrayField("AdditionalProperties", out AdditionalPropertyObjects)) { foreach (JsonObject AdditionalPropertyObject in AdditionalPropertyObjects) { string Name; if (AdditionalPropertyObject.TryGetStringField("Name", out Name)) { string Value; if (AdditionalPropertyObject.TryGetStringField("Value", out Value)) { Receipt.AdditionalProperties.Add(new ReceiptProperty(Name, Value)); } } } } // Read the precompiled dependencies string[] PrecompiledBuildDependencies; if (RawObject.TryGetStringArrayField("PrecompiledBuildDependencies", out PrecompiledBuildDependencies)) { Receipt.PrecompiledBuildDependencies.UnionWith(PrecompiledBuildDependencies); } // Read the precompiled dependencies string[] PrecompiledRuntimeDependencies; if (RawObject.TryGetStringArrayField("PrecompiledRuntimeDependencies", out PrecompiledRuntimeDependencies)) { Receipt.PrecompiledRuntimeDependencies.UnionWith(PrecompiledRuntimeDependencies); } return(Receipt); }
public override bool PrepTargetForDeployment(TargetReceipt Receipt) { // @todo Lumin: Need to create a MabuFile with no data files - including the executable!! return(true); }
/// <summary> /// Deploys the given target /// </summary> /// <param name="Receipt">Receipt for the target being deployed</param> public override void Deploy(TargetReceipt Receipt) { new UEDeployIOS().PrepTargetForDeployment(Receipt); }
/// <summary> /// Checks if all the files in a receipt are present and that all the DLLs are at the same version /// </summary> /// <returns> /// True if all the files are valid. /// </returns> static bool CheckBinariesExist(TargetReceipt Receipt) { bool bExist = true; foreach(BuildProduct BuildProduct in Receipt.BuildProducts) { if(BuildProduct.Type == BuildProductType.Executable || BuildProduct.Type == BuildProductType.DynamicLibrary) { if(!File.Exists(BuildProduct.Path)) { Log.TraceWarning("Missing binary: {0}", BuildProduct.Path); bExist = false; } } } return bExist; }
/// <summary> /// Constructor /// </summary> /// <param name="ProjectFile"></param> /// <param name="VersionFile"></param> /// <param name="ReceiptFile"></param> /// <param name="Receipt"></param> /// <param name="FileToManifest"></param> public WriteMetadataTargetInfo(FileReference ProjectFile, FileReference VersionFile, FileReference ReceiptFile, TargetReceipt Receipt, Dictionary <FileReference, ModuleManifest> FileToManifest) //string EngineManifestName, string ProjectManifestName, Dictionary<string, FileReference> ModuleNameToLocation) { this.ProjectFile = ProjectFile; this.VersionFile = VersionFile; this.ReceiptFile = ReceiptFile; this.Receipt = Receipt; this.FileToManifest = FileToManifest; }
/// <summary> /// Checks if all the files in a receipt have the same version /// </summary> /// <returns> /// True if all the files are valid. /// </returns> static bool CheckDynamicLibaryVersionsMatch(TargetReceipt Receipt) { List<Tuple<string, int>> BinaryVersions = new List<Tuple<string,int>>(); foreach(BuildProduct BuildProduct in Receipt.BuildProducts) { if(BuildProduct.Type == BuildProductType.DynamicLibrary) { int Version = BuildHostPlatform.Current.GetDllApiVersion(BuildProduct.Path); BinaryVersions.Add(new Tuple<string,int>(BuildProduct.Path, Version)); } } bool bMatch = true; if(BinaryVersions.Count > 0 && !BinaryVersions.All(x => x.Item2 == BinaryVersions[0].Item2)) { Log.TraceWarning("Detected mismatch in binary versions:"); foreach(Tuple<string, int> BinaryVersion in BinaryVersions) { Log.TraceWarning(" {0} has API version {1}", BinaryVersion.Item1, BinaryVersion.Item2); File.Delete(BinaryVersion.Item1); } bMatch = false; } return bMatch; }
public override void AddFilesToReceipt(TargetReceipt Receipt, UEBuildBinary Binary) { // the binary will have all of the .so's in the output files, we need to trim down to the shared apk (which is what needs to go into the manifest) if (Binary.Config.Type != UEBuildBinaryType.StaticLibrary) { foreach (string BinaryPath in Binary.Config.OutputFilePaths) { string ApkFile = Path.ChangeExtension(BinaryPath, ".apk"); Receipt.AddBuildProduct(ApkFile, BuildProductType.Executable); } } }
/// <summary> /// Copy constructor /// </summary> /// <param name="InOther">Receipt to copy from</param> public TargetReceipt(TargetReceipt Other) { foreach(BuildProduct OtherBuildProduct in Other.BuildProducts) { BuildProducts.Add(new BuildProduct(OtherBuildProduct)); } foreach(RuntimeDependency OtherRuntimeDependency in Other.RuntimeDependencies) { RuntimeDependencies.Add(new RuntimeDependency(OtherRuntimeDependency)); } }