2016-01-07 08:17:16 -05:00
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
2015-05-01 10:58:14 -04:00
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")]
2015-05-06 11:06:35 -04:00
[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")]
2015-05-01 15:01:10 -04:00
[Help("TargetPlatforms", "Specify a list of target platforms to build, separated by '+' characters (eg. -TargetPlatforms=Win32+Win64). Default is all the Rocket target platforms.")]
2015-05-06 11:07:47 -04:00
[Help("Package", "The path which the build artifacts should be packaged to, ready for distribution.")]
2015-05-01 10:58:14 -04:00
class BuildPlugin : BuildCommand
{
public override void ExecuteBuild ( )
{
// Get the plugin filename
2016-03-11 09:55:03 -05:00
string PluginParam = ParseParamValue ( "Plugin" ) ;
if ( PluginParam = = null )
2015-05-01 10:58:14 -04:00
{
throw new AutomationException ( "Plugin file name was not specified via the -plugin argument" ) ;
}
2015-05-06 11:06:35 -04:00
2015-05-01 10:58:14 -04:00
// Read the plugin
2016-03-11 09:55:03 -05:00
FileReference PluginFile = new FileReference ( PluginParam ) ;
DirectoryReference PluginDirectory = PluginFile . Directory ;
PluginDescriptor Plugin = PluginDescriptor . FromFile ( PluginFile ) ;
2015-05-01 10:58:14 -04:00
// Clean the intermediate build directory
2016-03-11 09:55:03 -05:00
DirectoryReference IntermediateBuildDirectory = DirectoryReference . Combine ( PluginDirectory , "Intermediate" , "Build" ) ;
if ( CommandUtils . DirectoryExists ( IntermediateBuildDirectory . FullName ) )
2015-05-01 10:58:14 -04:00
{
2016-03-11 09:55:03 -05:00
CommandUtils . DeleteDirectory ( IntermediateBuildDirectory . FullName ) ;
2015-05-01 10:58:14 -04:00
}
2016-03-11 09:55:03 -05:00
// Create a host project for the plugin. For script generator plugins, we need to have UHT be able to load it - and that can only happen if it's enabled in a project.
DirectoryReference HostProjectDirectory = DirectoryReference . Combine ( new DirectoryReference ( CommandUtils . CmdEnv . LocalRoot ) , "HostProject" ) ;
if ( CommandUtils . DirectoryExists ( HostProjectDirectory . FullName ) )
{
CommandUtils . DeleteDirectory ( HostProjectDirectory . FullName ) ;
}
DirectoryReference HostProjectPluginDirectory = DirectoryReference . Combine ( HostProjectDirectory , "Plugins" , PluginFile . GetFileNameWithoutExtension ( ) ) ;
string [ ] CopyPluginFiles = Directory . EnumerateFiles ( PluginDirectory . FullName , "*" , SearchOption . AllDirectories ) . ToArray ( ) ;
foreach ( string CopyPluginFile in CopyPluginFiles )
{
CommandUtils . CopyFile ( CopyPluginFile , CommandUtils . MakeRerootedFilePath ( CopyPluginFile , PluginDirectory . FullName , HostProjectPluginDirectory . FullName ) ) ;
}
FileReference HostProjectPluginFile = FileReference . Combine ( HostProjectPluginDirectory , PluginFile . GetFileName ( ) ) ;
FileReference HostProjectFile = FileReference . Combine ( HostProjectDirectory , "HostProject.uproject" ) ;
File . WriteAllText ( HostProjectFile . FullName , "{ \"FileVersion\": 3, \"Plugins\": [ { \"Name\": \"" + PluginFile . GetFileNameWithoutExtension ( ) + "\", \"Enabled\": true } ] }" ) ;
2015-05-05 18:52:17 -04:00
// Get any additional arguments from the commandline
string AdditionalArgs = "" ;
2015-05-01 15:01:10 -04:00
// Build the host platforms
2015-05-01 10:58:14 -04:00
List < string > ReceiptFileNames = new List < string > ( ) ;
2015-05-01 15:01:10 -04:00
UnrealTargetPlatform HostPlatform = BuildHostPlatform . Current . Platform ;
if ( ! ParseParam ( "NoHostPlatform" ) )
{
2016-03-11 09:55:03 -05:00
if ( Plugin . bCanBeUsedWithUnrealHeaderTool )
{
2016-03-17 11:10:14 -04:00
BuildPluginWithUBT ( PluginFile , Plugin , null , "UnrealHeaderTool" , TargetRules . TargetType . Program , HostPlatform , UnrealTargetConfiguration . Development , ReceiptFileNames , String . Format ( "{0} -plugin {1}" , AdditionalArgs , CommandUtils . MakePathSafeToUseWithCommandLine ( HostProjectPluginFile . FullName ) ) ) ;
2016-03-11 09:55:03 -05:00
}
2016-03-17 11:10:14 -04:00
BuildPluginWithUBT ( PluginFile , Plugin , HostProjectFile , "UE4Editor" , TargetRules . TargetType . Editor , HostPlatform , UnrealTargetConfiguration . Development , ReceiptFileNames , AdditionalArgs ) ;
2015-05-01 15:01:10 -04:00
}
// Add the game targets
List < UnrealTargetPlatform > TargetPlatforms = Rocket . RocketBuild . GetTargetPlatforms ( this , HostPlatform ) ;
foreach ( UnrealTargetPlatform TargetPlatform in TargetPlatforms )
{
if ( Rocket . RocketBuild . IsCodeTargetPlatform ( HostPlatform , TargetPlatform ) )
{
2016-03-17 11:10:14 -04:00
BuildPluginWithUBT ( PluginFile , Plugin , HostProjectFile , "UE4Game" , TargetRules . TargetType . Game , TargetPlatform , UnrealTargetConfiguration . Development , ReceiptFileNames , AdditionalArgs ) ;
BuildPluginWithUBT ( PluginFile , Plugin , HostProjectFile , "UE4Game" , TargetRules . TargetType . Game , TargetPlatform , UnrealTargetConfiguration . Shipping , ReceiptFileNames , AdditionalArgs ) ;
2015-05-01 15:01:10 -04:00
}
}
2015-05-01 10:58:14 -04:00
// Package the plugin to the output folder
string PackageDirectory = ParseParamValue ( "Package" ) ;
if ( PackageDirectory ! = null )
{
2016-03-11 09:55:03 -05:00
List < BuildProduct > BuildProducts = GetBuildProductsFromReceipts ( UnrealBuildTool . UnrealBuildTool . EngineDirectory , HostProjectDirectory , ReceiptFileNames ) ;
PackagePlugin ( HostProjectPluginFile , BuildProducts , PackageDirectory ) ;
2015-05-01 10:58:14 -04:00
}
}
2016-03-17 11:10:14 -04:00
void BuildPluginWithUBT ( FileReference PluginFile , PluginDescriptor Plugin , FileReference HostProjectFile , string TargetName , TargetRules . TargetType TargetType , UnrealTargetPlatform Platform , UnrealTargetConfiguration Configuration , List < string > ReceiptFileNames , string InAdditionalArgs )
2015-05-01 10:58:14 -04:00
{
// 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 )
{
2015-05-22 18:26:58 -04:00
bool bBuildDeveloperTools = ( TargetType = = TargetRules . TargetType . Editor | | TargetType = = TargetRules . TargetType . Program ) ;
bool bBuildEditor = ( TargetType = = TargetRules . TargetType . Editor ) ;
if ( Module . IsCompiledInConfiguration ( Platform , TargetType , bBuildDeveloperTools , bBuildEditor ) )
2015-05-01 10:58:14 -04:00
{
ModuleNames . Add ( Module . Name ) ;
}
}
// Add these modules to the build agenda
if ( ModuleNames . Count > 0 )
{
2016-03-11 09:55:03 -05:00
string Arguments = "" ; // String.Format("-plugin {0}", CommandUtils.MakePathSafeToUseWithCommandLine(PluginFile.FullName));
2015-05-01 10:58:14 -04:00
foreach ( string ModuleName in ModuleNames )
{
Arguments + = String . Format ( " -module {0}" , ModuleName ) ;
}
2016-03-17 11:10:14 -04:00
string Architecture = UEBuildPlatform . GetBuildPlatform ( Platform ) . CreateContext ( HostProjectFile ) . GetActiveArchitecture ( ) ;
string ReceiptFileName = TargetReceipt . GetDefaultPath ( Path . GetDirectoryName ( PluginFile . FullName ) , TargetName , Platform , Configuration , Architecture ) ;
2015-05-01 10:58:14 -04:00
Arguments + = String . Format ( " -receipt {0}" , CommandUtils . MakePathSafeToUseWithCommandLine ( ReceiptFileName ) ) ;
ReceiptFileNames . Add ( ReceiptFileName ) ;
2015-05-05 18:52:17 -04:00
if ( ! String . IsNullOrEmpty ( InAdditionalArgs ) )
{
Arguments + = InAdditionalArgs ;
}
2015-05-01 10:58:14 -04:00
2016-03-17 11:10:14 -04:00
CommandUtils . RunUBT ( CmdEnv , UE4Build . GetUBTExecutable ( ) , String . Format ( "{0} {1} {2}{3} {4}" , TargetName , Platform , Configuration , ( HostProjectFile = = null ) ? "" : String . Format ( " -project=\"{0}\"" , HostProjectFile . FullName ) , Arguments ) ) ;
2015-05-01 10:58:14 -04:00
}
}
2016-03-11 09:55:03 -05:00
static List < BuildProduct > GetBuildProductsFromReceipts ( DirectoryReference EngineDir , DirectoryReference ProjectDir , List < string > ReceiptFileNames )
2015-05-01 10:58:14 -04:00
{
List < BuildProduct > BuildProducts = new List < BuildProduct > ( ) ;
foreach ( string ReceiptFileName in ReceiptFileNames )
{
2015-08-10 16:07:05 -04:00
TargetReceipt Receipt ;
if ( ! TargetReceipt . TryRead ( ReceiptFileName , out Receipt ) )
{
throw new AutomationException ( "Missing or invalid target receipt ({0})" , ReceiptFileName ) ;
}
2016-03-11 09:55:03 -05:00
Receipt . ExpandPathVariables ( EngineDir , ProjectDir ) ;
2015-05-01 10:58:14 -04:00
BuildProducts . AddRange ( Receipt . BuildProducts ) ;
}
return BuildProducts ;
}
2016-03-11 09:55:03 -05:00
static void PackagePlugin ( FileReference PluginFile , List < BuildProduct > BuildProducts , string PackageDirectory )
2015-05-01 10:58:14 -04:00
{
// Clear the output directory
CommandUtils . DeleteDirectoryContents ( PackageDirectory ) ;
// Copy all the files to the output directory
2016-03-11 09:55:03 -05:00
List < string > MatchingFileNames = FilterPluginFiles ( PluginFile . FullName , BuildProducts ) ;
2015-05-01 10:58:14 -04:00
foreach ( string MatchingFileName in MatchingFileNames )
{
2016-03-11 09:55:03 -05:00
string SourceFileName = Path . Combine ( Path . GetDirectoryName ( PluginFile . FullName ) , MatchingFileName ) ;
2015-05-01 10:58:14 -04:00
string TargetFileName = Path . Combine ( PackageDirectory , MatchingFileName ) ;
CommandUtils . CopyFile ( SourceFileName , TargetFileName ) ;
2015-05-19 12:09:26 -04:00
CommandUtils . SetFileAttributes ( TargetFileName , ReadOnly : false ) ;
2015-05-01 10:58:14 -04:00
}
// Get the output plugin filename
2016-03-11 09:55:03 -05:00
FileReference TargetPluginFile = FileReference . Combine ( new DirectoryReference ( PackageDirectory ) , PluginFile . GetFileName ( ) ) ;
PluginDescriptor NewDescriptor = PluginDescriptor . FromFile ( TargetPluginFile ) ;
2015-05-27 12:56:05 -04:00
NewDescriptor . bEnabledByDefault = true ;
2015-05-01 10:58:14 -04:00
NewDescriptor . bInstalled = true ;
2016-03-11 09:55:03 -05:00
NewDescriptor . Save ( TargetPluginFile . FullName ) ;
2015-05-01 10:58:14 -04:00
}
static List < string > FilterPluginFiles ( string PluginFileName , List < BuildProduct > BuildProducts )
{
string PluginDirectory = Path . GetDirectoryName ( PluginFileName ) ;
// Set up the default filter
FileFilter Filter = new FileFilter ( ) ;
Filter . AddRuleForFile ( PluginFileName , PluginDirectory , FileFilterType . Include ) ;
Filter . AddRuleForFiles ( BuildProducts . Select ( x = > x . Path ) , PluginDirectory , FileFilterType . Include ) ;
2015-08-19 11:27:49 -04:00
Filter . Include ( "/Binaries/ThirdParty/..." ) ;
2015-05-01 10:58:14 -04:00
Filter . Include ( "/Resources/..." ) ;
Filter . Include ( "/Content/..." ) ;
Filter . Include ( "/Intermediate/Build/.../Inc/..." ) ;
Filter . Include ( "/Source/..." ) ;
// Add custom rules for each platform
string FilterFileName = Path . Combine ( Path . GetDirectoryName ( PluginFileName ) , "Config" , "FilterPlugin.ini" ) ;
if ( File . Exists ( FilterFileName ) )
{
Filter . ReadRulesFromFile ( FilterFileName , "FilterPlugin" ) ;
}
// Apply the standard exclusion rules
Filter . ExcludeConfidentialFolders ( ) ;
Filter . ExcludeConfidentialPlatforms ( ) ;
// Apply the filter to the plugin directory
2015-08-05 10:22:11 -04:00
return Filter . ApplyToDirectory ( PluginDirectory , true ) ;
2015-05-01 10:58:14 -04:00
}
}