Files
UnrealEngineUWP/Engine/Source/Programs/AutomationTool/Scripts/BuildPluginCommand.Automation.cs
Marc Audy 69d9a1a087 Copying //UE4/Orion-Staging to //UE4/Dev-Main (Source: //UE4/Orion-Staging @ 3134206)
#lockdown Nick.Penwarden
#rb none
#codereview Andrew.Grant
==========================
MAJOR FEATURES + CHANGES
==========================

Change 2845744 on 2016/01/27 by Andrew.Grant

	Merging from //Orion/Dev-General @ 2845681

Change 2849210 on 2016/01/29 by Andrew.Grant

	Merging using //Orion/Dev-General/_To_//UE4/Orion-Stating

Change 2854307 on 2016/02/03 by Andrew.Grant

	Merging using //Orion/Dev-General/_To_//UE4/Orion-Stating

Change 2880059 on 2016/02/24 by Andrew.Grant

	Merging  //Orion/Dev-General @ 2879808

Change 2891205 on 2016/03/02 by Andrew.Grant

	Merging //Orion/Dev-General @ 2889885

Change 2904080 on 2016/03/10 by Andrew.Grant

	Merging using //Orion/Dev-General @ 2902652

Change 2950235 on 2016/04/20 by Andrew.Grant

	Automerged files from Dev-General

Change 2976227 on 2016/05/12 by Andrew.Grant

	Autoresolved files from using //Orion/Dev-General

Change 3016193 on 2016/06/16 by Andrew.Grant

	Merging //Orion/Dev-General @ 3015761

Change 3033336 on 2016/06/29 by Andrew.Grant

	Merging using //Orion/Dev-General/_To_//UE4/Orion-Stating

Change 3037514 on 2016/07/05 by Andrew.Grant

	Merging from //Orion/Dev-General @ 3037465

Change 3091216 on 2016/08/16 by Andrew.Grant

	Merging using //Orion/Dev-General/_To_//UE4/Orion-Stating

Change 3107127 on 2016/08/30 by Andrew.Grant

	Merging using //Orion/Dev-General/_To_//UE4/Orion-Stating

Change 3129090 on 2016/09/16 by Andrew.Grant

	Autoresolved files from Dev-Gen @ 3130045

Change 3130536 on 2016/09/19 by Andrew.Grant

	To Resolve

Change 3130537 on 2016/09/19 by Andrew.Grant

	Tricky merges?

Change 3130810 on 2016/09/19 by Andrew.Grant

	Merging from //Orion/Dev-General @ 3130045

Change 3130880 on 2016/09/19 by Andrew.Grant

	Blueprint fix

Change 3131009 on 2016/09/19 by Andrew.Grant

	removed spammy warning

Change 3131216 on 2016/09/19 by Andrew.Grant

	Content fixes for Orion-Staging

Change 3131700 on 2016/09/19 by Andrew.Grant

	Merging //UE4/Dev-Main to Orion-Staging (//UE4/Orion-Staging)

Change 3132144 on 2016/09/20 by Andrew.Grant

	Merging test framework work from Dev-General

Change 3132154 on 2016/09/20 by Andrew.Grant

	Fix for linux client

Change 3132179 on 2016/09/20 by Andrew.Grant

	Fixed breakages due to latest //UE4/Main

Change 3132948 on 2016/09/20 by Andrew.Grant

	Fix for UE-36216 (replicating 3125764 from ForniteMain)

Change 3133103 on 2016/09/20 by Andrew.Grant

	Added EpicCMSUIFramework and CommonUI to Fortnite plugin

Change 3133327 on 2016/09/20 by Andrew.Grant

	Orion automation improvements

Change 3133555 on 2016/09/20 by Andrew.Grant

	FIx for UE-36226

Change 3133996 on 2016/09/21 by Andrew.Grant

	REbuilt texture streaming

Change 3134204 on 2016/09/21 by Andrew.Grant

	Merging audio files from Orion with correct compression settings

Change 3134205 on 2016/09/21 by Andrew.Grant

	Fix for gameplay tag ordering from Orion, and fix for soak test report numbers

Change 3134206 on 2016/09/21 by Andrew.Grant

	Merging //UE4/Dev-Main to Orion-Staging (//UE4/Orion-Staging)

[CL 3135156 by Marc Audy in Main branch]
2016-09-21 18:16:12 -04:00

256 lines
12 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 = Rocket.RocketBuild.GetTargetPlatforms(this, BuildHostPlatform.Current.Platform).Where(x => Rocket.RocketBuild.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);
}
}