You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#lockdown Nick.Penwarden #rb none ========================== MAJOR FEATURES + CHANGES ========================== Change 3129636 on 2016/09/17 by Ben.Marsh UBT: Add a "-nolink" option which allows compiling object files without linking them into an executable. Useful for non-unity builds, which take a very long time to link or fail on some platforms due to command lines being too long, PDB file having too many records, etc... Change 3129825 on 2016/09/18 by Ben.Marsh UBT: Don't force Linux to build in unity; it seems to build fine without. Change 3129965 on 2016/09/19 by Matthew.Griffin Duplicating CL#3129960 from Release-4.13 Exclude NetworkProfiler when building CS tools for Linux Change3130653on 2016/09/19 by Ben.Marsh UHT: Fix missing "Error:" prefix in output log, causing messages to be ignored for failure emails. Change3130662on 2016/09/19 by Ben.Marsh EC: Prevent UHT failures from being reported twice, and remove the need for special case to show UHT summary output. Change 3131956 on 2016/09/20 by Matthew.Griffin Addtional fixes for compiling Editor as a monolithic executable Change so monolithic editor is output to Project Binaries directory Removed duplicated ReturnContainerIndexFromChannelName function Only check for out of date modules for non monolithic editor Don't define GIsGameAgnosticExe or PER_MODULE_BOILERPLATE for monolithic editor, done elsewhere Correct IMPLEMENT_MODULE for QuadricMeshReduction and AudioCapture modules Change 3132112 on 2016/09/20 by Ben.Marsh Docs: Remove reference to UBT environment variables from configuration docs. Change 3132815 on 2016/09/20 by Ben.Marsh AutomationTool: Delete GUBP. Everything now uses BuildGraph! Change 3132871 on 2016/09/20 by Ben.Marsh UBT: Remove GUBP callbacks from TargetRules instances. Change 3132987 on 2016/09/20 by Ben.Marsh Allow public distribution of the compiled SimplygonMeshUtilities binaries. Change 3133974 on 2016/09/21 by Ben.Marsh Allow public distribution of the SimplygonSwarm module. Requires a separate Simplygon DLL (still in a NotForLicensees folder) to function correctly. Change 3137228 on 2016/09/22 by Ben.Marsh UAT: Merging fix to parallel executor on Linux from 4.13 branch. Change 3139783 on 2016/09/26 by Matthew.Griffin Fixed Xbox support for Installed Builds Corrected typo in Xbox+PS4 filter creation and added XboxOnePackageNameUtil.exe Added Xbox versions of ThirdParty libs that hadn't been specified until now Change 3141721 on 2016/09/27 by Ben.Marsh Remove declaration of circular references between FbxAutomationTestBuilder and LevelEditor; causes LevelEditor to be built differently if plugin is enabled, which results in shared build products being invalidated by switching between games. Change 3141789 on 2016/09/27 by Ben.Marsh UBT: Retain the ".suppressed" part of output file names when building import libraries for circularly referenced modules. Change 3141805 on 2016/09/27 by Ben.Marsh UBT: Allow reusing build ids in version manifests as long as we aren't modifying any engine binaries (building more or fewer is permitted), and merge manifests together if possible. Allows building the entire solution through Visual Studio, when some projects may build more modules than another. Change 3141980 on 2016/09/27 by Ben.Marsh EC: Include a "Steps to Reproduce" section in failure emails, which gives the command line to run to execute the step. Change 3143996 on 2016/09/28 by Ben.Marsh BuildGraph: Fix exported job steps having dependencies on nodes behind triggers, causing jobs to never terminate. Change 3144696 on 2016/09/29 by Matthew.Griffin Adding -NoSharedPCH to NonUnity build steps and split them into separate nodes for UE4Editor and UE4Game Fixed redefinition of __WINDOWS_DS__ Change 3144931 on 2016/09/29 by Ben.Marsh Core: Changes to search paths for DLL loading. * The default binaries directory is now added to the list of search paths. Normally LoadLibrary finds these without needing to preload them, but plugins can change the global search paths by calling SetDefaultDllDirectories(). * Only the top entry of the DLL directory stack is searched. There is typically only one directory here anyway, but the intent is more consistent with the operation of SetDllDirectory(). * Resolved import paths are converted to absolute, so the resulting calls to LoadLibrary will not be influenced by calls to SetDefaultDllDirectories() changing the base directory. * Search paths aren't de-duplicated any more. They don't overlap in practice, and it's not expensive even if they do. Change 3144932 on 2016/09/29 by Ben.Marsh Vulkan: Only add vulkan-1.dll as a delay load dependency from the VulkanRHI module, otherwise it can be added to the linker command-line 20 or more times. Change 3145011 on 2016/09/29 by Ben.Marsh Core: Include the compatible changelist in version manifests, so local builds after syncing with UGS will have the correct compatible changelist numbers post-hotfix. [CL 3146509 by Ben Marsh in Main branch]
331 lines
14 KiB
C#
331 lines
14 KiB
C#
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Threading;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using AutomationTool;
|
|
using UnrealBuildTool;
|
|
|
|
[Help("Builds a plugin, and packages it for distribution")]
|
|
[Help("Plugin", "Specify the path to the descriptor file for the plugin that should be packaged")]
|
|
[Help("NoHostPlatform", "Prevent compiling for the editor platform on the host")]
|
|
[Help("TargetPlatforms", "Specify a list of target platforms to build, separated by '+' characters (eg. -TargetPlatforms=Win32+Win64). Default is all the Rocket target platforms.")]
|
|
[Help("Package", "The path which the build artifacts should be packaged to, ready for distribution.")]
|
|
class BuildPlugin : BuildCommand
|
|
{
|
|
public override void ExecuteBuild()
|
|
{
|
|
// Get the plugin filename
|
|
string PluginParam = ParseParamValue("Plugin");
|
|
if(PluginParam == null)
|
|
{
|
|
throw new AutomationException("Missing -Plugin=... argument");
|
|
}
|
|
|
|
// Check it exists
|
|
FileReference PluginFile = new FileReference(PluginParam);
|
|
if (!PluginFile.Exists())
|
|
{
|
|
throw new AutomationException("Plugin '{0}' not found", PluginFile.FullName);
|
|
}
|
|
|
|
// Get the output directory
|
|
string PackageParam = ParseParamValue("Package");
|
|
if (PackageParam == null)
|
|
{
|
|
throw new AutomationException("Missing -Package=... argument");
|
|
}
|
|
|
|
// Make sure the packaging directory is valid
|
|
DirectoryReference PackageDir = new DirectoryReference(PackageParam);
|
|
if (PluginFile.IsUnderDirectory(PackageDir))
|
|
{
|
|
throw new AutomationException("Packaged plugin output directory must be different to source");
|
|
}
|
|
if (PackageDir.IsUnderDirectory(DirectoryReference.Combine(CommandUtils.RootDirectory, "Engine")))
|
|
{
|
|
throw new AutomationException("Output directory for packaged plugin must be outside engine directory");
|
|
}
|
|
|
|
// Clear the output directory of existing stuff
|
|
if (PackageDir.Exists())
|
|
{
|
|
CommandUtils.DeleteDirectoryContents(PackageDir.FullName);
|
|
}
|
|
else
|
|
{
|
|
PackageDir.CreateDirectory();
|
|
}
|
|
|
|
// Create a placeholder FilterPlugin.ini with instructions on how to use it
|
|
FileReference SourceFilterFile = FileReference.Combine(PluginFile.Directory, "Config", "FilterPlugin.ini");
|
|
if (!SourceFilterFile.Exists())
|
|
{
|
|
List<string> Lines = new List<string>();
|
|
Lines.Add("[FilterPlugin]");
|
|
Lines.Add("; This section lists additional files which will be packaged along with your plugin. Paths should be listed relative to the root plugin directory, and");
|
|
Lines.Add("; may include \"...\", \"*\", and \"?\" wildcards to match directories, files, and individual characters respectively.");
|
|
Lines.Add(";");
|
|
Lines.Add("; Examples:");
|
|
Lines.Add("; /README.txt");
|
|
Lines.Add("; /Extras/...");
|
|
Lines.Add("; /Binaries/ThirdParty/*.dll");
|
|
SourceFilterFile.Directory.CreateDirectory();
|
|
CommandUtils.WriteAllLines_NoExceptions(SourceFilterFile.FullName, Lines.ToArray());
|
|
}
|
|
|
|
// Create a host project for the plugin. For script generator plugins, we need to have UHT be able to load it, which can only happen if it's enabled in a project.
|
|
FileReference HostProjectFile = FileReference.Combine(PackageDir, "HostProject", "HostProject.uproject");
|
|
FileReference HostProjectPluginFile = CreateHostProject(HostProjectFile, PluginFile);
|
|
|
|
// Read the plugin
|
|
CommandUtils.Log("Reading plugin from {0}...", HostProjectPluginFile);
|
|
PluginDescriptor Plugin = PluginDescriptor.FromFile(HostProjectPluginFile, false);
|
|
|
|
// Compile the plugin for all the target platforms
|
|
List<UnrealTargetPlatform> HostPlatforms = ParseParam("NoHostPlatform")? new List<UnrealTargetPlatform>() : new List<UnrealTargetPlatform> { BuildHostPlatform.Current.Platform };
|
|
List<UnrealTargetPlatform> TargetPlatforms = GetTargetPlatforms(this, BuildHostPlatform.Current.Platform).Where(x => IsCodeTargetPlatform(BuildHostPlatform.Current.Platform, x)).ToList();
|
|
FileReference[] BuildProducts = CompilePlugin(HostProjectFile, HostProjectPluginFile, Plugin, HostPlatforms, TargetPlatforms, "");
|
|
|
|
// Package up the final plugin data
|
|
PackagePlugin(HostProjectPluginFile, BuildProducts, PackageDir);
|
|
|
|
// Remove the host project
|
|
if(!ParseParam("NoDeleteHostProject"))
|
|
{
|
|
CommandUtils.DeleteDirectory(HostProjectFile.Directory.FullName);
|
|
}
|
|
}
|
|
|
|
FileReference CreateHostProject(FileReference HostProjectFile, FileReference PluginFile)
|
|
{
|
|
DirectoryReference HostProjectDir = HostProjectFile.Directory;
|
|
HostProjectDir.CreateDirectory();
|
|
|
|
// Create the new project descriptor
|
|
File.WriteAllText(HostProjectFile.FullName, "{ \"FileVersion\": 3, \"Plugins\": [ { \"Name\": \"" + PluginFile.GetFileNameWithoutExtension() + "\", \"Enabled\": true } ] }");
|
|
|
|
// Get the plugin directory in the host project, and copy all the files in
|
|
DirectoryReference HostProjectPluginDir = DirectoryReference.Combine(HostProjectDir, "Plugins", PluginFile.GetFileNameWithoutExtension());
|
|
CommandUtils.ThreadedCopyFiles(PluginFile.Directory.FullName, HostProjectPluginDir.FullName);
|
|
CommandUtils.DeleteDirectory(true, DirectoryReference.Combine(HostProjectPluginDir, "Intermediate").FullName);
|
|
|
|
// Return the path to the plugin file in the host project
|
|
return FileReference.Combine(HostProjectPluginDir, PluginFile.GetFileName());
|
|
}
|
|
|
|
FileReference[] CompilePlugin(FileReference HostProjectFile, FileReference HostProjectPluginFile, PluginDescriptor Plugin, List<UnrealTargetPlatform> HostPlatforms, List<UnrealTargetPlatform> TargetPlatforms, string AdditionalArgs)
|
|
{
|
|
List<string> ReceiptFileNames = new List<string>();
|
|
|
|
// Build the host platforms
|
|
if(HostPlatforms.Count > 0)
|
|
{
|
|
CommandUtils.Log("Building plugin for host platforms: {0}", String.Join(", ", HostPlatforms));
|
|
foreach (UnrealTargetPlatform HostPlatform in HostPlatforms)
|
|
{
|
|
if (Plugin.bCanBeUsedWithUnrealHeaderTool)
|
|
{
|
|
CompilePluginWithUBT(null, HostProjectPluginFile, Plugin, "UnrealHeaderTool", TargetRules.TargetType.Program, HostPlatform, UnrealTargetConfiguration.Development, ReceiptFileNames, String.Format("{0} -plugin {1}", AdditionalArgs, CommandUtils.MakePathSafeToUseWithCommandLine(HostProjectPluginFile.FullName)));
|
|
}
|
|
CompilePluginWithUBT(HostProjectFile, HostProjectPluginFile, Plugin, "UE4Editor", TargetRules.TargetType.Editor, HostPlatform, UnrealTargetConfiguration.Development, ReceiptFileNames, AdditionalArgs);
|
|
}
|
|
}
|
|
|
|
// Add the game targets
|
|
if(TargetPlatforms.Count > 0)
|
|
{
|
|
CommandUtils.Log("Building plugin for target platforms: {0}", String.Join(", ", TargetPlatforms));
|
|
foreach (UnrealTargetPlatform TargetPlatform in TargetPlatforms)
|
|
{
|
|
CompilePluginWithUBT(HostProjectFile, HostProjectPluginFile, Plugin, "UE4Game", TargetRules.TargetType.Game, TargetPlatform, UnrealTargetConfiguration.Development, ReceiptFileNames, null);
|
|
CompilePluginWithUBT(HostProjectFile, HostProjectPluginFile, Plugin, "UE4Game", TargetRules.TargetType.Game, TargetPlatform, UnrealTargetConfiguration.Shipping, ReceiptFileNames, null);
|
|
}
|
|
}
|
|
|
|
// Package the plugin to the output folder
|
|
List<BuildProduct> BuildProducts = GetBuildProductsFromReceipts(UnrealBuildTool.UnrealBuildTool.EngineDirectory, HostProjectFile.Directory, ReceiptFileNames);
|
|
return BuildProducts.Select(x => new FileReference(x.Path)).ToArray();
|
|
}
|
|
|
|
void CompilePluginWithUBT(FileReference HostProjectFile, FileReference HostProjectPluginFile, PluginDescriptor Plugin, string TargetName, TargetRules.TargetType TargetType, UnrealTargetPlatform Platform, UnrealTargetConfiguration Configuration, List<string> ReceiptFileNames, string InAdditionalArgs)
|
|
{
|
|
// Find a list of modules that need to be built for this plugin
|
|
List<string> ModuleNames = new List<string>();
|
|
foreach(ModuleDescriptor Module in Plugin.Modules)
|
|
{
|
|
bool bBuildDeveloperTools = (TargetType == TargetRules.TargetType.Editor || TargetType == TargetRules.TargetType.Program);
|
|
bool bBuildEditor = (TargetType == TargetRules.TargetType.Editor);
|
|
if(Module.IsCompiledInConfiguration(Platform, TargetType, bBuildDeveloperTools, bBuildEditor))
|
|
{
|
|
ModuleNames.Add(Module.Name);
|
|
}
|
|
}
|
|
|
|
// Add these modules to the build agenda
|
|
if(ModuleNames.Count > 0)
|
|
{
|
|
string Arguments = "";// String.Format("-plugin {0}", CommandUtils.MakePathSafeToUseWithCommandLine(PluginFile.FullName));
|
|
foreach(string ModuleName in ModuleNames)
|
|
{
|
|
Arguments += String.Format(" -module {0}", ModuleName);
|
|
}
|
|
|
|
string Architecture = UEBuildPlatform.GetBuildPlatform(Platform).CreateContext(HostProjectFile).GetActiveArchitecture();
|
|
|
|
string ReceiptFileName = TargetReceipt.GetDefaultPath(HostProjectPluginFile.Directory.FullName, TargetName, Platform, Configuration, Architecture);
|
|
Arguments += String.Format(" -receipt {0}", CommandUtils.MakePathSafeToUseWithCommandLine(ReceiptFileName));
|
|
ReceiptFileNames.Add(ReceiptFileName);
|
|
|
|
if(!String.IsNullOrEmpty(InAdditionalArgs))
|
|
{
|
|
Arguments += InAdditionalArgs;
|
|
}
|
|
|
|
CommandUtils.RunUBT(CmdEnv, UE4Build.GetUBTExecutable(), String.Format("{0} {1} {2}{3} {4}", TargetName, Platform, Configuration, (HostProjectFile == null)? "" : String.Format(" -project=\"{0}\"", HostProjectFile.FullName), Arguments));
|
|
}
|
|
}
|
|
|
|
static List<BuildProduct> GetBuildProductsFromReceipts(DirectoryReference EngineDir, DirectoryReference ProjectDir, List<string> ReceiptFileNames)
|
|
{
|
|
List<BuildProduct> BuildProducts = new List<BuildProduct>();
|
|
foreach(string ReceiptFileName in ReceiptFileNames)
|
|
{
|
|
TargetReceipt Receipt;
|
|
if(!TargetReceipt.TryRead(ReceiptFileName, out Receipt))
|
|
{
|
|
throw new AutomationException("Missing or invalid target receipt ({0})", ReceiptFileName);
|
|
}
|
|
Receipt.ExpandPathVariables(EngineDir, ProjectDir);
|
|
BuildProducts.AddRange(Receipt.BuildProducts);
|
|
}
|
|
return BuildProducts;
|
|
}
|
|
|
|
static void PackagePlugin(FileReference SourcePluginFile, IEnumerable<FileReference> BuildProducts, DirectoryReference TargetDir)
|
|
{
|
|
DirectoryReference SourcePluginDir = SourcePluginFile.Directory;
|
|
|
|
// Copy all the files to the output directory
|
|
FileReference[] SourceFiles = FilterPluginFiles(SourcePluginFile, BuildProducts).ToArray();
|
|
foreach(FileReference SourceFile in SourceFiles)
|
|
{
|
|
FileReference TargetFile = FileReference.Combine(TargetDir, SourceFile.MakeRelativeTo(SourcePluginDir));
|
|
CommandUtils.CopyFile(SourceFile.FullName, TargetFile.FullName);
|
|
CommandUtils.SetFileAttributes(TargetFile.FullName, ReadOnly: false);
|
|
}
|
|
|
|
// Get the output plugin filename
|
|
FileReference TargetPluginFile = FileReference.Combine(TargetDir, SourcePluginFile.GetFileName());
|
|
PluginDescriptor NewDescriptor = PluginDescriptor.FromFile(TargetPluginFile, false);
|
|
NewDescriptor.bEnabledByDefault = true;
|
|
NewDescriptor.bInstalled = true;
|
|
NewDescriptor.Save(TargetPluginFile.FullName, false);
|
|
}
|
|
|
|
static IEnumerable<FileReference> FilterPluginFiles(FileReference PluginFile, IEnumerable<FileReference> BuildProducts)
|
|
{
|
|
// Set up the default filter
|
|
FileFilter Filter = new FileFilter();
|
|
Filter.AddRuleForFile(PluginFile.FullName, PluginFile.Directory.FullName, FileFilterType.Include);
|
|
Filter.AddRuleForFiles(BuildProducts, PluginFile.Directory, FileFilterType.Include);
|
|
Filter.Include("/Binaries/ThirdParty/...");
|
|
Filter.Include("/Resources/...");
|
|
Filter.Include("/Content/...");
|
|
Filter.Include("/Intermediate/Build/.../Inc/...");
|
|
Filter.Include("/Source/...");
|
|
|
|
// Add custom rules for each platform
|
|
FileReference FilterFile = FileReference.Combine(PluginFile.Directory, "Config", "FilterPlugin.ini");
|
|
if(FilterFile.Exists())
|
|
{
|
|
CommandUtils.Log("Reading filter rules from {0}", FilterFile);
|
|
Filter.ReadRulesFromFile(FilterFile.FullName, "FilterPlugin");
|
|
}
|
|
|
|
// Apply the standard exclusion rules
|
|
Filter.ExcludeConfidentialFolders();
|
|
Filter.ExcludeConfidentialPlatforms();
|
|
|
|
// Apply the filter to the plugin directory
|
|
return Filter.ApplyToDirectory(PluginFile.Directory, true);
|
|
}
|
|
|
|
static List<UnrealTargetPlatform> GetTargetPlatforms(BuildCommand Command, UnrealTargetPlatform HostPlatform)
|
|
{
|
|
List<UnrealTargetPlatform> TargetPlatforms = new List<UnrealTargetPlatform>();
|
|
if(!Command.ParseParam("NoTargetPlatforms"))
|
|
{
|
|
// Always support the host platform
|
|
TargetPlatforms.Add(HostPlatform);
|
|
|
|
// Add other target platforms for each host platform
|
|
if(HostPlatform == UnrealTargetPlatform.Win64)
|
|
{
|
|
TargetPlatforms.Add(UnrealTargetPlatform.Win32);
|
|
}
|
|
if(HostPlatform == UnrealTargetPlatform.Win64 || HostPlatform == UnrealTargetPlatform.Mac)
|
|
{
|
|
TargetPlatforms.Add(UnrealTargetPlatform.Android);
|
|
}
|
|
if(HostPlatform == UnrealTargetPlatform.Win64 || HostPlatform == UnrealTargetPlatform.Mac)
|
|
{
|
|
TargetPlatforms.Add(UnrealTargetPlatform.IOS);
|
|
}
|
|
if (HostPlatform == UnrealTargetPlatform.Win64 || HostPlatform == UnrealTargetPlatform.Mac)
|
|
{
|
|
TargetPlatforms.Add(UnrealTargetPlatform.TVOS);
|
|
}
|
|
if (HostPlatform == UnrealTargetPlatform.Win64)
|
|
{
|
|
TargetPlatforms.Add(UnrealTargetPlatform.Linux);
|
|
}
|
|
if(HostPlatform == UnrealTargetPlatform.Win64 || HostPlatform == UnrealTargetPlatform.Mac )
|
|
{
|
|
TargetPlatforms.Add(UnrealTargetPlatform.HTML5);
|
|
}
|
|
|
|
// Remove any platforms that aren't enabled on the command line
|
|
string TargetPlatformFilter = Command.ParseParamValue("TargetPlatforms", null);
|
|
if(TargetPlatformFilter != null)
|
|
{
|
|
List<UnrealTargetPlatform> NewTargetPlatforms = new List<UnrealTargetPlatform>();
|
|
foreach (string TargetPlatformName in TargetPlatformFilter.Split(new char[]{ '+' }, StringSplitOptions.RemoveEmptyEntries))
|
|
{
|
|
UnrealTargetPlatform TargetPlatform;
|
|
if(!Enum.TryParse(TargetPlatformName, out TargetPlatform))
|
|
{
|
|
throw new AutomationException("Unknown target platform '{0}' specified on command line");
|
|
}
|
|
else if(TargetPlatforms.Contains(TargetPlatform))
|
|
{
|
|
NewTargetPlatforms.Add(TargetPlatform);
|
|
}
|
|
}
|
|
TargetPlatforms = NewTargetPlatforms;
|
|
}
|
|
}
|
|
return TargetPlatforms;
|
|
}
|
|
|
|
static bool IsCodeTargetPlatform(UnrealTargetPlatform HostPlatform, UnrealTargetPlatform TargetPlatform)
|
|
{
|
|
if(TargetPlatform == UnrealTargetPlatform.Linux)
|
|
{
|
|
return false;
|
|
}
|
|
if(HostPlatform == UnrealTargetPlatform.Win64 && TargetPlatform == UnrealTargetPlatform.IOS)
|
|
{
|
|
return false;
|
|
}
|
|
if (HostPlatform == UnrealTargetPlatform.Win64 && TargetPlatform == UnrealTargetPlatform.TVOS)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|