2014-12-07 19:09:38 -05:00
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
using System ;
using System.Collections.Generic ;
using System.Text ;
using System.Diagnostics ;
using System.IO ;
using System.Linq ;
using System.Xml ;
2014-12-04 05:35:51 -05:00
using System.Globalization ;
2015-06-09 11:50:55 -04:00
using Tools.DotNETCommon.CaselessDictionary ;
2014-03-14 14:13:41 -04:00
namespace UnrealBuildTool
2015-09-24 12:37:21 -04:00
{
2014-03-14 14:13:41 -04:00
/// <summary>
2014-06-05 12:11:58 -04:00
/// All binary types generated by UBT
2014-03-14 14:13:41 -04:00
/// </summary>
public enum UEBuildBinaryType
{
Executable ,
DynamicLinkLibrary ,
2014-06-05 12:11:58 -04:00
StaticLibrary ,
Object ,
PrecompiledHeader
}
2014-03-14 14:13:41 -04:00
/// <summary>
/// UEBuildBinary configuration
/// Configuration class for a UEBuildBinary.
/// Exposes the configuration values of the BuildBinary class without exposing the functions.
/// </summary>
public class UEBuildBinaryConfiguration
{
/// <summary>
/// The type of binary to build
/// </summary>
public UEBuildBinaryType Type ;
/// <summary>
/// The output file path. This must be set before a binary can be built using it.
/// </summary>
2015-09-03 08:47:24 -04:00
public List < FileReference > OutputFilePaths = new List < FileReference > ( ) ;
2014-09-02 14:26:49 -04:00
/// <summary>
2015-03-27 07:15:32 -04:00
/// Returns the OutputFilePath if there is only one entry in OutputFilePaths
2014-09-02 14:26:49 -04:00
/// </summary>
2015-09-03 08:47:24 -04:00
public FileReference OutputFilePath
2014-09-02 14:26:49 -04:00
{
get
{
2015-05-18 08:16:56 -04:00
if ( OutputFilePaths . Count ! = 1 )
2014-09-02 14:26:49 -04:00
{
2015-05-18 08:16:56 -04:00
throw new BuildException ( "Attempted to use UEBuildBinaryConfiguration.OutputFilePath property, but there are multiple (or no) OutputFilePaths. You need to handle multiple in the code that called this (size = {0})" , OutputFilePaths . Count ) ;
2014-09-02 14:26:49 -04:00
}
return OutputFilePaths [ 0 ] ;
}
}
2014-03-14 14:13:41 -04:00
/// <summary>
/// Original output filepath. This is the original binary name before hot-reload suffix has been appended to it.
/// </summary>
2015-09-03 08:47:24 -04:00
public List < FileReference > OriginalOutputFilePaths ;
2014-09-02 14:26:49 -04:00
/// <summary>
2015-03-27 07:15:32 -04:00
/// Returns the OriginalOutputFilePath if there is only one entry in OriginalOutputFilePaths
2014-09-02 14:26:49 -04:00
/// </summary>
2015-09-03 08:47:24 -04:00
public FileReference OriginalOutputFilePath
2014-09-02 14:26:49 -04:00
{
get
{
2015-05-18 08:16:56 -04:00
if ( OriginalOutputFilePaths . Count ! = 1 )
2014-09-02 14:26:49 -04:00
{
2015-05-18 08:16:56 -04:00
throw new BuildException ( "Attempted to use UEBuildBinaryConfiguration.OriginalOutputFilePath property, but there are multiple (or no) OriginalOutputFilePaths. You need to handle multiple in the code that called this (size = {0})" , OriginalOutputFilePaths . Count ) ;
2014-09-02 14:26:49 -04:00
}
2015-03-27 07:15:32 -04:00
return OriginalOutputFilePaths [ 0 ] ;
2014-09-02 14:26:49 -04:00
}
}
2014-03-14 14:13:41 -04:00
/// <summary>
/// The intermediate directory for this binary. Modules should create separate intermediate directories below this. Must be set before a binary can be built using it.
/// </summary>
2015-09-03 08:47:24 -04:00
public DirectoryReference IntermediateDirectory ;
2014-03-14 14:13:41 -04:00
/// <summary>
/// If true, build exports lib
/// </summary>
public bool bAllowExports = false ;
2015-09-24 12:37:21 -04:00
2014-03-14 14:13:41 -04:00
/// <summary>
/// If true, create a separate import library
/// </summary>
public bool bCreateImportLibrarySeparately = false ;
/// <summary>
/// If true, include dependent libraries in the static library being built
/// </summary>
public bool bIncludeDependentLibrariesInLibrary = false ;
/// <summary>
/// If false, this binary will not be compiled and it is only used to set up link environments
/// </summary>
public bool bAllowCompilation = true ;
2014-04-23 18:25:10 -04:00
/// <summary>
/// True if this binary has any Build.cs files, if not this is probably a binary-only plugins
/// </summary>
public bool bHasModuleRules = true ;
2015-09-24 12:37:21 -04:00
/// <summary>
/// For most binaries, this is false. If this is a cross-platform binary build for a specific platform (for example XB1 DLL for a windows editor) this will be true.
/// </summary>
public bool bIsCrossTarget = false ;
2014-03-14 14:13:41 -04:00
2015-09-24 12:37:21 -04:00
/// <summary>
2015-04-02 11:09:01 -04:00
/// If true, creates an additional console application. Hack for Windows, where it's not possible to conditionally inherit a parent's console Window depending on how
/// the application is invoked; you have to link the same executable with a different subsystem setting.
/// </summary>
public bool bBuildAdditionalConsoleApp = false ;
2014-03-14 14:13:41 -04:00
/// <summary>
/// The projectfile path
/// </summary>
2015-09-03 08:47:24 -04:00
public FileReference ProjectFilePath ;
2015-09-24 12:37:21 -04:00
2014-03-14 14:13:41 -04:00
/// <summary>
/// List of modules to link together into this executable
/// </summary>
public List < string > ModuleNames = new List < string > ( ) ;
/// <summary>
/// The configuration class for a binary build.
/// </summary>
/// <param name="InType"></param>
/// <param name="InOutputFilePath"></param>
/// <param name="bInAllowExports"></param>
/// <param name="bInCreateImportLibrarySeparately"></param>
2015-09-24 12:37:21 -04:00
/// <param name="bInIsCrossTarget">For most binaries, this is false. If this is a cross-platform binary build for a specific platform (for example XB1 DLL for a windows editor) this will be true.</param>
/// <param name="InProjectFilePath"></param>
2014-03-14 14:13:41 -04:00
/// <param name="InModuleNames"></param>
public UEBuildBinaryConfiguration (
UEBuildBinaryType InType ,
2015-09-03 08:47:24 -04:00
IEnumerable < FileReference > InOutputFilePaths = null ,
DirectoryReference InIntermediateDirectory = null ,
2014-03-14 14:13:41 -04:00
bool bInAllowExports = false ,
bool bInCreateImportLibrarySeparately = false ,
bool bInIncludeDependentLibrariesInLibrary = false ,
bool bInAllowCompilation = true ,
2014-04-23 18:25:10 -04:00
bool bInHasModuleRules = true ,
2015-09-24 12:37:21 -04:00
bool bInIsCrossTarget = false ,
2015-09-03 08:47:24 -04:00
FileReference InProjectFilePath = null ,
2015-05-18 08:16:56 -04:00
IEnumerable < string > InModuleNames = null
2014-03-14 14:13:41 -04:00
)
{
Type = InType ;
2015-05-18 08:16:56 -04:00
if ( InOutputFilePaths ! = null )
{
OutputFilePaths . AddRange ( InOutputFilePaths ) ;
}
2014-03-14 14:13:41 -04:00
IntermediateDirectory = InIntermediateDirectory ;
bAllowExports = bInAllowExports ;
bCreateImportLibrarySeparately = bInCreateImportLibrarySeparately ;
bIncludeDependentLibrariesInLibrary = bInIncludeDependentLibrariesInLibrary ;
bAllowCompilation = bInAllowCompilation ;
2014-04-23 18:25:10 -04:00
bHasModuleRules = bInHasModuleRules ;
2015-09-24 12:37:21 -04:00
bIsCrossTarget = bInIsCrossTarget ;
2014-03-14 14:13:41 -04:00
ProjectFilePath = InProjectFilePath ;
2015-09-24 12:37:21 -04:00
if ( InModuleNames ! = null )
2015-04-11 13:09:16 -04:00
{
ModuleNames . AddRange ( InModuleNames ) ;
}
2014-03-14 14:13:41 -04:00
}
}
/// <summary>
/// A binary built by UBT.
/// </summary>
public abstract class UEBuildBinary
{
/// <summary>
/// The target which owns this binary.
/// </summary>
public UEBuildTarget Target ;
/// <summary>
/// The build binary configuration data
/// </summary>
public UEBuildBinaryConfiguration Config = null ;
/// <summary>
/// Create an instance of the class with the given configuration data
/// </summary>
/// <param name="InConfig">The build binary configuration to initialize the class with</param>
2015-09-24 12:37:21 -04:00
public UEBuildBinary ( UEBuildTarget InTarget , UEBuildBinaryConfiguration InConfig )
2014-03-14 14:13:41 -04:00
{
Debug . Assert ( InConfig . OutputFilePath ! = null & & InConfig . IntermediateDirectory ! = null ) ;
Target = InTarget ;
Config = InConfig ;
}
/// <summary>
/// Called to resolve module names and uniquely bind modules to a binary.
/// </summary>
/// <param name="BuildTarget">The build target the modules are being bound for</param>
/// <param name="Target">The target info</param>
2015-09-24 12:37:21 -04:00
public virtual void BindModules ( ) { }
2014-03-14 14:13:41 -04:00
/// <summary>
/// Builds the binary.
/// </summary>
2014-06-17 02:04:37 -04:00
/// <param name="ToolChain">The toolchain which to use for building</param>
2014-03-14 14:13:41 -04:00
/// <param name="CompileEnvironment">The environment to compile the binary in</param>
/// <param name="LinkEnvironment">The environment to link the binary in</param>
/// <returns></returns>
2015-09-27 13:05:49 -04:00
public abstract IEnumerable < FileItem > Build ( UEToolChain ToolChain , CPPEnvironment CompileEnvironment , LinkEnvironment LinkEnvironment ) ;
2014-03-14 14:13:41 -04:00
/// <summary>
/// Called to allow the binary to modify the link environment of a different binary containing
/// a module that depends on a module in this binary. */
/// </summary>
/// <param name="DependentLinkEnvironment">The link environment of the dependency</param>
2015-09-24 12:37:21 -04:00
public virtual void SetupDependentLinkEnvironment ( LinkEnvironment DependentLinkEnvironment ) { }
2014-03-14 14:13:41 -04:00
/// <summary>
/// Called to allow the binary to to determine if it matches the Only module "short module name".
/// </summary>
/// <param name="OnlyModules"></param>
/// <returns>The OnlyModule if found, null if not</returns>
2015-09-24 12:37:21 -04:00
public virtual OnlyModule FindOnlyModule ( List < OnlyModule > OnlyModules )
{
return null ;
}
2014-03-14 14:13:41 -04:00
2014-08-14 03:37:01 -04:00
/// <summary>
/// Called to allow the binary to find game modules.
/// </summary>
/// <param name="OnlyModules"></param>
/// <returns>The OnlyModule if found, null if not</returns>
public virtual List < UEBuildModule > FindGameModules ( )
{
return null ;
}
2014-03-14 14:13:41 -04:00
/// <summary>
/// Generates a list of all modules referenced by this binary
/// </summary>
/// <param name="bIncludeDynamicallyLoaded">True if dynamically loaded modules (and all of their dependent modules) should be included.</param>
/// <param name="bForceCircular">True if circular dependencies should be process</param>
/// <returns>List of all referenced modules</returns>
2015-09-24 12:37:21 -04:00
public virtual List < UEBuildModule > GetAllDependencyModules ( bool bIncludeDynamicallyLoaded , bool bForceCircular )
2014-03-14 14:13:41 -04:00
{
return new List < UEBuildModule > ( ) ;
}
/// <summary>
/// Process all modules that aren't yet bound, creating binaries for modules that don't yet have one (if needed),
/// and updating modules for circular dependencies.
/// </summary>
2015-04-11 13:09:16 -04:00
public virtual void ProcessUnboundModules ( )
2014-03-14 14:13:41 -04:00
{
}
/// <summary>
/// Sets whether to create a separate import library to resolve circular dependencies for this binary
/// </summary>
/// <param name="bInCreateImportLibrarySeparately">True to create a separate import library</param>
2015-09-24 12:37:21 -04:00
public virtual void SetCreateImportLibrarySeparately ( bool bInCreateImportLibrarySeparately )
2014-03-14 14:13:41 -04:00
{
}
/// <summary>
/// Sets whether to include dependent libraries when building a static library
/// </summary>
/// <param name="bInIncludeDependentLibrariesInLibrary">True to include dependent libraries</param>
public virtual void SetIncludeDependentLibrariesInLibrary ( bool bInIncludeDependentLibrariesInLibrary )
{
}
/// <summary>
/// Adds a module to the binary.
/// </summary>
/// <param name="ModuleName">The module to add</param>
2015-09-24 12:37:21 -04:00
public virtual void AddModule ( UEBuildModule Module )
2014-03-14 14:13:41 -04:00
{
}
2015-04-03 10:25:57 -04:00
/// <summary>
2015-09-05 18:10:25 -04:00
/// Gets all build products produced by this binary
2015-04-03 10:25:57 -04:00
/// </summary>
2015-09-05 18:10:25 -04:00
/// <param name="ToolChain">The platform toolchain</param>
/// <param name="BuildProducts">Mapping of produced build product to type</param>
2015-09-27 13:05:49 -04:00
public virtual void GetBuildProducts ( UEToolChain ToolChain , Dictionary < FileReference , BuildProductType > BuildProducts )
2015-04-03 10:25:57 -04:00
{
// Get the type of build products we're creating
BuildProductType Type = BuildProductType . RequiredResource ;
2015-09-24 12:37:21 -04:00
switch ( Config . Type )
2015-04-03 10:25:57 -04:00
{
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 ) ;
2015-09-03 08:47:24 -04:00
foreach ( FileReference OutputFilePath in Config . OutputFilePaths )
2015-04-03 10:25:57 -04:00
{
2015-09-05 18:10:25 -04:00
AddBuildProductAndDebugFile ( OutputFilePath , Type , DebugExtension , BuildProducts , ToolChain ) ;
2015-04-03 10:25:57 -04:00
}
// Add the console app, if there is one
if ( Config . Type = = UEBuildBinaryType . Executable & & Config . bBuildAdditionalConsoleApp )
{
2015-09-03 08:47:24 -04:00
foreach ( FileReference OutputFilePath in Config . OutputFilePaths )
2015-04-03 10:25:57 -04:00
{
2015-09-05 18:10:25 -04:00
AddBuildProductAndDebugFile ( GetAdditionalConsoleAppPath ( OutputFilePath ) , Type , DebugExtension , BuildProducts , ToolChain ) ;
2015-04-03 10:25:57 -04:00
}
}
// Add any extra files from the toolchain
2015-09-05 18:10:25 -04:00
ToolChain . ModifyBuildProducts ( this , BuildProducts ) ;
2015-04-03 10:25:57 -04:00
}
/// <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>
2015-09-27 13:05:49 -04:00
static void AddBuildProductAndDebugFile ( FileReference OutputFile , BuildProductType OutputType , string DebugExtension , Dictionary < FileReference , BuildProductType > BuildProducts , UEToolChain ToolChain )
2015-04-03 10:25:57 -04:00
{
2015-09-05 18:10:25 -04:00
BuildProducts . Add ( OutputFile , OutputType ) ;
2015-04-03 10:25:57 -04:00
2015-09-24 12:37:21 -04:00
if ( ! String . IsNullOrEmpty ( DebugExtension ) & & ToolChain . ShouldAddDebugFileToReceipt ( OutputFile , OutputType ) )
2015-04-03 10:25:57 -04:00
{
2015-09-05 18:10:25 -04:00
BuildProducts . Add ( OutputFile . ChangeExtension ( DebugExtension ) , BuildProductType . SymbolFile ) ;
2015-04-03 10:25:57 -04:00
}
}
2014-03-14 14:13:41 -04:00
/// <summary>
/// Helper function to get the console app BinaryName-Cmd.exe filename based on the binary filename.
/// </summary>
/// <param name="BinaryPath">Full path to the binary exe.</param>
/// <returns></returns>
2015-09-03 08:47:24 -04:00
public static FileReference GetAdditionalConsoleAppPath ( FileReference BinaryPath )
2014-03-14 14:13:41 -04:00
{
2015-09-03 08:47:24 -04:00
return FileReference . Combine ( BinaryPath . Directory , BinaryPath . GetFileNameWithoutExtension ( ) + "-Cmd" + BinaryPath . GetExtension ( ) ) ;
2014-03-14 14:13:41 -04:00
}
2015-03-27 07:15:32 -04:00
2015-09-24 13:47:13 -04:00
/// <summary>
/// Checks whether the binary output paths are appropriate for the distribution
/// level of its direct module dependencies
/// </summary>
2015-09-04 08:02:30 -04:00
public void CheckOutputDistributionLevelAgainstDependencies ( Dictionary < UEBuildModule , UEBuildModuleDistribution > ModuleDistributionCache )
2015-03-27 07:15:32 -04:00
{
// Find maximum distribution level of its direct dependencies
var DistributionLevel = UEBuildModuleDistribution . Public ;
var DependantModules = GetAllDependencyModules ( false , false ) ;
List < string > [ ] DependantModuleNames = new List < string > [ Enum . GetNames ( typeof ( UEBuildModuleDistribution ) ) . Length ] ;
foreach ( var Module in DependantModules )
{
2015-09-04 08:02:30 -04:00
UEBuildModuleDistribution ModuleDistributionLevel ;
2015-09-24 12:37:21 -04:00
if ( ! ModuleDistributionCache . TryGetValue ( Module , out ModuleDistributionLevel ) )
2015-09-04 08:02:30 -04:00
{
ModuleDistributionLevel = Module . DetermineDistributionLevel ( ) ;
ModuleDistributionCache . Add ( Module , ModuleDistributionLevel ) ;
}
if ( ModuleDistributionLevel ! = UEBuildModuleDistribution . Public )
2015-03-27 07:15:32 -04:00
{
// Make a list of non-public dependant modules so that exception
// message can be more helpful
2015-09-04 08:02:30 -04:00
int DistributionIndex = ( int ) ModuleDistributionLevel ;
2015-03-27 07:15:32 -04:00
if ( DependantModuleNames [ DistributionIndex ] = = null )
{
DependantModuleNames [ DistributionIndex ] = new List < string > ( ) ;
}
DependantModuleNames [ DistributionIndex ] . Add ( Module . Name ) ;
2015-09-04 08:02:30 -04:00
DistributionLevel = Utils . Max ( DistributionLevel , ModuleDistributionLevel ) ;
2015-03-27 07:15:32 -04:00
}
}
// Check Output Paths if dependencies shouldn't be distributed to everyone
if ( DistributionLevel ! = UEBuildModuleDistribution . Public )
{
foreach ( var OutputFilePath in Config . OutputFilePaths )
{
2015-09-03 08:47:24 -04:00
var OutputDistributionLevel = UEBuildModule . GetModuleDistributionLevelBasedOnLocation ( OutputFilePath . FullName ) ;
2015-03-27 07:15:32 -04:00
// Throw exception if output path is not appropriate
if ( OutputDistributionLevel < DistributionLevel )
{
var JoinedModuleNames = String . Join ( "," , DependantModuleNames [ ( int ) DistributionLevel ] ) ;
throw new BuildException ( "Output file \"{0}\" has distribution level of \"{1}\" but has direct dependencies on modules with distribution level of \"{2}\" ({3}).\nEither change to dynamic dependencies, set BinariesSubFolder/ExeBinariesSubFolder to \"{2}\" or set bOutputPubliclyDistributable to true in the target.cs file." ,
OutputFilePath , OutputDistributionLevel . ToString ( ) , DistributionLevel . ToString ( ) , JoinedModuleNames ) ;
}
}
}
}
2014-03-14 14:13:41 -04:00
} ;
/// <summary>
/// A binary built by UBT from a set of C++ modules.
/// </summary>
public class UEBuildBinaryCPP : UEBuildBinary
{
2015-09-06 10:35:57 -04:00
public readonly List < UEBuildModule > Modules = new List < UEBuildModule > ( ) ;
2014-03-14 14:13:41 -04:00
private bool bCreateImportLibrarySeparately ;
private bool bIncludeDependentLibrariesInLibrary ;
2015-09-08 08:00:41 -04:00
private List < string > DependentLinkLibraries ;
2014-03-14 14:13:41 -04:00
/// <summary>
/// Create an instance initialized to the given configuration
/// </summary>
/// <param name="InConfig">The build binary configuration to initialize the instance to</param>
2015-09-24 12:37:21 -04:00
public UEBuildBinaryCPP ( UEBuildTarget InTarget , UEBuildBinaryConfiguration InConfig )
: base ( InTarget , InConfig )
2014-03-14 14:13:41 -04:00
{
bCreateImportLibrarySeparately = InConfig . bCreateImportLibrarySeparately ;
bIncludeDependentLibrariesInLibrary = InConfig . bIncludeDependentLibrariesInLibrary ;
}
/// <summary>
/// Adds a module to the binary.
/// </summary>
/// <param name="ModuleName">The module to add</param>
2015-09-06 10:35:57 -04:00
public override void AddModule ( UEBuildModule Module )
2014-03-14 14:13:41 -04:00
{
2015-09-24 12:37:21 -04:00
if ( ! Modules . Contains ( Module ) )
2014-03-14 14:13:41 -04:00
{
2015-09-06 10:35:57 -04:00
Modules . Add ( Module ) ;
2014-03-14 14:13:41 -04:00
}
}
// UEBuildBinary interface.
/// <summary>
/// Called to resolve module names and uniquely bind modules to a binary.
/// </summary>
/// <param name="BuildTarget">The build target the modules are being bound for</param>
/// <param name="Target">The target info</param>
public override void BindModules ( )
{
2015-09-24 12:37:21 -04:00
foreach ( var Module in Modules )
2014-03-14 14:13:41 -04:00
{
2014-04-23 18:25:10 -04:00
if ( Config . bHasModuleRules )
2014-03-14 14:13:41 -04:00
{
2015-09-24 12:37:21 -04:00
if ( Module . Binary = = null )
2015-03-20 08:25:23 -04:00
{
Module . Binary = this ;
Module . bIncludedInTarget = true ;
}
2015-09-24 12:37:21 -04:00
else if ( Module . Binary . Config . Type ! = UEBuildBinaryType . StaticLibrary )
2014-04-23 18:25:10 -04:00
{
2015-09-06 10:35:57 -04:00
throw new BuildException ( "Module \"{0}\" linked into both {1} and {2}, which creates ambiguous linkage for dependents." , Module . Name , Module . Binary . Config . OutputFilePath , Config . OutputFilePath ) ;
2014-04-23 18:25:10 -04:00
}
2014-03-14 14:13:41 -04:00
}
}
}
/// <summary>
/// Generates a list of all modules referenced by this binary
/// </summary>
/// <param name="bIncludeDynamicallyLoaded">True if dynamically loaded modules (and all of their dependent modules) should be included.</param>
/// <param name="bForceCircular">True if circular dependencies should be process</param>
/// <returns>List of all referenced modules</returns>
public override List < UEBuildModule > GetAllDependencyModules ( bool bIncludeDynamicallyLoaded , bool bForceCircular )
{
2015-06-09 11:50:55 -04:00
var ReferencedModules = new CaselessDictionary < UEBuildModule . ModuleIndexPair > ( ) ;
2015-09-24 12:37:21 -04:00
foreach ( var Module in Modules )
2014-03-14 14:13:41 -04:00
{
2015-09-24 12:37:21 -04:00
if ( ! ReferencedModules . ContainsKey ( Module . Name ) )
2014-03-14 14:13:41 -04:00
{
2015-09-24 12:37:21 -04:00
ReferencedModules [ Module . Name ] = null ;
2014-03-14 14:13:41 -04:00
2015-06-09 11:50:55 -04:00
Module . GetAllDependencyModules ( ReferencedModules , bIncludeDynamicallyLoaded , bForceCircular , bOnlyDirectDependencies : false ) ;
2014-03-14 14:13:41 -04:00
2015-09-24 12:37:21 -04:00
ReferencedModules [ Module . Name ] = new UEBuildModule . ModuleIndexPair { Module = Module , Index = ReferencedModules . Count } ;
2014-03-14 14:13:41 -04:00
}
}
2015-06-09 11:50:55 -04:00
return ReferencedModules . Values . OrderBy ( M = > M . Index ) . Select ( M = > M . Module ) . ToList ( ) ;
2014-03-14 14:13:41 -04:00
}
/// <summary>
/// Process all modules that aren't yet bound, creating binaries for modules that don't yet have one (if needed),
/// and updating modules for circular dependencies.
/// </summary>
/// <returns>List of newly-created binaries (may be empty)</returns>
2015-04-11 13:09:16 -04:00
public override void ProcessUnboundModules ( )
2014-03-14 14:13:41 -04:00
{
2014-04-23 18:25:10 -04:00
if ( Config . bHasModuleRules )
2014-03-14 14:13:41 -04:00
{
2015-04-11 13:09:16 -04:00
// Modules may be added to this binary during this process, so don't foreach over ModuleNames
2015-09-24 12:37:21 -04:00
foreach ( UEBuildModule Module in Modules )
2014-04-23 18:25:10 -04:00
{
2015-08-28 15:47:20 -04:00
Module . RecursivelyCreateModules ( ) ;
2015-04-11 13:09:16 -04:00
Module . RecursivelyProcessUnboundModules ( ) ;
2014-04-23 18:25:10 -04:00
}
}
2014-03-14 14:13:41 -04:00
}
/// <summary>
/// Sets whether to create a separate import library to resolve circular dependencies for this binary
/// </summary>
/// <param name="bInCreateImportLibrarySeparately">True to create a separate import library</param>
public override void SetCreateImportLibrarySeparately ( bool bInCreateImportLibrarySeparately )
{
bCreateImportLibrarySeparately = bInCreateImportLibrarySeparately ;
}
/// <summary>
/// Sets whether to include dependent libraries when building a static library
/// </summary>
/// <param name="bInIncludeDependentLibrariesInLibrary"></param>
public override void SetIncludeDependentLibrariesInLibrary ( bool bInIncludeDependentLibrariesInLibrary )
{
bIncludeDependentLibrariesInLibrary = bInIncludeDependentLibrariesInLibrary ;
}
2014-12-04 05:35:51 -05:00
bool IsBuildingDll ( UEBuildBinaryType Type )
{
if ( BuildConfiguration . bRunUnrealCodeAnalyzer )
{
return false ;
}
return Type = = UEBuildBinaryType . DynamicLinkLibrary ;
}
bool IsBuildingLibrary ( UEBuildBinaryType Type )
{
if ( BuildConfiguration . bRunUnrealCodeAnalyzer )
{
return false ;
}
return Type = = UEBuildBinaryType . StaticLibrary ;
}
2014-03-14 14:13:41 -04:00
/// <summary>
/// Builds the binary.
/// </summary>
/// <param name="CompileEnvironment">The environment to compile the binary in</param>
/// <param name="LinkEnvironment">The environment to link the binary in</param>
/// <returns></returns>
2015-09-27 13:05:49 -04:00
public override IEnumerable < FileItem > Build ( UEToolChain ToolChain , CPPEnvironment CompileEnvironment , LinkEnvironment LinkEnvironment )
2014-03-14 14:13:41 -04:00
{
2014-12-04 05:35:51 -05:00
// UnrealCodeAnalyzer produces output files only for a specific module.
2015-09-06 10:35:57 -04:00
if ( BuildConfiguration . bRunUnrealCodeAnalyzer & & ! ( Modules . Any ( x = > x . Name = = BuildConfiguration . UCAModuleToAnalyze ) ) )
2014-03-14 14:13:41 -04:00
{
2014-12-04 05:35:51 -05:00
return new List < FileItem > ( ) ;
2014-03-14 14:13:41 -04:00
}
2014-12-04 05:35:51 -05:00
// Setup linking environment.
2015-09-24 08:08:38 -04:00
var BinaryLinkEnvironment = SetupBinaryLinkEnvironment ( ToolChain , LinkEnvironment , CompileEnvironment ) ;
2014-09-08 12:56:22 -04:00
2014-12-04 05:35:51 -05:00
// Return linked files.
2015-09-24 08:08:38 -04:00
return SetupOutputFiles ( ToolChain , ref BinaryLinkEnvironment ) ;
2014-03-14 14:13:41 -04:00
}
/// <summary>
/// Called to allow the binary to modify the link environment of a different binary containing
/// a module that depends on a module in this binary.
/// </summary>
/// <param name="DependentLinkEnvironment">The link environment of the dependency</param>
2015-03-21 11:34:08 -04:00
public override void SetupDependentLinkEnvironment ( LinkEnvironment DependentLinkEnvironment )
2014-03-14 14:13:41 -04:00
{
2015-09-08 08:00:41 -04:00
// Cache the list of libraries in the dependent link environment between calls. We typically run this code path many times for each module.
2015-09-24 12:37:21 -04:00
if ( DependentLinkLibraries = = null )
2014-03-14 14:13:41 -04:00
{
2015-09-08 08:00:41 -04:00
DependentLinkLibraries = new List < string > ( ) ;
foreach ( FileReference OutputFilePath in Config . OutputFilePaths )
2014-09-02 14:26:49 -04:00
{
2015-09-08 08:00:41 -04:00
FileReference LibraryFileName ;
if ( Config . Type = = UEBuildBinaryType . StaticLibrary | | DependentLinkEnvironment . Config . Target . Platform = = CPPTargetPlatform . Mac | | DependentLinkEnvironment . Config . Target . Platform = = CPPTargetPlatform . Linux )
{
LibraryFileName = OutputFilePath ;
}
else
{
LibraryFileName = FileReference . Combine ( Config . IntermediateDirectory , OutputFilePath . GetFileNameWithoutExtension ( ) + ".lib" ) ;
}
DependentLinkLibraries . Add ( LibraryFileName . FullName ) ;
2014-09-02 14:26:49 -04:00
}
2014-03-14 14:13:41 -04:00
}
2015-09-08 08:00:41 -04:00
DependentLinkEnvironment . Config . AdditionalLibraries . AddRange ( DependentLinkLibraries ) ;
2015-05-30 17:50:01 -04:00
// If we're linking against static library containing the launch module on windows, we need to add the compiled resource separately. We can't link it through the static library.
2015-09-24 12:37:21 -04:00
if ( Config . Type = = UEBuildBinaryType . StaticLibrary & & Modules . Any ( x = > x . Name = = "Launch" ) & & ( Target . Platform = = UnrealTargetPlatform . Win32 | | Target . Platform = = UnrealTargetPlatform . Win64 ) )
2015-05-30 17:50:01 -04:00
{
2015-09-03 08:47:24 -04:00
FileReference ResourceFileRef = FileReference . Combine ( Config . IntermediateDirectory , "Launch" , "PCLaunch.rc.res" ) ;
DependentLinkEnvironment . InputFiles . Add ( FileItem . GetItemByFileReference ( ResourceFileRef ) ) ;
2015-05-30 17:50:01 -04:00
}
2014-03-14 14:13:41 -04:00
}
/// <summary>
/// Called to allow the binary to to determine if it matches the Only module "short module name".
/// </summary>
/// <param name="OnlyModules"></param>
/// <returns>The OnlyModule if found, null if not</returns>
public override OnlyModule FindOnlyModule ( List < OnlyModule > OnlyModules )
{
2015-09-06 10:35:57 -04:00
foreach ( var Module in Modules )
2014-03-14 14:13:41 -04:00
{
foreach ( var OnlyModule in OnlyModules )
{
2015-09-06 10:35:57 -04:00
if ( OnlyModule . OnlyModuleName . ToLower ( ) = = Module . Name . ToLower ( ) )
2014-03-14 14:13:41 -04:00
{
return OnlyModule ;
}
}
}
return null ;
}
2014-08-14 03:37:01 -04:00
public override List < UEBuildModule > FindGameModules ( )
{
var GameModules = new List < UEBuildModule > ( ) ;
2015-09-06 10:35:57 -04:00
foreach ( var Module in Modules )
2014-08-14 03:37:01 -04:00
{
2015-09-03 08:47:24 -04:00
if ( ! Module . ModuleDirectory . IsUnderDirectory ( UnrealBuildTool . EngineDirectory ) )
2014-08-14 03:37:01 -04:00
{
GameModules . Add ( Module ) ;
}
}
return GameModules ;
}
2015-04-03 10:25:57 -04:00
/// <summary>
2015-09-05 18:10:25 -04:00
/// Gets all build products produced by this binary
2015-04-03 10:25:57 -04:00
/// </summary>
/// <param name="ToolChain">The platform toolchain</param>
2015-09-05 18:10:25 -04:00
/// <param name="BuildProducts">Mapping of produced build product to type</param>
2015-09-27 13:05:49 -04:00
public override void GetBuildProducts ( UEToolChain ToolChain , Dictionary < FileReference , BuildProductType > BuildProducts )
2015-04-03 10:25:57 -04:00
{
2015-09-05 18:10:25 -04:00
base . GetBuildProducts ( ToolChain , BuildProducts ) ;
2015-04-09 10:13:10 -04:00
2015-05-30 17:50:01 -04:00
// Add the compiled resource file if we're building a static library containing the launch module on Windows
2015-09-24 12:37:21 -04:00
if ( Config . Type = = UEBuildBinaryType . StaticLibrary & & Modules . Any ( x = > x . Name = = "Launch" ) & & ( Target . Platform = = UnrealTargetPlatform . Win32 | | Target . Platform = = UnrealTargetPlatform . Win64 ) )
2015-05-30 17:50:01 -04:00
{
2015-09-03 08:47:24 -04:00
FileReference ResourceFilePath = FileReference . Combine ( Config . IntermediateDirectory , "Launch" , "PCLaunch.rc.res" ) ;
2015-09-05 18:10:25 -04:00
BuildProducts . Add ( ResourceFilePath , BuildProductType . StaticLibrary ) ;
2015-05-30 17:50:01 -04:00
}
2015-04-03 10:25:57 -04:00
}
2014-03-14 14:13:41 -04:00
// Object interface.
/// <summary>
/// ToString implementation
/// </summary>
/// <returns>Returns the OutputFilePath for this binary</returns>
public override string ToString ( )
{
2015-09-03 08:47:24 -04:00
return Config . OutputFilePath . FullName ;
2014-03-14 14:13:41 -04:00
}
2014-12-04 05:35:51 -05:00
2015-09-27 13:05:49 -04:00
private LinkEnvironment SetupBinaryLinkEnvironment ( UEToolChain ToolChain , LinkEnvironment LinkEnvironment , CPPEnvironment CompileEnvironment )
2014-12-04 05:35:51 -05:00
{
var BinaryLinkEnvironment = LinkEnvironment . DeepCopy ( ) ;
2015-09-08 15:50:24 -04:00
var LinkEnvironmentVisitedModules = new HashSet < UEBuildModule > ( ) ;
2014-12-04 05:35:51 -05:00
var BinaryDependencies = new List < UEBuildBinary > ( ) ;
CompileEnvironment . Config . bIsBuildingDLL = IsBuildingDll ( Config . Type ) ;
CompileEnvironment . Config . bIsBuildingLibrary = IsBuildingLibrary ( Config . Type ) ;
var BinaryCompileEnvironment = CompileEnvironment . DeepCopy ( ) ;
// @Hack: This to prevent UHT from listing CoreUObject.generated.cpp as its dependency.
// We flag the compile environment when we build UHT so that we don't need to check
// this for each file when generating their dependencies.
BinaryCompileEnvironment . bHackHeaderGenerator = ( Target . GetAppName ( ) = = "UnrealHeaderTool" ) ;
// @todo: This should be in some Windows code somewhere...
// Set the original file name macro; used in PCLaunch.rc to set the binary metadata fields.
var OriginalFilename = ( Config . OriginalOutputFilePaths ! = null ) ?
2015-09-03 08:47:24 -04:00
Config . OriginalOutputFilePaths [ 0 ] . GetFileName ( ) :
Config . OutputFilePaths [ 0 ] . GetFileName ( ) ;
2014-12-04 05:35:51 -05:00
BinaryCompileEnvironment . Config . Definitions . Add ( "ORIGINAL_FILE_NAME=\"" + OriginalFilename + "\"" ) ;
2015-09-06 10:35:57 -04:00
foreach ( var Module in Modules )
2014-12-04 05:35:51 -05:00
{
2015-09-24 12:37:21 -04:00
List < FileItem > LinkInputFiles ;
if ( Module . Binary = = null | | Module . Binary = = this )
2014-12-04 05:35:51 -05:00
{
2015-03-20 08:25:23 -04:00
// Compile each module.
2015-09-06 10:35:57 -04:00
Log . TraceVerbose ( "Compile module: " + Module . Name ) ;
2015-09-24 08:08:38 -04:00
LinkInputFiles = Module . Compile ( ToolChain , CompileEnvironment , BinaryCompileEnvironment ) ;
2015-03-20 08:25:23 -04:00
// NOTE: Because of 'Shared PCHs', in monolithic builds the same PCH file may appear as a link input
// multiple times for a single binary. We'll check for that here, and only add it once. This avoids
// a linker warning about redundant .obj files.
foreach ( var LinkInputFile in LinkInputFiles )
2014-12-04 05:35:51 -05:00
{
2015-03-20 08:25:23 -04:00
if ( ! BinaryLinkEnvironment . InputFiles . Contains ( LinkInputFile ) )
{
BinaryLinkEnvironment . InputFiles . Add ( LinkInputFile ) ;
}
2014-12-04 05:35:51 -05:00
}
}
2015-09-24 12:37:21 -04:00
else
2015-03-20 08:25:23 -04:00
{
BinaryDependencies . Add ( Module . Binary ) ;
}
2014-12-04 05:35:51 -05:00
if ( ! BuildConfiguration . bRunUnrealCodeAnalyzer )
{
// Allow the module to modify the link environment for the binary.
2015-05-22 08:57:34 -04:00
Module . SetupPrivateLinkEnvironment ( this , BinaryLinkEnvironment , BinaryDependencies , LinkEnvironmentVisitedModules ) ;
2014-12-04 05:35:51 -05:00
}
}
// Allow the binary dependencies to modify the link environment.
foreach ( var BinaryDependency in BinaryDependencies )
{
2015-03-21 11:34:08 -04:00
BinaryDependency . SetupDependentLinkEnvironment ( BinaryLinkEnvironment ) ;
2014-12-04 05:35:51 -05:00
}
2015-06-02 21:45:00 -04:00
// Remove the default resource file on Windows (PCLaunch.rc) if the user has specified their own
if ( BinaryLinkEnvironment . InputFiles . Select ( Item = > Path . GetFileName ( Item . AbsolutePath ) . ToLower ( ) ) . Any ( Name = > Name . EndsWith ( ".res" ) & & ! Name . EndsWith ( ".inl.res" ) & & Name ! = "pclaunch.rc.res" ) )
{
BinaryLinkEnvironment . InputFiles . RemoveAll ( x = > Path . GetFileName ( x . AbsolutePath ) . ToLower ( ) = = "pclaunch.rc.res" ) ;
}
2014-12-04 05:35:51 -05:00
// Set the link output file.
2015-05-18 08:16:56 -04:00
BinaryLinkEnvironment . Config . OutputFilePaths = Config . OutputFilePaths . ToList ( ) ;
2014-12-04 05:35:51 -05:00
// Set whether the link is allowed to have exports.
BinaryLinkEnvironment . Config . bHasExports = Config . bAllowExports ;
// Set the output folder for intermediate files
BinaryLinkEnvironment . Config . IntermediateDirectory = Config . IntermediateDirectory ;
// Put the non-executable output files (PDB, import library, etc) in the same directory as the production
2015-09-03 08:47:24 -04:00
BinaryLinkEnvironment . Config . OutputDirectory = Config . OutputFilePaths [ 0 ] . Directory ;
2014-12-04 05:35:51 -05:00
// Setup link output type
BinaryLinkEnvironment . Config . bIsBuildingDLL = IsBuildingDll ( Config . Type ) ;
BinaryLinkEnvironment . Config . bIsBuildingLibrary = IsBuildingLibrary ( Config . Type ) ;
return BinaryLinkEnvironment ;
}
2015-09-27 13:05:49 -04:00
private List < FileItem > SetupOutputFiles ( UEToolChain ToolChain , ref LinkEnvironment BinaryLinkEnvironment )
2014-12-04 05:35:51 -05:00
{
// Early exits first
if ( ProjectFileGenerator . bGenerateProjectFiles )
{
// We're generating projects. Since we only need include paths and definitions, there is no need
// to go ahead and run through the linking logic.
return BinaryLinkEnvironment . InputFiles ;
}
if ( BuildConfiguration . bEnableCodeAnalysis )
{
// We're only analyzing code, so we won't actually link any executables. Instead, our output
// files will simply be the .obj files that were compiled during static analysis.
return BinaryLinkEnvironment . InputFiles ;
}
if ( BuildConfiguration . bRunUnrealCodeAnalyzer )
{
//
// Create actions to analyze *.includes files and provide suggestions on how to modify PCH.
//
return CreateOutputFilesForUCA ( BinaryLinkEnvironment ) ;
}
//
// Regular linking action.
//
var OutputFiles = new List < FileItem > ( ) ;
if ( bCreateImportLibrarySeparately )
{
// Mark the link environment as cross-referenced.
BinaryLinkEnvironment . Config . bIsCrossReferenced = true ;
if ( BinaryLinkEnvironment . Config . Target . Platform ! = CPPTargetPlatform . Mac & & BinaryLinkEnvironment . Config . Target . Platform ! = CPPTargetPlatform . Linux )
{
// Create the import library.
2015-09-24 08:08:38 -04:00
OutputFiles . AddRange ( ToolChain . LinkAllFiles ( BinaryLinkEnvironment , true ) ) ;
2014-12-04 05:35:51 -05:00
}
}
BinaryLinkEnvironment . Config . bIncludeDependentLibrariesInLibrary = bIncludeDependentLibrariesInLibrary ;
// Link the binary.
2015-09-24 08:08:38 -04:00
FileItem [ ] Executables = ToolChain . LinkAllFiles ( BinaryLinkEnvironment , false ) ;
2014-12-04 05:35:51 -05:00
OutputFiles . AddRange ( Executables ) ;
// Produce additional console app if requested
2015-04-02 11:09:01 -04:00
if ( Config . bBuildAdditionalConsoleApp )
2014-12-04 05:35:51 -05:00
{
// Produce additional binary but link it as a console app
var ConsoleAppLinkEvironment = BinaryLinkEnvironment . DeepCopy ( ) ;
ConsoleAppLinkEvironment . Config . bIsBuildingConsoleApplication = true ;
ConsoleAppLinkEvironment . Config . WindowsEntryPointOverride = "WinMainCRTStartup" ; // For WinMain() instead of "main()" for Launch module
2015-05-18 08:16:56 -04:00
ConsoleAppLinkEvironment . Config . OutputFilePaths = ConsoleAppLinkEvironment . Config . OutputFilePaths . Select ( Path = > GetAdditionalConsoleAppPath ( Path ) ) . ToList ( ) ;
2014-12-04 05:35:51 -05:00
// Link the console app executable
2015-09-24 08:08:38 -04:00
OutputFiles . AddRange ( ToolChain . LinkAllFiles ( ConsoleAppLinkEvironment , false ) ) ;
2014-12-04 05:35:51 -05:00
}
foreach ( var Executable in Executables )
{
2015-09-24 08:08:38 -04:00
OutputFiles . AddRange ( ToolChain . PostBuild ( Executable , BinaryLinkEnvironment ) ) ;
2014-12-04 05:35:51 -05:00
}
return OutputFiles ;
}
private List < FileItem > CreateOutputFilesForUCA ( LinkEnvironment BinaryLinkEnvironment )
{
var OutputFiles = new List < FileItem > ( ) ;
2015-09-06 10:35:57 -04:00
var ModuleName = Modules . Select ( Module = > Module . Name ) . First ( Name = > Name . CompareTo ( BuildConfiguration . UCAModuleToAnalyze ) = = 0 ) ;
2014-12-04 05:35:51 -05:00
var ModuleCPP = ( UEBuildModuleCPP ) Target . GetModuleByName ( ModuleName ) ;
var ModulePrivatePCH = ModuleCPP . ProcessedDependencies . UniquePCHHeaderFile ;
2015-09-03 08:47:24 -04:00
var IntermediatePath = Path . Combine ( Target . ProjectIntermediateDirectory . FullName , ModuleName ) ;
2014-12-04 05:35:51 -05:00
var OutputFileName = Target . OutputPath ;
2015-09-03 08:47:24 -04:00
var OutputFile = FileItem . GetItemByFileReference ( OutputFileName ) ;
2014-12-04 05:35:51 -05:00
Action LinkAction = new Action ( ActionType . Compile ) ;
2015-09-03 08:47:24 -04:00
LinkAction . WorkingDirectory = UnrealBuildTool . EngineSourceDirectory . FullName ;
2015-07-08 05:11:51 -04:00
LinkAction . CommandPath = System . IO . Path . Combine ( LinkAction . WorkingDirectory , @".." , @"Binaries" , @"Win32" , @"UnrealCodeAnalyzer.exe" ) ;
2014-12-04 05:35:51 -05:00
LinkAction . ProducedItems . Add ( OutputFile ) ;
LinkAction . PrerequisiteItems . AddRange ( BinaryLinkEnvironment . InputFiles ) ;
LinkAction . CommandArguments = @"-AnalyzePCHFile -PCHFile=""" + ModulePrivatePCH . AbsolutePath + @""" -OutputFile=""" + OutputFileName + @""" -HeaderDataPath=""" + IntermediatePath + @""" -UsageThreshold " + BuildConfiguration . UCAUsageThreshold . ToString ( CultureInfo . InvariantCulture ) ;
foreach ( string IncludeSearchPath in ModuleCPP . IncludeSearchPaths )
{
LinkAction . CommandArguments + = @" /I""" + LinkAction . WorkingDirectory + @"\" + IncludeSearchPath + @"""" ;
}
OutputFiles . Add ( OutputFile ) ;
return OutputFiles ;
}
2014-03-14 14:13:41 -04:00
} ;
/// <summary>
/// A DLL built by MSBuild from a C# project.
/// </summary>
public class UEBuildBinaryCSDLL : UEBuildBinary
{
/// <summary>
/// Create an instance initialized to the given configuration
/// </summary>
/// <param name="InConfig">The build binary configuration to initialize the instance to</param>
public UEBuildBinaryCSDLL ( UEBuildTarget InTarget , UEBuildBinaryConfiguration InConfig )
: base ( InTarget , InConfig )
{
}
/// <summary>
/// Builds the binary.
/// </summary>
2014-06-17 02:04:37 -04:00
/// <param name="ToolChain">The toolchain to use for building</param>
2014-03-14 14:13:41 -04:00
/// <param name="CompileEnvironment">The environment to compile the binary in</param>
/// <param name="LinkEnvironment">The environment to link the binary in</param>
/// <returns></returns>
2015-09-27 13:05:49 -04:00
public override IEnumerable < FileItem > Build ( UEToolChain ToolChain , CPPEnvironment CompileEnvironment , LinkEnvironment LinkEnvironment )
2014-03-14 14:13:41 -04:00
{
var ProjectCSharpEnviroment = new CSharpEnvironment ( ) ;
2014-06-09 11:12:01 -04:00
if ( LinkEnvironment . Config . Target . Configuration = = CPPTargetConfiguration . Debug )
2015-09-24 12:37:21 -04:00
{
2014-03-14 14:13:41 -04:00
ProjectCSharpEnviroment . TargetConfiguration = CSharpTargetConfiguration . Debug ;
}
else
{
ProjectCSharpEnviroment . TargetConfiguration = CSharpTargetConfiguration . Development ;
}
2014-06-09 11:12:01 -04:00
ProjectCSharpEnviroment . EnvironmentTargetPlatform = LinkEnvironment . Config . Target . Platform ;
2014-03-14 14:13:41 -04:00
2015-09-24 08:08:38 -04:00
ToolChain . CompileCSharpProject ( ProjectCSharpEnviroment , Config . ProjectFilePath , Config . OutputFilePath ) ;
2014-03-14 14:13:41 -04:00
2015-09-03 08:47:24 -04:00
return new FileItem [ ] { FileItem . GetItemByFileReference ( Config . OutputFilePath ) } ;
2014-03-14 14:13:41 -04:00
}
} ;
}