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 ;
2014-04-29 11:21:18 -04:00
using System.Text.RegularExpressions ;
2014-03-14 14:13:41 -04:00
using System.Xml ;
2015-06-09 11:50:55 -04:00
using Tools.DotNETCommon.CaselessDictionary ;
2014-03-14 14:13:41 -04:00
namespace UnrealBuildTool
{
2014-05-22 01:20:24 -04:00
/** Type of module. Mirrored in UHT as EBuildModuleType */
2014-03-14 14:13:41 -04:00
public enum UEBuildModuleType
{
2014-05-22 01:20:24 -04:00
Unknown ,
Runtime ,
Developer ,
Editor ,
ThirdParty ,
Program ,
Game ,
}
public static class UEBuildModuleTypeExtensions
{
public static bool IsEngineModule ( this UEBuildModuleType ModuleType )
{
return ModuleType ! = UEBuildModuleType . Game ;
}
2014-03-14 14:13:41 -04:00
}
2015-03-27 07:15:32 -04:00
/ * *
* Distribution level of module .
* Note : The name of each entry is used to search for / create folders
* /
public enum UEBuildModuleDistribution
{
/// Binaries can be distributed to everyone
Public ,
/// Can be used by UE4 but not required
CarefullyRedist ,
/// Epic Employees and Contractors
NotForLicensees ,
/// Epic Employees only
NoRedist ,
}
2014-03-14 14:13:41 -04:00
/** A unit of code compilation and linking. */
public abstract class UEBuildModule
{
2014-05-22 01:20:24 -04:00
/** Known module folders */
public static readonly string RuntimeFolder = String . Format ( "{0}Runtime{0}" , Path . DirectorySeparatorChar ) ;
public static readonly string DeveloperFolder = String . Format ( "{0}Developer{0}" , Path . DirectorySeparatorChar ) ;
public static readonly string EditorFolder = String . Format ( "{0}Editor{0}" , Path . DirectorySeparatorChar ) ;
public static readonly string ProgramsFolder = String . Format ( "{0}Programs{0}" , Path . DirectorySeparatorChar ) ;
2015-04-21 15:16:38 -04:00
public static UEBuildModuleType GetModuleTypeFromDescriptor ( ModuleDescriptor Module )
2014-05-29 17:37:45 -04:00
{
2015-04-21 15:16:38 -04:00
switch ( Module . Type )
2014-05-29 17:37:45 -04:00
{
2015-04-21 15:16:38 -04:00
case ModuleHostType . Developer :
return UEBuildModuleType . Developer ;
case ModuleHostType . Editor :
case ModuleHostType . EditorNoCommandlet :
return UEBuildModuleType . Editor ;
case ModuleHostType . Program :
return UEBuildModuleType . Program ;
case ModuleHostType . Runtime :
case ModuleHostType . RuntimeNoCommandlet :
return UEBuildModuleType . Runtime ;
default :
throw new BuildException ( "Unhandled module type {0}" , Module . Type . ToString ( ) ) ;
2014-05-29 17:37:45 -04:00
}
}
public static UEBuildModuleType GetEngineModuleTypeBasedOnLocation ( string ModuleName , UEBuildModuleType ModuleType , string ModuleFileRelativeToEngineDirectory )
2014-05-22 01:20:24 -04:00
{
if ( ModuleFileRelativeToEngineDirectory . IndexOf ( UEBuildModule . RuntimeFolder , StringComparison . InvariantCultureIgnoreCase ) > = 0 )
{
ModuleType = UEBuildModuleType . Runtime ;
}
else if ( ModuleFileRelativeToEngineDirectory . IndexOf ( UEBuildModule . DeveloperFolder , StringComparison . InvariantCultureIgnoreCase ) > = 0 )
{
ModuleType = UEBuildModuleType . Developer ;
}
else if ( ModuleFileRelativeToEngineDirectory . IndexOf ( UEBuildModule . EditorFolder , StringComparison . InvariantCultureIgnoreCase ) > = 0 )
{
ModuleType = UEBuildModuleType . Editor ;
}
else if ( ModuleFileRelativeToEngineDirectory . IndexOf ( UEBuildModule . ProgramsFolder , StringComparison . InvariantCultureIgnoreCase ) > = 0 )
{
ModuleType = UEBuildModuleType . Program ;
}
return ModuleType ;
}
2015-03-27 07:15:32 -04:00
/ * *
* Checks what distribution level a particular path should have by checking for key folders anywhere in it
* /
public static UEBuildModuleDistribution GetModuleDistributionLevelBasedOnLocation ( string FilePath )
{
// Get full path to ensure all folder separators are the same
FilePath = Path . GetFullPath ( FilePath ) ;
// Check from highest to lowest (don't actually need to check 'Everyone')
for ( var DistributionLevel = UEBuildModuleDistribution . NoRedist ; DistributionLevel > UEBuildModuleDistribution . Public ; DistributionLevel - - )
{
var DistributionFolderName = String . Format ( "{0}{1}{0}" , Path . DirectorySeparatorChar , DistributionLevel . ToString ( ) ) ;
if ( FilePath . IndexOf ( DistributionFolderName , StringComparison . InvariantCultureIgnoreCase ) > = 0 )
{
return DistributionLevel ;
}
if ( DistributionLevel = = UEBuildModuleDistribution . NotForLicensees )
{
// Extra checks for PS4 and XboxOne folders, which are equivalent to NotForLicensees
var PS4FolderName = String . Format ( "{0}ps4{0}" , Path . DirectorySeparatorChar ) ;
var XboxFolderName = String . Format ( "{0}xboxone{0}" , Path . DirectorySeparatorChar ) ;
if ( FilePath . IndexOf ( PS4FolderName , StringComparison . InvariantCultureIgnoreCase ) > = 0
| | FilePath . IndexOf ( XboxFolderName , StringComparison . InvariantCultureIgnoreCase ) > = 0 )
{
return UEBuildModuleDistribution . NotForLicensees ;
}
}
}
return UEBuildModuleDistribution . Public ;
}
/ * *
* Determines the distribution level of a module based on its directory and includes .
* /
private void SetupModuleDistributionLevel ( )
{
List < string > PathsToCheck = new List < string > ( ) ;
PathsToCheck . Add ( ModuleDirectory ) ;
PathsToCheck . AddRange ( PublicIncludePaths ) ;
PathsToCheck . AddRange ( PrivateIncludePaths ) ;
// Not sure if these two are necessary as paths will usually be in basic includes too
PathsToCheck . AddRange ( PublicSystemIncludePaths ) ;
PathsToCheck . AddRange ( PublicLibraryPaths ) ;
DistributionLevel = UEBuildModuleDistribution . Public ;
// Keep checking as long as we haven't reached the maximum level
for ( int PathIndex = 0 ; PathIndex < PathsToCheck . Count & & DistributionLevel ! = UEBuildModuleDistribution . NoRedist ; + + PathIndex )
{
DistributionLevel = Utils . Max ( DistributionLevel , UEBuildModule . GetModuleDistributionLevelBasedOnLocation ( PathsToCheck [ PathIndex ] ) ) ;
}
}
2014-09-11 03:21:51 -04:00
/** Converts an optional string list parameter to a well-defined hash set. */
protected static HashSet < string > HashSetFromOptionalEnumerableStringParameter ( IEnumerable < string > InEnumerableStrings )
2014-03-14 14:13:41 -04:00
{
2014-09-11 03:21:51 -04:00
return InEnumerableStrings = = null ? new HashSet < string > ( ) : new HashSet < string > ( InEnumerableStrings ) ;
2014-03-14 14:13:41 -04:00
}
/** The target which owns this module. */
public readonly UEBuildTarget Target ;
/** The name that uniquely identifies the module. */
public readonly string Name ;
/** The type of module being built. Used to switch between debug/development and precompiled/source configurations. */
public UEBuildModuleType Type ;
2015-08-28 08:39:42 -04:00
/** The rules for this module */
public ModuleRules Rules ;
2015-03-27 07:15:32 -04:00
/** The distribution level of the module being built. Used to check where build products are placed. */
public UEBuildModuleDistribution DistributionLevel ;
2014-03-14 14:13:41 -04:00
/** Path to the module directory */
public readonly string ModuleDirectory ;
2014-07-21 04:28:22 -04:00
/** Is this module allowed to be redistributed. */
private readonly bool? IsRedistributableOverride ;
2015-05-08 15:19:00 -04:00
/** The name of the .Build.cs file this module was created from, if any */
private readonly string BuildCsFilenameField ;
public string BuildCsFilename { get { return BuildCsFilenameField ; } }
2014-07-21 04:28:22 -04:00
/ * *
* Tells if this module can be redistributed .
*
* @returns True if this module can be redistributed . False otherwise .
* /
public bool IsRedistributable ( )
{
return IsRedistributableOverride . HasValue
? IsRedistributableOverride . Value
: ( Type ! = UEBuildModuleType . Developer & & Type ! = UEBuildModuleType . Editor ) ;
}
2014-03-14 14:13:41 -04:00
/** The binary the module will be linked into for the current target. Only set after UEBuildBinary.BindModules is called. */
public UEBuildBinary Binary = null ;
/** Whether this module is included in the current target. Only set after UEBuildBinary.BindModules is called. */
public bool bIncludedInTarget = false ;
2014-04-30 07:59:06 -04:00
2014-09-11 03:21:51 -04:00
protected readonly HashSet < string > PublicDefinitions ;
protected readonly HashSet < string > PublicIncludePaths ;
protected readonly HashSet < string > PrivateIncludePaths ;
protected readonly HashSet < string > PublicSystemIncludePaths ;
protected readonly HashSet < string > PublicLibraryPaths ;
protected readonly HashSet < string > PublicAdditionalLibraries ;
protected readonly HashSet < string > PublicFrameworks ;
protected readonly HashSet < string > PublicWeakFrameworks ;
protected readonly HashSet < UEBuildFramework > PublicAdditionalFrameworks ;
protected readonly HashSet < string > PublicAdditionalShadowFiles ;
protected readonly HashSet < UEBuildBundleResource > PublicAdditionalBundleResources ;
2014-03-14 14:13:41 -04:00
/** Names of modules with header files that this module's public interface needs access to. */
2015-08-28 15:47:20 -04:00
protected List < UEBuildModule > PublicIncludePathModules ;
2014-03-14 14:13:41 -04:00
/** Names of modules that this module's public interface depends on. */
2015-08-28 15:47:20 -04:00
protected List < UEBuildModule > PublicDependencyModules ;
2014-03-14 14:13:41 -04:00
/** Names of DLLs that this module should delay load */
2014-09-11 03:21:51 -04:00
protected HashSet < string > PublicDelayLoadDLLs ;
2014-03-14 14:13:41 -04:00
/** Names of modules with header files that this module's private implementation needs access to. */
2015-08-28 15:47:20 -04:00
protected List < UEBuildModule > PrivateIncludePathModules ;
2014-03-14 14:13:41 -04:00
/** Names of modules that this module's private implementation depends on. */
2015-08-28 15:47:20 -04:00
protected List < UEBuildModule > PrivateDependencyModules ;
2014-03-14 14:13:41 -04:00
/** Extra modules this module may require at run time */
2015-08-28 15:47:20 -04:00
protected List < UEBuildModule > DynamicallyLoadedModules ;
2014-03-14 14:13:41 -04:00
/** Extra modules this module may require at run time, that are on behalf of another platform (i.e. shader formats and the like) */
2015-08-28 15:47:20 -04:00
protected List < UEBuildModule > PlatformSpecificDynamicallyLoadedModules ;
2014-03-14 14:13:41 -04:00
2015-04-03 10:25:57 -04:00
/** Files which this module depends on at runtime. */
public List < RuntimeDependency > RuntimeDependencies ;
2014-03-14 14:13:41 -04:00
public UEBuildModule (
UEBuildTarget InTarget ,
string InName ,
UEBuildModuleType InType ,
string InModuleDirectory ,
2015-08-28 08:39:42 -04:00
ModuleRules InRules ,
2015-05-08 15:19:00 -04:00
string InBuildCsFilename
2014-03-14 14:13:41 -04:00
)
{
Target = InTarget ;
Name = InName ;
Type = InType ;
2015-08-28 08:39:42 -04:00
Rules = InRules ;
2014-03-14 14:13:41 -04:00
ModuleDirectory = InModuleDirectory ;
2015-08-28 08:39:42 -04:00
PublicDefinitions = HashSetFromOptionalEnumerableStringParameter ( InRules . Definitions ) ;
PublicIncludePaths = HashSetFromOptionalEnumerableStringParameter ( InRules . PublicIncludePaths ) ;
PublicSystemIncludePaths = HashSetFromOptionalEnumerableStringParameter ( InRules . PublicSystemIncludePaths ) ;
PublicLibraryPaths = HashSetFromOptionalEnumerableStringParameter ( InRules . PublicLibraryPaths ) ;
PublicAdditionalLibraries = HashSetFromOptionalEnumerableStringParameter ( InRules . PublicAdditionalLibraries ) ;
PublicFrameworks = HashSetFromOptionalEnumerableStringParameter ( InRules . PublicFrameworks ) ;
PublicWeakFrameworks = HashSetFromOptionalEnumerableStringParameter ( InRules . PublicWeakFrameworks ) ;
PublicAdditionalFrameworks = InRules . PublicAdditionalFrameworks = = null ? new HashSet < UEBuildFramework > ( ) : new HashSet < UEBuildFramework > ( InRules . PublicAdditionalFrameworks ) ;
PublicAdditionalShadowFiles = HashSetFromOptionalEnumerableStringParameter ( InRules . PublicAdditionalShadowFiles ) ;
PublicAdditionalBundleResources = InRules . AdditionalBundleResources = = null ? new HashSet < UEBuildBundleResource > ( ) : new HashSet < UEBuildBundleResource > ( InRules . AdditionalBundleResources ) ;
PublicDelayLoadDLLs = HashSetFromOptionalEnumerableStringParameter ( InRules . PublicDelayLoadDLLs ) ;
PrivateIncludePaths = HashSetFromOptionalEnumerableStringParameter ( InRules . PrivateIncludePaths ) ;
RuntimeDependencies = ( InRules . RuntimeDependencies = = null ) ? new List < RuntimeDependency > ( ) : new List < RuntimeDependency > ( InRules . RuntimeDependencies ) ;
IsRedistributableOverride = InRules . IsRedistributableOverride ;
2014-03-14 14:13:41 -04:00
2015-05-08 15:19:00 -04:00
Debug . Assert ( InBuildCsFilename = = null | | InBuildCsFilename . EndsWith ( ".Build.cs" , StringComparison . InvariantCultureIgnoreCase ) ) ;
BuildCsFilenameField = InBuildCsFilename ;
2015-03-27 07:15:32 -04:00
SetupModuleDistributionLevel ( ) ;
2014-03-14 14:13:41 -04:00
Target . RegisterModule ( this ) ;
}
2015-08-28 15:47:20 -04:00
/** Determines whether this module has a circular dependency on the given module */
public bool HasCircularDependencyOn ( string ModuleName )
{
return Rules . CircularlyReferencedDependentModules . Contains ( ModuleName ) ;
}
2014-03-14 14:13:41 -04:00
/** Sets up the environment for compiling any module that includes the public interface of this module. */
protected virtual void SetupPublicCompileEnvironment (
UEBuildBinary SourceBinary ,
bool bIncludePathsOnly ,
2015-03-21 11:34:08 -04:00
HashSet < string > IncludePaths ,
HashSet < string > SystemIncludePaths ,
List < string > Definitions ,
List < UEBuildFramework > AdditionalFrameworks ,
Dictionary < UEBuildModule , bool > VisitedModules
2014-03-14 14:13:41 -04:00
)
{
// There may be circular dependencies in compile dependencies, so we need to avoid reentrance.
if ( ! VisitedModules . ContainsKey ( this ) )
{
VisitedModules . Add ( this , true ) ;
// Add this module's public include paths and definitions.
2014-08-21 07:33:21 -04:00
AddIncludePathsWithChecks ( IncludePaths , PublicIncludePaths ) ;
AddIncludePathsWithChecks ( SystemIncludePaths , PublicSystemIncludePaths ) ;
2014-03-14 14:13:41 -04:00
Definitions . AddRange ( PublicDefinitions ) ;
// If this module is being built into a DLL or EXE, set up an IMPORTS or EXPORTS definition for it.
2015-08-10 13:10:18 -04:00
if ( Binary = = null )
{
// If we're referencing include paths for a module that's not being built, we don't actually need to import anything from it, but we need to avoid barfing when
// the compiler encounters an _API define. We also want to avoid changing the compile environment in cases where the module happens to be compiled because it's a dependency
// of something else, which cause a fall-through to the code below and set up an empty _API define.
if ( bIncludePathsOnly )
{
Log . TraceVerbose ( "{0}: Include paths only for {1} (no binary)" , Path . GetFileNameWithoutExtension ( SourceBinary . Config . OutputFilePaths [ 0 ] ) , Name ) ;
Definitions . Add ( Name . ToUpperInvariant ( ) + "_API=" ) ;
}
}
else
2014-03-14 14:13:41 -04:00
{
2014-09-02 14:26:49 -04:00
string BinaryPath = Binary . Config . OutputFilePaths [ 0 ] ;
string SourceBinaryPath = SourceBinary . Config . OutputFilePaths [ 0 ] ;
2014-03-14 14:13:41 -04:00
if ( ProjectFileGenerator . bGenerateProjectFiles | | ( Binary . Config . Type = = UEBuildBinaryType . StaticLibrary ) )
{
// When generating IntelliSense files, never add dllimport/dllexport specifiers as it
// simply confuses the compiler
2014-07-31 09:34:11 -04:00
Definitions . Add ( Name . ToUpperInvariant ( ) + "_API=" ) ;
2014-03-14 14:13:41 -04:00
}
else if ( Binary = = SourceBinary )
{
if ( Binary . Config . bAllowExports )
{
2014-09-02 14:26:49 -04:00
Log . TraceVerbose ( "{0}: Exporting {1} from {2}" , Path . GetFileNameWithoutExtension ( SourceBinaryPath ) , Name , Path . GetFileNameWithoutExtension ( BinaryPath ) ) ;
2014-07-31 09:34:11 -04:00
Definitions . Add ( Name . ToUpperInvariant ( ) + "_API=DLLEXPORT" ) ;
2014-03-14 14:13:41 -04:00
}
else
{
2014-09-02 14:26:49 -04:00
Log . TraceVerbose ( "{0}: Not importing/exporting {1} (binary: {2})" , Path . GetFileNameWithoutExtension ( SourceBinaryPath ) , Name , Path . GetFileNameWithoutExtension ( BinaryPath ) ) ;
2014-07-31 09:34:11 -04:00
Definitions . Add ( Name . ToUpperInvariant ( ) + "_API=" ) ;
2014-03-14 14:13:41 -04:00
}
}
else
{
// @todo SharedPCH: Public headers included from modules that are not importing the module of that public header, seems invalid.
// Those public headers have no business having APIs in them. OnlineSubsystem has some public headers like this. Without changing
// this, we need to suppress warnings at compile time.
if ( bIncludePathsOnly )
{
2014-09-02 14:26:49 -04:00
Log . TraceVerbose ( "{0}: Include paths only for {1} (binary: {2})" , Path . GetFileNameWithoutExtension ( SourceBinaryPath ) , Name , Path . GetFileNameWithoutExtension ( BinaryPath ) ) ;
2014-07-31 09:34:11 -04:00
Definitions . Add ( Name . ToUpperInvariant ( ) + "_API=" ) ;
2014-03-14 14:13:41 -04:00
}
else if ( Binary . Config . bAllowExports )
{
2014-09-02 14:26:49 -04:00
Log . TraceVerbose ( "{0}: Importing {1} from {2}" , Path . GetFileNameWithoutExtension ( SourceBinaryPath ) , Name , Path . GetFileNameWithoutExtension ( BinaryPath ) ) ;
2014-07-31 09:34:11 -04:00
Definitions . Add ( Name . ToUpperInvariant ( ) + "_API=DLLIMPORT" ) ;
2014-03-14 14:13:41 -04:00
}
else
{
2014-09-02 14:26:49 -04:00
Log . TraceVerbose ( "{0}: Not importing/exporting {1} (binary: {2})" , Path . GetFileNameWithoutExtension ( SourceBinaryPath ) , Name , Path . GetFileNameWithoutExtension ( BinaryPath ) ) ;
2014-07-31 09:34:11 -04:00
Definitions . Add ( Name . ToUpperInvariant ( ) + "_API=" ) ;
2014-03-14 14:13:41 -04:00
}
}
}
if ( ! bIncludePathsOnly )
{
// Recurse on this module's public dependencies.
2015-08-28 15:47:20 -04:00
foreach ( UEBuildModule DependencyModule in PublicDependencyModules )
2014-03-14 14:13:41 -04:00
{
2015-03-21 11:34:08 -04:00
DependencyModule . SetupPublicCompileEnvironment ( SourceBinary , bIncludePathsOnly , IncludePaths , SystemIncludePaths , Definitions , AdditionalFrameworks , VisitedModules ) ;
2014-03-14 14:13:41 -04:00
}
}
// Now add an include paths from modules with header files that we need access to, but won't necessarily be importing
2015-08-28 15:47:20 -04:00
foreach ( UEBuildModule IncludePathModule in PublicIncludePathModules )
2014-03-14 14:13:41 -04:00
{
bool bInnerIncludePathsOnly = true ;
2015-03-21 11:34:08 -04:00
IncludePathModule . SetupPublicCompileEnvironment ( SourceBinary , bInnerIncludePathsOnly , IncludePaths , SystemIncludePaths , Definitions , AdditionalFrameworks , VisitedModules ) ;
2014-03-14 14:13:41 -04:00
}
2014-05-19 06:57:00 -04:00
// Add the module's directory to the include path, so we can root #includes to it
2014-06-23 07:57:23 -04:00
IncludePaths . Add ( Utils . CleanDirectorySeparators ( Utils . MakePathRelativeTo ( ModuleDirectory , Path . Combine ( ProjectFileGenerator . RootRelativePath , "Engine/Source" ) ) , '/' ) ) ;
2014-07-01 11:28:39 -04:00
// Add the additional frameworks so that the compiler can know about their #include paths
AdditionalFrameworks . AddRange ( PublicAdditionalFrameworks ) ;
2014-12-04 11:18:56 -05:00
// Remember the module so we can refer to it when needed
foreach ( var Framework in PublicAdditionalFrameworks )
{
Framework . OwningModule = this ;
}
2014-03-14 14:13:41 -04:00
}
}
2014-08-21 07:33:21 -04:00
2014-08-22 08:28:48 -04:00
static Regex VCMacroRegex = new Regex ( @"\$\([A-Za-z0-9_]+\)" ) ;
2014-08-22 08:23:53 -04:00
/** Checks if path contains a VC macro */
protected bool DoesPathContainVCMacro ( string Path )
{
2014-08-22 08:28:48 -04:00
return VCMacroRegex . IsMatch ( Path ) ;
2014-08-22 08:23:53 -04:00
}
2014-08-21 07:33:21 -04:00
/** Adds PathsToAdd to IncludePaths, performing path normalization and ignoring duplicates. */
2014-09-11 03:21:51 -04:00
protected void AddIncludePathsWithChecks ( HashSet < string > IncludePaths , HashSet < string > PathsToAdd )
2014-08-21 07:33:21 -04:00
{
2014-09-11 05:47:22 -04:00
if ( ProjectFileGenerator . bGenerateProjectFiles )
2014-08-21 07:33:21 -04:00
{
2014-09-11 05:47:22 -04:00
// Extra checks are switched off for IntelliSense generation as they provide
// no additional value and cause performance impact.
IncludePaths . UnionWith ( PathsToAdd ) ;
}
else
{
foreach ( var Path in PathsToAdd )
2014-08-21 07:33:21 -04:00
{
2014-09-11 05:47:22 -04:00
var NormalizedPath = Path . TrimEnd ( '/' ) ;
// If path doesn't exist, it may contain VC macro (which is passed directly to and expanded by compiler).
if ( Directory . Exists ( NormalizedPath ) | | DoesPathContainVCMacro ( NormalizedPath ) )
{
IncludePaths . Add ( NormalizedPath ) ;
}
2014-08-21 07:33:21 -04:00
}
}
}
2014-03-14 14:13:41 -04:00
/** Sets up the environment for compiling this module. */
protected virtual void SetupPrivateCompileEnvironment (
2015-03-21 11:34:08 -04:00
HashSet < string > IncludePaths ,
HashSet < string > SystemIncludePaths ,
List < string > Definitions ,
List < UEBuildFramework > AdditionalFrameworks
2014-03-14 14:13:41 -04:00
)
{
2015-08-28 15:47:20 -04:00
Dictionary < UEBuildModule , bool > VisitedModules = new Dictionary < UEBuildModule , bool > ( ) ;
2014-03-14 14:13:41 -04:00
2014-10-30 17:10:56 -04:00
if ( this . Type = = UEBuildModuleType . Game )
{
Definitions . Add ( "DEPRECATED_FORGAME=DEPRECATED" ) ;
}
2014-03-14 14:13:41 -04:00
// Add this module's private include paths and definitions.
2014-08-21 07:33:21 -04:00
AddIncludePathsWithChecks ( IncludePaths , PrivateIncludePaths ) ;
2014-03-14 14:13:41 -04:00
// Allow the module's public dependencies to modify the compile environment.
bool bIncludePathsOnly = false ;
2015-03-21 11:34:08 -04:00
SetupPublicCompileEnvironment ( Binary , bIncludePathsOnly , IncludePaths , SystemIncludePaths , Definitions , AdditionalFrameworks , VisitedModules ) ;
2014-03-14 14:13:41 -04:00
// Also allow the module's private dependencies to modify the compile environment.
2015-08-28 15:47:20 -04:00
foreach ( UEBuildModule DependencyModule in PrivateDependencyModules )
2014-03-14 14:13:41 -04:00
{
2015-03-21 11:34:08 -04:00
DependencyModule . SetupPublicCompileEnvironment ( Binary , bIncludePathsOnly , IncludePaths , SystemIncludePaths , Definitions , AdditionalFrameworks , VisitedModules ) ;
2014-03-14 14:13:41 -04:00
}
// Add include paths from modules with header files that our private files need access to, but won't necessarily be importing
2015-08-28 15:47:20 -04:00
foreach ( UEBuildModule IncludePathModule in PrivateIncludePathModules )
2014-03-14 14:13:41 -04:00
{
bool bInnerIncludePathsOnly = true ;
2015-03-21 11:34:08 -04:00
IncludePathModule . SetupPublicCompileEnvironment ( Binary , bInnerIncludePathsOnly , IncludePaths , SystemIncludePaths , Definitions , AdditionalFrameworks , VisitedModules ) ;
2014-03-14 14:13:41 -04:00
}
}
/** Sets up the environment for linking any module that includes the public interface of this module. */
protected virtual void SetupPublicLinkEnvironment (
UEBuildBinary SourceBinary ,
2015-03-21 11:34:08 -04:00
List < string > LibraryPaths ,
List < string > AdditionalLibraries ,
List < string > Frameworks ,
List < string > WeakFrameworks ,
List < UEBuildFramework > AdditionalFrameworks ,
List < string > AdditionalShadowFiles ,
List < UEBuildBundleResource > AdditionalBundleResources ,
List < string > DelayLoadDLLs ,
List < UEBuildBinary > BinaryDependencies ,
Dictionary < UEBuildModule , bool > VisitedModules
2014-03-14 14:13:41 -04:00
)
{
// There may be circular dependencies in compile dependencies, so we need to avoid reentrance.
if ( ! VisitedModules . ContainsKey ( this ) )
{
VisitedModules . Add ( this , true ) ;
// Only process modules that are included in the current target.
if ( bIncludedInTarget )
{
// Add this module's binary to the binary dependencies.
if ( Binary ! = null
& & Binary ! = SourceBinary
& & ! BinaryDependencies . Contains ( Binary ) )
{
BinaryDependencies . Add ( Binary ) ;
}
// If this module belongs to a static library that we are not currently building, recursively add the link environment settings for all of its dependencies too.
// Keep doing this until we reach a module that is not part of a static library (or external module, since they have no associated binary).
// Static libraries do not contain the symbols for their dependencies, so we need to recursively gather them to be linked into other binary types.
bool bIsBuildingAStaticLibrary = ( SourceBinary ! = null & & SourceBinary . Config . Type = = UEBuildBinaryType . StaticLibrary ) ;
bool bIsModuleBinaryAStaticLibrary = ( Binary ! = null & & Binary . Config . Type = = UEBuildBinaryType . StaticLibrary ) ;
if ( ! bIsBuildingAStaticLibrary & & bIsModuleBinaryAStaticLibrary )
{
// Gather all dependencies and recursively call SetupPublicLinkEnvironmnet
2015-08-28 15:47:20 -04:00
List < UEBuildModule > AllDependencyModules = new List < UEBuildModule > ( ) ;
AllDependencyModules . AddRange ( PrivateDependencyModules ) ;
AllDependencyModules . AddRange ( PublicDependencyModules ) ;
2014-03-14 14:13:41 -04:00
2015-08-28 15:47:20 -04:00
foreach ( UEBuildModule DependencyModule in AllDependencyModules )
2014-03-14 14:13:41 -04:00
{
bool bIsExternalModule = ( DependencyModule as UEBuildExternalModule ! = null ) ;
bool bIsInStaticLibrary = ( DependencyModule . Binary ! = null & & DependencyModule . Binary . Config . Type = = UEBuildBinaryType . StaticLibrary ) ;
if ( bIsExternalModule | | bIsInStaticLibrary )
{
2015-03-21 11:34:08 -04:00
DependencyModule . SetupPublicLinkEnvironment ( SourceBinary , LibraryPaths , AdditionalLibraries , Frameworks , WeakFrameworks ,
AdditionalFrameworks , AdditionalShadowFiles , AdditionalBundleResources , DelayLoadDLLs , BinaryDependencies , VisitedModules ) ;
2014-03-14 14:13:41 -04:00
}
}
}
// Add this module's public include library paths and additional libraries.
LibraryPaths . AddRange ( PublicLibraryPaths ) ;
AdditionalLibraries . AddRange ( PublicAdditionalLibraries ) ;
Frameworks . AddRange ( PublicFrameworks ) ;
2014-06-18 15:57:40 -04:00
WeakFrameworks . AddRange ( PublicWeakFrameworks ) ;
2014-07-28 14:55:48 -04:00
AdditionalBundleResources . AddRange ( PublicAdditionalBundleResources ) ;
Support for third party iOS framework bundled assets
* Work in progress, works with RPC utility, local mac support incoming
* Changed AdditionalPublicFrameworks from storing just string, to storing the frame work name, zip name, and bundled asset name that needs to be copied
* We also now store the module that added this framework, so we can derive the module project path, etc when we need it for when we create intermediate directories
#Codereview Josh.Adams, Peter.Sauerbrei, Michael.Noland, Gil.Gribb, Robert.Manuszewski
[CL 2068603 by John Pollard in Main branch]
2014-05-09 16:38:26 -04:00
// Remember the module so we can refer to it when needed
foreach ( var Framework in PublicAdditionalFrameworks )
{
Framework . OwningModule = this ;
}
2014-03-14 14:13:41 -04:00
AdditionalFrameworks . AddRange ( PublicAdditionalFrameworks ) ;
AdditionalShadowFiles . AddRange ( PublicAdditionalShadowFiles ) ;
DelayLoadDLLs . AddRange ( PublicDelayLoadDLLs ) ;
}
}
}
/** Sets up the environment for linking this module. */
public virtual void SetupPrivateLinkEnvironment (
2015-05-22 08:57:34 -04:00
UEBuildBinary SourceBinary ,
2015-03-21 11:34:08 -04:00
LinkEnvironment LinkEnvironment ,
List < UEBuildBinary > BinaryDependencies ,
Dictionary < UEBuildModule , bool > VisitedModules
2014-03-14 14:13:41 -04:00
)
{
// Allow the module's public dependencies to add library paths and additional libraries to the link environment.
2015-05-22 08:57:34 -04:00
SetupPublicLinkEnvironment ( SourceBinary , LinkEnvironment . Config . LibraryPaths , LinkEnvironment . Config . AdditionalLibraries , LinkEnvironment . Config . Frameworks , LinkEnvironment . Config . WeakFrameworks ,
2015-03-21 11:34:08 -04:00
LinkEnvironment . Config . AdditionalFrameworks , LinkEnvironment . Config . AdditionalShadowFiles , LinkEnvironment . Config . AdditionalBundleResources , LinkEnvironment . Config . DelayLoadDLLs , BinaryDependencies , VisitedModules ) ;
2014-03-14 14:13:41 -04:00
// Also allow the module's public and private dependencies to modify the link environment.
2015-08-28 15:47:20 -04:00
List < UEBuildModule > AllDependencyModules = new List < UEBuildModule > ( ) ;
AllDependencyModules . AddRange ( PrivateDependencyModules ) ;
AllDependencyModules . AddRange ( PublicDependencyModules ) ;
2014-03-14 14:13:41 -04:00
2015-08-28 15:47:20 -04:00
foreach ( UEBuildModule DependencyModule in AllDependencyModules )
2014-03-14 14:13:41 -04:00
{
2015-05-22 08:57:34 -04:00
DependencyModule . SetupPublicLinkEnvironment ( SourceBinary , LinkEnvironment . Config . LibraryPaths , LinkEnvironment . Config . AdditionalLibraries , LinkEnvironment . Config . Frameworks , LinkEnvironment . Config . WeakFrameworks ,
2015-03-21 11:34:08 -04:00
LinkEnvironment . Config . AdditionalFrameworks , LinkEnvironment . Config . AdditionalShadowFiles , LinkEnvironment . Config . AdditionalBundleResources , LinkEnvironment . Config . DelayLoadDLLs , BinaryDependencies , VisitedModules ) ;
2014-03-14 14:13:41 -04:00
}
}
/** Compiles the module, and returns a list of files output by the compiler. */
2015-04-10 11:19:40 -04:00
public abstract List < FileItem > Compile ( CPPEnvironment GlobalCompileEnvironment , CPPEnvironment CompileEnvironment ) ;
2014-03-14 14:13:41 -04:00
// Object interface.
public override string ToString ( )
{
return Name ;
}
2015-06-09 11:50:55 -04:00
[DebuggerDisplay("{Index}: {Module}")]
public class ModuleIndexPair
{
public UEBuildModule Module ;
public int Index ;
}
2014-03-14 14:13:41 -04:00
/ * *
* Gets all of the modules referenced by this module
*
2015-06-09 11:50:55 -04:00
* @param ReferencedModules Hash of all referenced modules with their addition index .
2014-03-14 14:13:41 -04:00
* @param bIncludeDynamicallyLoaded True if dynamically loaded modules ( and all of their dependent modules ) should be included .
2014-07-31 09:34:11 -04:00
* @param bForceCircular True if circular dependencies should be processed
* @param bOnlyDirectDependencies True to return only this module ' s direct dependencies
2014-03-14 14:13:41 -04:00
* /
2015-06-09 11:50:55 -04:00
public virtual void GetAllDependencyModules ( CaselessDictionary < ModuleIndexPair > ReferencedModules , bool bIncludeDynamicallyLoaded , bool bForceCircular , bool bOnlyDirectDependencies )
2014-03-14 14:13:41 -04:00
{
}
2015-03-20 08:25:23 -04:00
/ * *
* Gets all of the modules precompiled along with this module
*
* @param Modules Set of all the precompiled modules
* /
public virtual void RecursivelyAddPrecompiledModules ( List < UEBuildModule > Modules )
{
}
2014-03-14 14:13:41 -04:00
/ * *
* Gathers and binds binaries for this module and all of it ' s dependent modules
* /
2015-04-11 13:09:16 -04:00
public virtual void RecursivelyProcessUnboundModules ( )
2014-03-14 14:13:41 -04:00
{
}
/ * *
2015-08-28 15:47:20 -04:00
* Creates all the modules required for this target
2014-03-14 14:13:41 -04:00
* /
2015-08-28 15:47:20 -04:00
public void RecursivelyCreateModules ( )
2014-03-14 14:13:41 -04:00
{
2015-08-28 15:47:20 -04:00
// Create all the include path modules. These modules may not be added to the target (and we don't process their dependencies), but they need
// to be created to set up their compile environment.
RecursivelyCreateIncludePathModulesByName ( Target , Rules . PublicIncludePathModuleNames , ref PublicIncludePathModules ) ;
RecursivelyCreateIncludePathModulesByName ( Target , Rules . PrivateIncludePathModuleNames , ref PrivateIncludePathModules ) ;
// Create all the dependency modules
RecursivelyCreateModulesByName ( Target , Rules . PublicDependencyModuleNames , ref PublicDependencyModules ) ;
RecursivelyCreateModulesByName ( Target , Rules . PrivateDependencyModuleNames , ref PrivateDependencyModules ) ;
RecursivelyCreateModulesByName ( Target , Rules . DynamicallyLoadedModuleNames , ref DynamicallyLoadedModules ) ;
RecursivelyCreateModulesByName ( Target , Rules . PlatformSpecificDynamicallyLoadedModuleNames , ref PlatformSpecificDynamicallyLoadedModules ) ;
}
private static void RecursivelyCreateModulesByName ( UEBuildTarget Target , List < string > ModuleNames , ref List < UEBuildModule > Modules )
{
// Check whether the module list is already set. We set this immediately (via the ref) to avoid infinite recursion.
if ( Modules = = null )
{
Modules = new List < UEBuildModule > ( ) ;
foreach ( string ModuleName in ModuleNames . Distinct ( StringComparer . InvariantCultureIgnoreCase ) )
{
UEBuildModule Module = Target . FindOrCreateModuleByName ( ModuleName ) ;
Module . RecursivelyCreateModules ( ) ;
Modules . Add ( Module ) ;
}
}
}
private static void RecursivelyCreateIncludePathModulesByName ( UEBuildTarget Target , List < string > ModuleNames , ref List < UEBuildModule > Modules )
{
// Check whether the module list is already set. We set this immediately (via the ref) to avoid infinite recursion.
if ( Modules = = null )
{
Modules = new List < UEBuildModule > ( ) ;
foreach ( string ModuleName in ModuleNames )
{
UEBuildModule Module = Target . FindOrCreateModuleByName ( ModuleName ) ;
RecursivelyCreateIncludePathModulesByName ( Target , Module . Rules . PublicIncludePathModuleNames , ref Module . PublicIncludePathModules ) ;
Modules . Add ( Module ) ;
}
}
2014-03-14 14:13:41 -04:00
}
} ;
/** A module that is never compiled by us, and is only used to group include paths and libraries into a dependency unit. */
class UEBuildExternalModule : UEBuildModule
{
public UEBuildExternalModule (
UEBuildTarget InTarget ,
UEBuildModuleType InType ,
string InName ,
string InModuleDirectory ,
2015-08-28 08:39:42 -04:00
ModuleRules InRules ,
2015-05-08 15:19:00 -04:00
string InBuildCsFilename
2014-03-14 14:13:41 -04:00
)
: base (
2015-05-08 15:19:00 -04:00
InTarget : InTarget ,
InType : InType ,
InName : InName ,
InModuleDirectory : InModuleDirectory ,
2015-08-28 08:39:42 -04:00
InRules : InRules ,
2015-05-08 15:19:00 -04:00
InBuildCsFilename : InBuildCsFilename
2014-03-14 14:13:41 -04:00
)
{
bIncludedInTarget = true ;
}
// UEBuildModule interface.
2015-04-10 11:19:40 -04:00
public override List < FileItem > Compile ( CPPEnvironment GlobalCompileEnvironment , CPPEnvironment CompileEnvironment )
2014-03-14 14:13:41 -04:00
{
return new List < FileItem > ( ) ;
}
} ;
2014-12-17 12:37:39 -05:00
/** A module that is compiled from C++ code. */
2014-03-14 14:13:41 -04:00
public class UEBuildModuleCPP : UEBuildModule
{
2014-04-28 04:53:09 -04:00
public class AutoGenerateCppInfoClass
2014-04-23 20:18:55 -04:00
{
2014-08-02 09:44:00 -04:00
public class BuildInfoClass
2014-04-23 20:18:55 -04:00
{
2014-09-22 09:46:58 -04:00
/** The wildcard of the *.generated.cpp file which was generated for the module */
public readonly string FileWildcard ;
2014-04-23 20:18:55 -04:00
2014-09-22 09:46:58 -04:00
public BuildInfoClass ( string InWildcard )
2014-08-02 09:44:00 -04:00
{
2014-09-22 09:46:58 -04:00
Debug . Assert ( InWildcard ! = null ) ;
2014-08-02 09:44:00 -04:00
2014-09-22 09:46:58 -04:00
FileWildcard = InWildcard ;
2014-08-02 09:44:00 -04:00
}
}
/** Information about how to build the .generated.cpp files. If this is null, then we're not building .generated.cpp files for this module. */
public BuildInfoClass BuildInfo ;
public AutoGenerateCppInfoClass ( BuildInfoClass InBuildInfo )
{
BuildInfo = InBuildInfo ;
2014-04-23 20:18:55 -04:00
}
}
2014-08-02 09:44:00 -04:00
/** Information about the .generated.cpp file. If this is null then this module doesn't have any UHT-produced code. */
2014-04-28 04:53:09 -04:00
public AutoGenerateCppInfoClass AutoGenerateCppInfo = null ;
2014-04-23 20:18:55 -04:00
2014-04-28 04:53:09 -04:00
public class SourceFilesClass
2014-04-23 20:18:55 -04:00
{
public readonly List < FileItem > MissingFiles = new List < FileItem > ( ) ;
public readonly List < FileItem > CPPFiles = new List < FileItem > ( ) ;
public readonly List < FileItem > CFiles = new List < FileItem > ( ) ;
public readonly List < FileItem > CCFiles = new List < FileItem > ( ) ;
public readonly List < FileItem > MMFiles = new List < FileItem > ( ) ;
public readonly List < FileItem > RCFiles = new List < FileItem > ( ) ;
public readonly List < FileItem > OtherFiles = new List < FileItem > ( ) ;
2014-04-28 04:53:09 -04:00
public int Count
{
get
{
return MissingFiles . Count +
CPPFiles . Count +
CFiles . Count +
CCFiles . Count +
MMFiles . Count +
RCFiles . Count +
OtherFiles . Count ;
}
}
2015-05-14 08:05:11 -04:00
/// <summary>
/// Copy from list to list helper.
/// </summary>
/// <param name="From">Source list.</param>
/// <param name="To">Destination list.</param>
private static void CopyFromListToList ( List < FileItem > From , List < FileItem > To )
{
To . Clear ( ) ;
To . AddRange ( From ) ;
}
/// <summary>
/// Copies file lists from other SourceFilesClass to this.
/// </summary>
/// <param name="Other">Source object.</param>
public void CopyFrom ( SourceFilesClass Other )
{
CopyFromListToList ( Other . MissingFiles , MissingFiles ) ;
CopyFromListToList ( Other . CPPFiles , CPPFiles ) ;
CopyFromListToList ( Other . CFiles , CFiles ) ;
CopyFromListToList ( Other . CCFiles , CCFiles ) ;
CopyFromListToList ( Other . MMFiles , MMFiles ) ;
CopyFromListToList ( Other . RCFiles , RCFiles ) ;
CopyFromListToList ( Other . OtherFiles , OtherFiles ) ;
}
2014-04-23 20:18:55 -04:00
}
2014-10-30 10:07:51 -04:00
/ * *
* Adds additional source cpp files for this module .
*
* @param Files Files to add .
* /
public void AddAdditionalCPPFiles ( IEnumerable < FileItem > Files )
{
SourceFilesToBuild . CPPFiles . AddRange ( Files ) ;
}
2014-05-29 16:51:44 -04:00
/** A list of the absolute paths of source files to be built in this module. */
public readonly SourceFilesClass SourceFilesToBuild = new SourceFilesClass ( ) ;
2015-05-14 08:05:11 -04:00
/** A list of the source files that were found for the module. */
public readonly SourceFilesClass SourceFilesFound = new SourceFilesClass ( ) ;
2015-04-20 18:05:25 -04:00
/** The directory for this module's generated code */
public readonly string GeneratedCodeDirectory ;
2014-03-14 14:13:41 -04:00
/** The preprocessor definitions used to compile this module's private implementation. */
2014-09-11 03:21:51 -04:00
HashSet < string > Definitions ;
2014-03-14 14:13:41 -04:00
/// When set, allows this module to report compiler definitions and include paths for Intellisense
IntelliSenseGatherer IntelliSenseGatherer ;
2014-12-04 05:35:51 -05:00
public List < string > IncludeSearchPaths = new List < string > ( ) ;
2014-04-23 20:18:55 -04:00
public class ProcessedDependenciesClass
{
/** The file, if any, which is used as the unique PCH for this module */
public FileItem UniquePCHHeaderFile = null ;
}
2014-03-14 14:13:41 -04:00
2014-04-23 20:18:55 -04:00
/** The processed dependencies for the class */
public ProcessedDependenciesClass ProcessedDependencies = null ;
2014-03-14 14:13:41 -04:00
2014-12-17 12:37:39 -05:00
/** @hack to skip adding definitions to compile environment. They will be baked into source code by external code. */
public bool bSkipDefinitionsForCompileEnvironment = false ;
2014-05-29 16:51:44 -04:00
/** Categorizes source files into per-extension buckets */
private static void CategorizeSourceFiles ( IEnumerable < FileItem > InSourceFiles , SourceFilesClass OutSourceFiles )
{
foreach ( var SourceFile in InSourceFiles )
{
string Extension = Path . GetExtension ( SourceFile . AbsolutePath ) . ToUpperInvariant ( ) ;
if ( ! SourceFile . bExists )
{
OutSourceFiles . MissingFiles . Add ( SourceFile ) ;
}
else if ( Extension = = ".CPP" )
{
OutSourceFiles . CPPFiles . Add ( SourceFile ) ;
}
else if ( Extension = = ".C" )
{
OutSourceFiles . CFiles . Add ( SourceFile ) ;
}
else if ( Extension = = ".CC" )
{
OutSourceFiles . CCFiles . Add ( SourceFile ) ;
}
else if ( Extension = = ".MM" | | Extension = = ".M" )
{
OutSourceFiles . MMFiles . Add ( SourceFile ) ;
}
else if ( Extension = = ".RC" )
{
OutSourceFiles . RCFiles . Add ( SourceFile ) ;
}
else
{
OutSourceFiles . OtherFiles . Add ( SourceFile ) ;
}
}
}
2014-03-14 14:13:41 -04:00
public UEBuildModuleCPP (
UEBuildTarget InTarget ,
string InName ,
UEBuildModuleType InType ,
string InModuleDirectory ,
2015-04-20 18:05:25 -04:00
string InGeneratedCodeDirectory ,
2014-03-14 14:13:41 -04:00
IntelliSenseGatherer InIntelliSenseGatherer ,
IEnumerable < FileItem > InSourceFiles ,
2015-08-28 08:39:42 -04:00
ModuleRules InRules ,
2015-05-08 15:19:00 -04:00
bool bInBuildSourceFiles ,
2015-08-28 08:39:42 -04:00
string InBuildCsFilename
2014-03-14 14:13:41 -04:00
)
: base ( InTarget ,
InName ,
InType ,
InModuleDirectory ,
2015-08-28 08:39:42 -04:00
InRules ,
2015-05-08 15:19:00 -04:00
InBuildCsFilename
2014-03-14 14:13:41 -04:00
)
{
2015-04-20 18:05:25 -04:00
GeneratedCodeDirectory = InGeneratedCodeDirectory ;
2014-03-14 14:13:41 -04:00
IntelliSenseGatherer = InIntelliSenseGatherer ;
2014-04-23 20:18:55 -04:00
2015-05-14 08:05:11 -04:00
CategorizeSourceFiles ( InSourceFiles , SourceFilesFound ) ;
2014-05-29 16:51:44 -04:00
if ( bInBuildSourceFiles )
2014-04-23 20:18:55 -04:00
{
2015-05-14 08:05:11 -04:00
SourceFilesToBuild . CopyFrom ( SourceFilesFound ) ;
2014-04-23 20:18:55 -04:00
}
2015-08-28 08:39:42 -04:00
Definitions = HashSetFromOptionalEnumerableStringParameter ( InRules . Definitions ) ;
2014-03-14 14:13:41 -04:00
foreach ( var Def in Definitions )
{
Log . TraceVerbose ( "Compile Env {0}: {1}" , Name , Def ) ;
}
}
// UEBuildModule interface.
2015-04-10 11:19:40 -04:00
public override List < FileItem > Compile ( CPPEnvironment GlobalCompileEnvironment , CPPEnvironment CompileEnvironment )
2014-03-14 14:13:41 -04:00
{
2014-06-09 11:12:01 -04:00
var BuildPlatform = UEBuildPlatform . GetBuildPlatformForCPPTargetPlatform ( CompileEnvironment . Config . Target . Platform ) ;
2014-03-14 14:13:41 -04:00
var LinkInputFiles = new List < FileItem > ( ) ;
if ( ProjectFileGenerator . bGenerateProjectFiles & & IntelliSenseGatherer = = null )
{
// Nothing to do for IntelliSense, bail out early
return LinkInputFiles ;
}
2014-04-23 20:18:55 -04:00
var ModuleCompileEnvironment = CreateModuleCompileEnvironment ( CompileEnvironment ) ;
2014-12-04 05:35:51 -05:00
IncludeSearchPaths = ModuleCompileEnvironment . Config . CPPIncludeInfo . IncludePaths . ToList ( ) ;
IncludeSearchPaths . AddRange ( ModuleCompileEnvironment . Config . CPPIncludeInfo . SystemIncludePaths . ToList ( ) ) ;
2014-03-14 14:13:41 -04:00
if ( IntelliSenseGatherer ! = null )
{
// Update project file's set of preprocessor definitions and include paths
IntelliSenseGatherer . AddIntelliSensePreprocessorDefinitions ( ModuleCompileEnvironment . Config . Definitions ) ;
Experimental UnrealBuildTool makefile support
UnrealBuildTool 'Makefiles' allow for very fast iterative builds.
- New BuildConfiguration.xml setting added: "bUseExperimentalFastBuildIteration" (disabled by default)
- Turning this on causes Unreal Build Tool to emit 'UBT Makefiles' for targets when they're built the first time.
- Subsequent builds will load these Makefiles and begin outdatedness checking and build invocation very quickly.
- The caveat is that if source files are added or removed to the project, UBT will need to gather information about those in order for your build to complete successfully.
- Currently, you must run the project file generator after adding/removing source files to tell UBT to re-gather this information.
- Events that can invalidate the 'UBT Makefile':
- Adding/removing .cpp files
- Adding/removing .h files with UObjects
- Adding new UObject types to a file that didn't previously have any
- Changing global build settings (most settings in this file qualify.)
- Changed code that affects how Unreal Header Tool works
- You can force regeneration of the 'UBT Makefile' by passing the '-Gather' argument, or simply regenerating project files
- New command-line parameters added:
- "-Gather": Tells UBT to always perform the gather step (slower but will catch project structural changes)
- "-NoGather": Disables the gather step, unless UBT detects that it must be done. This is the default when bUseExperimentalFastBuildIteration is enabled
- "-GatherOnly": Runs the gather step and saves a UBTMakefile, but doesn't build anything
- "-Assemble": Tells UBT to also assemble build products. This always defaults to enabled
- "-NoAssemble": Tells UBT to skip the assemble step, whether we gathered build products or not
- "-AssembleOnly": Tells UBT to only assemble build products and not to gather, unless UBT determines it must
Other changes:
- UBT now keeps track of which targets it was building in an intermediate file, to help it invalidate cached includes in subsequent runs when the targets are different
- C++ includes are now stored in a class separate from the C++ compile enviroment (for easier serialization)
- The method that UBT uses to find the CoreUObject module timestamp was rewritten
- Various '@todo ubtmake' comments added to tag possible remaining Makefile tasks
- The 'FileItem' class had some member variable comments and code cleaned up, while making it serializable
- Cleaned up the comments and member variables in the "Action" class, while making it serializable
- Some UBT classes are now "serializable". This is because we need to store the data in UBTMakefiles.
- Removed support for Actions to tinker with Stdout and Stderror (was not used for anything)
- Moved PrecompileHeaderEnvironment class to the UEBuildModule.cs source file
- Plugin intermediate include directories are now selected on demand rather than cached early
- Toolchain code for gathering prerequisite headers is now shared in a single function (AddPrerequisiteSourceFile)
- Removed Action.StatusDetailedDescription, was not used for anything
- Removed UEBuildConfiguration.bExcludePlugins, was not used for anything
- Removed ECompilationResult.FailedDueToHeaderChange, was not used for anything
[CL 2254472 by Mike Fricker in Main branch]
2014-08-13 08:17:43 -04:00
IntelliSenseGatherer . AddInteliiSenseIncludePaths ( ModuleCompileEnvironment . Config . CPPIncludeInfo . SystemIncludePaths , bAddingSystemIncludes : true ) ;
IntelliSenseGatherer . AddInteliiSenseIncludePaths ( ModuleCompileEnvironment . Config . CPPIncludeInfo . IncludePaths , bAddingSystemIncludes : false ) ;
2014-03-14 14:13:41 -04:00
// Bail out. We don't need to actually compile anything while generating project files.
return LinkInputFiles ;
}
2014-04-23 20:18:55 -04:00
// Throw an error if the module's source file list referenced any non-existent files.
2014-05-29 16:51:44 -04:00
if ( SourceFilesToBuild . MissingFiles . Count > 0 )
2014-03-14 14:13:41 -04:00
{
2014-04-23 20:18:55 -04:00
throw new BuildException (
"UBT ERROR: Module \"{0}\" references non-existent files:\n{1} (perhaps a file was added to the project but not checked in)" ,
Name ,
2014-05-29 16:51:44 -04:00
string . Join ( "\n" , SourceFilesToBuild . MissingFiles . Select ( M = > M . AbsolutePath ) )
2014-04-23 20:18:55 -04:00
) ;
2014-03-14 14:13:41 -04:00
}
// For an executable or a static library do not use the default RC file -
// If the executable wants it, it will be in their source list anyway.
// The issue here is that when making a monolithic game, the processing
// of the other game modules will stomp the game-specific rc file.
if ( Binary . Config . Type = = UEBuildBinaryType . DynamicLinkLibrary )
{
// Add default PCLaunch.rc file if this module has no own resource file specified
2014-05-29 16:51:44 -04:00
if ( SourceFilesToBuild . RCFiles . Count < = 0 )
2014-03-14 14:13:41 -04:00
{
2014-07-31 09:34:11 -04:00
string DefRC = Utils . CleanDirectorySeparators ( Path . GetFullPath ( Path . Combine ( Directory . GetCurrentDirectory ( ) , "Runtime/Launch/Resources/Windows/PCLaunch.rc" ) ) ) ;
2014-03-14 14:13:41 -04:00
FileItem Item = FileItem . GetItemByFullPath ( DefRC ) ;
2014-05-29 16:51:44 -04:00
SourceFilesToBuild . RCFiles . Add ( Item ) ;
2014-03-14 14:13:41 -04:00
}
2014-06-20 13:02:34 -04:00
// Always compile in the API version resource separately. This is required for the module manager to detect compatible API versions.
2014-07-31 09:34:11 -04:00
string ModuleVersionRC = Utils . CleanDirectorySeparators ( Path . GetFullPath ( Path . Combine ( Directory . GetCurrentDirectory ( ) , "Runtime/Core/Resources/Windows/ModuleVersionResource.rc.inl" ) ) ) ;
2014-06-20 13:02:34 -04:00
FileItem ModuleVersionItem = FileItem . GetItemByFullPath ( ModuleVersionRC ) ;
2014-07-31 09:34:11 -04:00
if ( ! SourceFilesToBuild . RCFiles . Contains ( ModuleVersionItem ) )
{
SourceFilesToBuild . RCFiles . Add ( ModuleVersionItem ) ;
}
2014-03-14 14:13:41 -04:00
}
2014-07-31 09:34:11 -04:00
{
// Process all of the header file dependencies for this module
this . CachePCHUsageForModuleSourceFiles ( ModuleCompileEnvironment ) ;
// Make sure our RC files have cached includes.
foreach ( var RCFile in SourceFilesToBuild . RCFiles )
{
Experimental UnrealBuildTool makefile support
UnrealBuildTool 'Makefiles' allow for very fast iterative builds.
- New BuildConfiguration.xml setting added: "bUseExperimentalFastBuildIteration" (disabled by default)
- Turning this on causes Unreal Build Tool to emit 'UBT Makefiles' for targets when they're built the first time.
- Subsequent builds will load these Makefiles and begin outdatedness checking and build invocation very quickly.
- The caveat is that if source files are added or removed to the project, UBT will need to gather information about those in order for your build to complete successfully.
- Currently, you must run the project file generator after adding/removing source files to tell UBT to re-gather this information.
- Events that can invalidate the 'UBT Makefile':
- Adding/removing .cpp files
- Adding/removing .h files with UObjects
- Adding new UObject types to a file that didn't previously have any
- Changing global build settings (most settings in this file qualify.)
- Changed code that affects how Unreal Header Tool works
- You can force regeneration of the 'UBT Makefile' by passing the '-Gather' argument, or simply regenerating project files
- New command-line parameters added:
- "-Gather": Tells UBT to always perform the gather step (slower but will catch project structural changes)
- "-NoGather": Disables the gather step, unless UBT detects that it must be done. This is the default when bUseExperimentalFastBuildIteration is enabled
- "-GatherOnly": Runs the gather step and saves a UBTMakefile, but doesn't build anything
- "-Assemble": Tells UBT to also assemble build products. This always defaults to enabled
- "-NoAssemble": Tells UBT to skip the assemble step, whether we gathered build products or not
- "-AssembleOnly": Tells UBT to only assemble build products and not to gather, unless UBT determines it must
Other changes:
- UBT now keeps track of which targets it was building in an intermediate file, to help it invalidate cached includes in subsequent runs when the targets are different
- C++ includes are now stored in a class separate from the C++ compile enviroment (for easier serialization)
- The method that UBT uses to find the CoreUObject module timestamp was rewritten
- Various '@todo ubtmake' comments added to tag possible remaining Makefile tasks
- The 'FileItem' class had some member variable comments and code cleaned up, while making it serializable
- Cleaned up the comments and member variables in the "Action" class, while making it serializable
- Some UBT classes are now "serializable". This is because we need to store the data in UBTMakefiles.
- Removed support for Actions to tinker with Stdout and Stderror (was not used for anything)
- Moved PrecompileHeaderEnvironment class to the UEBuildModule.cs source file
- Plugin intermediate include directories are now selected on demand rather than cached early
- Toolchain code for gathering prerequisite headers is now shared in a single function (AddPrerequisiteSourceFile)
- Removed Action.StatusDetailedDescription, was not used for anything
- Removed UEBuildConfiguration.bExcludePlugins, was not used for anything
- Removed ECompilationResult.FailedDueToHeaderChange, was not used for anything
[CL 2254472 by Mike Fricker in Main branch]
2014-08-13 08:17:43 -04:00
RCFile . CachedCPPIncludeInfo = ModuleCompileEnvironment . Config . CPPIncludeInfo ;
2014-07-31 09:34:11 -04:00
}
}
2014-03-14 14:13:41 -04:00
// Check to see if this is an Engine module (including program or plugin modules). That is, the module is located under the "Engine" folder
2015-08-07 13:58:49 -04:00
var IsPluginModule = Utils . IsFileUnderDirectory ( this . ModuleDirectory , Path . Combine ( Target . ProjectDirectory , "Plugins" ) ) ;
var IsGameModule = ! IsPluginModule & & ! Utils . IsFileUnderDirectory ( this . ModuleDirectory , Path . Combine ( ProjectFileGenerator . EngineRelativePath ) ) ;
2014-03-14 14:13:41 -04:00
// Should we force a precompiled header to be generated for this module? Usually, we only bother with a
// precompiled header if there are at least several source files in the module (after combining them for unity
// builds.) But for game modules, it can be convenient to always have a precompiled header to single-file
// changes to code is really quick to compile.
int MinFilesUsingPrecompiledHeader = BuildConfiguration . MinFilesUsingPrecompiledHeader ;
2015-08-28 08:39:42 -04:00
if ( Rules . MinFilesUsingPrecompiledHeaderOverride ! = 0 )
2014-03-14 14:13:41 -04:00
{
2015-08-28 08:39:42 -04:00
MinFilesUsingPrecompiledHeader = Rules . MinFilesUsingPrecompiledHeaderOverride ;
2014-03-14 14:13:41 -04:00
}
else if ( IsGameModule & & BuildConfiguration . bForcePrecompiledHeaderForGameModules )
{
// This is a game module with only a small number of source files, so go ahead and force a precompiled header
// to be generated to make incremental changes to source files as fast as possible for small projects.
MinFilesUsingPrecompiledHeader = 1 ;
}
2015-08-07 13:58:49 -04:00
// Engine modules will always use unity build mode unless MinSourceFilesForUnityBuildOverride is specified in
// the module rules file. By default, game modules only use unity of they have enough source files for that
// to be worthwhile. If you have a lot of small game modules, consider specifying MinSourceFilesForUnityBuildOverride=0
// in the modules that you don't typically iterate on source files in very frequently.
int MinSourceFilesForUnityBuild = 0 ;
2015-08-28 08:39:42 -04:00
if ( Rules . MinSourceFilesForUnityBuildOverride ! = 0 )
2014-03-14 14:13:41 -04:00
{
2015-08-28 08:39:42 -04:00
MinSourceFilesForUnityBuild = Rules . MinSourceFilesForUnityBuildOverride ;
2015-08-07 13:58:49 -04:00
}
else if ( IsGameModule )
{
// Game modules with only a small number of source files are usually better off having faster iteration times
// on single source file changes, so we forcibly disable unity build for those modules
MinSourceFilesForUnityBuild = BuildConfiguration . MinGameModuleSourceFilesForUnityBuild ;
}
// Should we use unity build mode for this module?
bool bModuleUsesUnityBuild = false ;
if ( BuildConfiguration . bUseUnityBuild | | BuildConfiguration . bForceUnityBuild )
{
if ( BuildConfiguration . bForceUnityBuild )
2014-11-04 05:27:19 -05:00
{
2015-08-07 13:58:49 -04:00
Log . TraceVerbose ( "Module '{0}' using unity build mode (bForceUnityBuild enabled for this module)" , this . Name ) ;
bModuleUsesUnityBuild = true ;
}
2015-08-28 08:39:42 -04:00
else if ( Rules . bFasterWithoutUnity )
2015-08-07 13:58:49 -04:00
{
Log . TraceVerbose ( "Module '{0}' not using unity build mode (bFasterWithoutUnity enabled for this module)" , this . Name ) ;
2014-11-04 05:27:19 -05:00
bModuleUsesUnityBuild = false ;
}
2015-08-07 13:58:49 -04:00
else if ( SourceFilesToBuild . CPPFiles . Count < MinSourceFilesForUnityBuild )
2014-11-04 05:27:19 -05:00
{
2015-08-07 13:58:49 -04:00
Log . TraceVerbose ( "Module '{0}' not using unity build mode (module with fewer than {1} source files)" , this . Name , MinSourceFilesForUnityBuild ) ;
2014-11-04 05:27:19 -05:00
bModuleUsesUnityBuild = false ;
}
2015-08-07 13:58:49 -04:00
else
{
Log . TraceVerbose ( "Module '{0}' using unity build mode (enabled in BuildConfiguration)" , this . Name ) ;
bModuleUsesUnityBuild = true ;
}
}
else
{
Log . TraceVerbose ( "Module '{0}' not using unity build mode (disabled in BuildConfiguration)" , this . Name ) ;
2014-03-14 14:13:41 -04:00
}
2014-04-24 15:04:34 -04:00
// The environment with which to compile the CPP files
var CPPCompileEnvironment = ModuleCompileEnvironment ;
2014-03-14 14:13:41 -04:00
// Precompiled header support.
bool bWasModuleCodeCompiled = false ;
2014-06-09 11:12:01 -04:00
if ( BuildPlatform . ShouldUsePCHFiles ( CompileEnvironment . Config . Target . Platform , CompileEnvironment . Config . Target . Configuration ) )
2014-03-14 14:13:41 -04:00
{
2014-07-31 09:34:11 -04:00
var PCHGenTimerStart = DateTime . UtcNow ;
2014-03-14 14:13:41 -04:00
// The code below will figure out whether this module will either use a "unique PCH" (private PCH that will only be included by
// this module's code files), or a "shared PCH" (potentially included by many code files in many modules.) Only one or the other
// will be used.
FileItem SharedPCHHeaderFile = null ;
// In the case of a shared PCH, we also need to keep track of which module that PCH's header file is a member of
string SharedPCHModuleName = String . Empty ;
2015-04-10 11:19:40 -04:00
if ( BuildConfiguration . bUseSharedPCHs & & CompileEnvironment . Config . bIsBuildingLibrary )
2014-03-14 14:13:41 -04:00
{
2015-04-10 11:19:40 -04:00
Log . TraceVerbose ( "Module '{0}' was not allowed to use Shared PCHs, because we're compiling to a library" , this . Name ) ;
2014-03-14 14:13:41 -04:00
}
2015-04-10 11:19:40 -04:00
bool bUseSharedPCHFiles = BuildConfiguration . bUseSharedPCHs & & ! CompileEnvironment . Config . bIsBuildingLibrary & & GlobalCompileEnvironment . SharedPCHHeaderFiles . Count > 0 ;
2014-03-14 14:13:41 -04:00
2014-07-31 09:34:11 -04:00
if ( bUseSharedPCHFiles )
2014-07-16 12:13:57 -04:00
{
2014-07-31 09:34:11 -04:00
string SharingPCHHeaderFilePath = null ;
bool bIsASharedPCHModule = bUseSharedPCHFiles & & GlobalCompileEnvironment . SharedPCHHeaderFiles . Any ( PCH = > PCH . Module = = this ) ;
if ( bIsASharedPCHModule )
2014-06-04 08:05:42 -04:00
{
2015-08-28 08:39:42 -04:00
SharingPCHHeaderFilePath = Path . GetFullPath ( Path . Combine ( ProjectFileGenerator . RootRelativePath , "Engine" , "Source" , Rules . SharedPCHHeaderFile ) ) ;
2014-06-04 08:05:42 -04:00
}
2014-07-16 12:13:57 -04:00
2015-04-10 11:19:40 -04:00
// We can't use a shared PCH file when compiling a module
2014-07-31 09:34:11 -04:00
// with exports, because the shared PCH can only have imports in it to work correctly.
2015-08-28 08:39:42 -04:00
bool bAllowSharedPCH = ( Rules . PCHUsage = = ModuleRules . PCHUsageMode . NoSharedPCHs ) ? false : true ;
2015-04-10 11:19:40 -04:00
bool bCanModuleUseOwnSharedPCH = bAllowSharedPCH & & bIsASharedPCHModule & & ! Binary . Config . bAllowExports & & ProcessedDependencies . UniquePCHHeaderFile . AbsolutePath . Equals ( SharingPCHHeaderFilePath , StringComparison . InvariantCultureIgnoreCase ) ;
2014-07-31 09:34:11 -04:00
if ( bAllowSharedPCH & & ( ! bIsASharedPCHModule | | bCanModuleUseOwnSharedPCH ) )
2014-07-16 12:13:57 -04:00
{
2014-07-31 09:34:11 -04:00
// Figure out which shared PCH tier we're in
2015-06-09 11:50:55 -04:00
var ReferencedModules = new CaselessDictionary < ModuleIndexPair > ( ) ;
{
this . GetAllDependencyModules ( ReferencedModules , bIncludeDynamicallyLoaded : false , bForceCircular : false , bOnlyDirectDependencies : true ) ;
2014-07-31 09:34:11 -04:00
}
2014-07-16 12:13:57 -04:00
2014-07-31 09:34:11 -04:00
int LargestSharedPCHHeaderFileIndex = - 1 ;
2015-06-09 11:50:55 -04:00
foreach ( var DependencyModule in ReferencedModules . Values . OrderBy ( P = > P . Index ) . Select ( P = > P . Module ) )
2014-03-14 14:13:41 -04:00
{
2014-07-31 09:34:11 -04:00
// These Shared PCHs are ordered from least complex to most complex. We'll start at the last one and search backwards.
for ( var SharedPCHHeaderFileIndex = GlobalCompileEnvironment . SharedPCHHeaderFiles . Count - 1 ; SharedPCHHeaderFileIndex > LargestSharedPCHHeaderFileIndex ; - - SharedPCHHeaderFileIndex )
2014-03-14 14:13:41 -04:00
{
2014-07-31 09:34:11 -04:00
var CurSharedPCHHeaderFile = GlobalCompileEnvironment . SharedPCHHeaderFiles [ SharedPCHHeaderFileIndex ] ;
2014-03-14 14:13:41 -04:00
2014-07-31 09:34:11 -04:00
if ( DependencyModule = = CurSharedPCHHeaderFile . Module | |
( bIsASharedPCHModule & & CurSharedPCHHeaderFile . Module = = this ) ) // If we ourselves are a shared PCH module, always at least use our own module as our shared PCH header if we can't find anything better
{
SharedPCHModuleName = CurSharedPCHHeaderFile . Module . Name ;
SharedPCHHeaderFile = CurSharedPCHHeaderFile . PCHHeaderFile ;
LargestSharedPCHHeaderFileIndex = SharedPCHHeaderFileIndex ;
break ;
2014-03-14 14:13:41 -04:00
}
}
2014-07-31 09:34:11 -04:00
if ( LargestSharedPCHHeaderFileIndex = = GlobalCompileEnvironment . SharedPCHHeaderFiles . Count - 1 )
2014-03-14 14:13:41 -04:00
{
2014-07-31 09:34:11 -04:00
// We've determined that the module is using our most complex PCH header, so we can early-out
break ;
2014-03-14 14:13:41 -04:00
}
}
2014-07-31 09:34:11 -04:00
// Did we not find a shared PCH header that is being included by this module? This could happen if the module is not including Core.h, even indirectly.
if ( String . IsNullOrEmpty ( SharedPCHModuleName ) )
2014-03-14 14:13:41 -04:00
{
2014-07-31 09:34:11 -04:00
throw new BuildException ( "Module {0} doesn't use a Shared PCH! Please add a dependency on a Shared PCH module to this module's dependency list" , this . Name ) ;
2014-03-14 14:13:41 -04:00
}
2014-12-17 09:40:26 -05:00
// Keep track of how many modules make use of this PCH for performance diagnostics
var LargestSharedPCHHeader = GlobalCompileEnvironment . SharedPCHHeaderFiles [ LargestSharedPCHHeaderFileIndex ] ;
+ + LargestSharedPCHHeader . NumModulesUsingThisPCH ;
2014-03-14 14:13:41 -04:00
}
2014-07-31 09:34:11 -04:00
else
2014-03-14 14:13:41 -04:00
{
2014-07-31 09:34:11 -04:00
Log . TraceVerbose ( "Module '{0}' cannot create or use Shared PCHs, because it needs its own private PCH" , this . Name ) ;
2014-03-14 14:13:41 -04:00
}
}
2014-04-23 20:18:55 -04:00
// The precompiled header environment for all source files in this module that use a precompiled header, if we even need one
PrecompileHeaderEnvironment ModulePCHEnvironment = null ;
2014-03-14 14:13:41 -04:00
// If there was one header that was included first by enough C++ files, use it as the precompiled header.
// Only use precompiled headers for projects with enough files to make the PCH creation worthwhile.
2014-05-29 16:51:44 -04:00
if ( SharedPCHHeaderFile ! = null | | SourceFilesToBuild . CPPFiles . Count > = MinFilesUsingPrecompiledHeader )
2014-03-14 14:13:41 -04:00
{
2014-04-24 15:04:34 -04:00
FileItem PCHToUse ;
2014-03-14 14:13:41 -04:00
if ( SharedPCHHeaderFile ! = null )
{
2014-05-29 16:51:44 -04:00
ModulePCHEnvironment = ApplySharedPCH ( GlobalCompileEnvironment , CompileEnvironment , ModuleCompileEnvironment , SourceFilesToBuild . CPPFiles , ref SharedPCHHeaderFile ) ;
2014-04-23 20:18:55 -04:00
if ( ModulePCHEnvironment ! = null )
2014-03-14 14:13:41 -04:00
{
2014-04-23 20:18:55 -04:00
// @todo SharedPCH: Ideally we would exhaustively check for a compatible compile environment (definitions, imports/exports, etc)
// Currently, it's possible for the shared PCH to be compiled differently depending on which module UBT happened to have
2014-07-31 09:34:11 -04:00
// include it first during the build phase. This could create problems with deterministic builds, or turn up compile
2014-04-23 20:18:55 -04:00
// errors unexpectedly due to compile environment differences.
2014-07-16 12:13:57 -04:00
Log . TraceVerbose ( "Module " + Name + " uses existing Shared PCH '" + ModulePCHEnvironment . PrecompiledHeaderIncludeFilename + "' (from module " + ModulePCHEnvironment . ModuleName + ")" ) ;
2014-04-23 20:18:55 -04:00
}
2014-04-24 15:04:34 -04:00
PCHToUse = SharedPCHHeaderFile ;
}
else
{
PCHToUse = ProcessedDependencies . UniquePCHHeaderFile ;
}
if ( PCHToUse ! = null )
{
// Update all CPPFiles to point to the PCH
2014-05-29 16:51:44 -04:00
foreach ( var CPPFile in SourceFilesToBuild . CPPFiles )
2014-04-23 20:18:55 -04:00
{
2014-04-24 15:04:34 -04:00
CPPFile . PCHHeaderNameInCode = PCHToUse . AbsolutePath ;
CPPFile . PrecompiledHeaderIncludeFilename = PCHToUse . AbsolutePath ;
2014-03-14 14:13:41 -04:00
}
}
// A shared PCH was not already set up for us, so set one up.
if ( ModulePCHEnvironment = = null )
{
2014-04-23 20:18:55 -04:00
var PCHHeaderFile = ProcessedDependencies . UniquePCHHeaderFile ;
2014-03-14 14:13:41 -04:00
var PCHModuleName = this . Name ;
if ( SharedPCHHeaderFile ! = null )
{
PCHHeaderFile = SharedPCHHeaderFile ;
PCHModuleName = SharedPCHModuleName ;
}
2014-05-29 16:51:44 -04:00
var PCHHeaderNameInCode = SourceFilesToBuild . CPPFiles [ 0 ] . PCHHeaderNameInCode ;
2014-03-14 14:13:41 -04:00
ModulePCHEnvironment = new PrecompileHeaderEnvironment ( PCHModuleName , PCHHeaderNameInCode , PCHHeaderFile , ModuleCompileEnvironment . Config . CLRMode , ModuleCompileEnvironment . Config . OptimizeCode ) ;
if ( SharedPCHHeaderFile ! = null )
{
// Add to list of shared PCH environments
GlobalCompileEnvironment . SharedPCHEnvironments . Add ( ModulePCHEnvironment ) ;
2014-07-16 12:13:57 -04:00
Log . TraceVerbose ( "Module " + Name + " uses new Shared PCH '" + ModulePCHEnvironment . PrecompiledHeaderIncludeFilename + "'" ) ;
2014-03-14 14:13:41 -04:00
}
else
{
2014-07-16 12:13:57 -04:00
Log . TraceVerbose ( "Module " + Name + " uses a Unique PCH '" + ModulePCHEnvironment . PrecompiledHeaderIncludeFilename + "'" ) ;
2014-03-14 14:13:41 -04:00
}
}
}
2014-07-16 12:13:57 -04:00
else
{
Log . TraceVerbose ( "Module " + Name + " doesn't use a Shared PCH, and only has " + SourceFilesToBuild . CPPFiles . Count . ToString ( ) + " source file(s). No Unique PCH will be generated." ) ;
}
2014-03-14 14:13:41 -04:00
// Compile the C++ source or the unity C++ files that use a PCH environment.
if ( ModulePCHEnvironment ! = null )
{
// Setup a new compile environment for this module's source files. It's pretty much the exact same as the
// module's compile environment, except that it will include a PCH file.
2014-05-22 04:16:41 -04:00
var ModulePCHCompileEnvironment = ModuleCompileEnvironment . DeepCopy ( ) ;
2014-04-23 20:18:55 -04:00
ModulePCHCompileEnvironment . Config . PrecompiledHeaderAction = PrecompiledHeaderAction . Include ;
ModulePCHCompileEnvironment . Config . PrecompiledHeaderIncludeFilename = ModulePCHEnvironment . PrecompiledHeaderIncludeFilename . AbsolutePath ;
ModulePCHCompileEnvironment . Config . PCHHeaderNameInCode = ModulePCHEnvironment . PCHHeaderNameInCode ;
2014-03-14 14:13:41 -04:00
2014-04-23 20:18:55 -04:00
if ( SharedPCHHeaderFile ! = null )
{
// Shared PCH headers need to be force included, because we're basically forcing the module to use
// the precompiled header that we want, instead of the "first include" in each respective .cpp file
ModulePCHCompileEnvironment . Config . bForceIncludePrecompiledHeader = true ;
2014-03-14 14:13:41 -04:00
}
2014-05-29 16:51:44 -04:00
var CPPFilesToBuild = SourceFilesToBuild . CPPFiles ;
2014-03-14 14:13:41 -04:00
if ( bModuleUsesUnityBuild )
{
// unity files generated for only the set of files which share the same PCH environment
2014-07-31 09:34:11 -04:00
CPPFilesToBuild = Unity . GenerateUnityCPPs ( Target , CPPFilesToBuild , ModulePCHCompileEnvironment , Name ) ;
2014-03-14 14:13:41 -04:00
}
// Check if there are enough unity files to warrant pch generation (and we haven't already generated the shared one)
2014-07-16 12:13:57 -04:00
if ( ModulePCHEnvironment . PrecompiledHeaderFile = = null )
2014-03-14 14:13:41 -04:00
{
2014-07-16 12:13:57 -04:00
if ( SharedPCHHeaderFile ! = null | | CPPFilesToBuild . Count > = MinFilesUsingPrecompiledHeader )
2014-03-14 14:13:41 -04:00
{
2015-05-13 07:52:34 -04:00
CPPOutput PCHOutput ;
if ( SharedPCHHeaderFile = = null )
2014-07-16 12:13:57 -04:00
{
2015-05-13 07:52:34 -04:00
PCHOutput = PrecompileHeaderEnvironment . GeneratePCHCreationAction (
Target ,
CPPFilesToBuild [ 0 ] . PCHHeaderNameInCode ,
ModulePCHEnvironment . PrecompiledHeaderIncludeFilename ,
ModuleCompileEnvironment ,
ModuleCompileEnvironment . Config . OutputDirectory ,
Name ,
true ) ;
}
else
{
UEBuildModuleCPP SharedPCHModule = ( UEBuildModuleCPP ) Target . FindOrCreateModuleByName ( SharedPCHModuleName ) ;
2014-03-14 14:13:41 -04:00
2015-05-13 07:52:34 -04:00
CPPEnvironment SharedPCHCompileEnvironment = GlobalCompileEnvironment . DeepCopy ( ) ;
2015-08-28 08:39:42 -04:00
SharedPCHCompileEnvironment . Config . bEnableShadowVariableWarning = SharedPCHModule . Rules . bEnableShadowVariableWarnings ;
2014-03-14 14:13:41 -04:00
2015-05-13 07:52:34 -04:00
SharedPCHModule . SetupPublicCompileEnvironment (
Binary ,
false ,
SharedPCHCompileEnvironment . Config . CPPIncludeInfo . IncludePaths ,
SharedPCHCompileEnvironment . Config . CPPIncludeInfo . SystemIncludePaths ,
SharedPCHCompileEnvironment . Config . Definitions ,
SharedPCHCompileEnvironment . Config . AdditionalFrameworks ,
new Dictionary < UEBuildModule , bool > ( ) ) ;
PCHOutput = PrecompileHeaderEnvironment . GeneratePCHCreationAction (
Target ,
CPPFilesToBuild [ 0 ] . PCHHeaderNameInCode ,
ModulePCHEnvironment . PrecompiledHeaderIncludeFilename ,
SharedPCHCompileEnvironment ,
Path . Combine ( CompileEnvironment . Config . OutputDirectory , "SharedPCHs" ) ,
"Shared" ,
false ) ;
2014-07-16 12:13:57 -04:00
}
ModulePCHEnvironment . PrecompiledHeaderFile = PCHOutput . PrecompiledHeaderFile ;
2014-03-14 14:13:41 -04:00
2014-07-16 12:13:57 -04:00
ModulePCHEnvironment . OutputObjectFiles . Clear ( ) ;
ModulePCHEnvironment . OutputObjectFiles . AddRange ( PCHOutput . ObjectFiles ) ;
}
else if ( CPPFilesToBuild . Count < MinFilesUsingPrecompiledHeader )
{
Log . TraceVerbose ( "Module " + Name + " doesn't use a Shared PCH, and only has " + CPPFilesToBuild . Count . ToString ( ) + " unity source file(s). No Unique PCH will be generated." ) ;
}
2014-03-14 14:13:41 -04:00
}
if ( ModulePCHEnvironment . PrecompiledHeaderFile ! = null )
{
// Link in the object files produced by creating the precompiled header.
LinkInputFiles . AddRange ( ModulePCHEnvironment . OutputObjectFiles ) ;
// if pch action was generated for the environment then use pch
ModulePCHCompileEnvironment . PrecompiledHeaderFile = ModulePCHEnvironment . PrecompiledHeaderFile ;
2014-04-24 15:04:34 -04:00
// Use this compile environment from now on
CPPCompileEnvironment = ModulePCHCompileEnvironment ;
2014-03-14 14:13:41 -04:00
}
2014-04-24 15:04:34 -04:00
2014-07-31 09:34:11 -04:00
LinkInputFiles . AddRange ( CPPCompileEnvironment . CompileFiles ( Target , CPPFilesToBuild , Name ) . ObjectFiles ) ;
2014-03-14 14:13:41 -04:00
bWasModuleCodeCompiled = true ;
}
if ( BuildConfiguration . bPrintPerformanceInfo )
{
2014-07-31 09:34:11 -04:00
var PCHGenTime = ( DateTime . UtcNow - PCHGenTimerStart ) . TotalSeconds ;
TotalPCHGenTime + = PCHGenTime ;
2014-03-14 14:13:41 -04:00
}
}
2014-05-29 16:51:44 -04:00
if ( ! bWasModuleCodeCompiled & & SourceFilesToBuild . CPPFiles . Count > 0 )
2014-03-14 14:13:41 -04:00
{
2014-05-29 16:51:44 -04:00
var CPPFilesToCompile = SourceFilesToBuild . CPPFiles ;
2014-04-23 20:18:55 -04:00
if ( bModuleUsesUnityBuild )
2014-03-14 14:13:41 -04:00
{
2014-07-31 09:34:11 -04:00
CPPFilesToCompile = Unity . GenerateUnityCPPs ( Target , CPPFilesToCompile , CPPCompileEnvironment , Name ) ;
2014-03-14 14:13:41 -04:00
}
2014-07-31 09:34:11 -04:00
LinkInputFiles . AddRange ( CPPCompileEnvironment . CompileFiles ( Target , CPPFilesToCompile , Name ) . ObjectFiles ) ;
2014-04-23 20:18:55 -04:00
}
2014-08-02 09:44:00 -04:00
if ( AutoGenerateCppInfo ! = null & & AutoGenerateCppInfo . BuildInfo ! = null & & ! CPPCompileEnvironment . bHackHeaderGenerator )
2014-04-23 20:18:55 -04:00
{
2014-09-22 09:46:58 -04:00
string [ ] GeneratedFiles = Directory . GetFiles ( Path . GetDirectoryName ( AutoGenerateCppInfo . BuildInfo . FileWildcard ) , Path . GetFileName ( AutoGenerateCppInfo . BuildInfo . FileWildcard ) ) ;
foreach ( string GeneratedFilename in GeneratedFiles )
{
var GeneratedCppFileItem = FileItem . GetItemByPath ( GeneratedFilename ) ;
2014-04-23 20:18:55 -04:00
2014-09-22 09:46:58 -04:00
CachePCHUsageForModuleSourceFile ( this . Target , CPPCompileEnvironment , GeneratedCppFileItem ) ;
2014-07-31 09:34:11 -04:00
2015-01-07 14:16:46 -05:00
// @todo ubtmake: Check for ALL other places where we might be injecting .cpp or .rc files for compiling without caching CachedCPPIncludeInfo first (anything platform specific?)
2014-09-22 09:46:58 -04:00
LinkInputFiles . AddRange ( CPPCompileEnvironment . CompileFiles ( Target , new List < FileItem > { GeneratedCppFileItem } , Name ) . ObjectFiles ) ;
}
2014-03-14 14:13:41 -04:00
}
// Compile C files directly.
2014-07-31 09:34:11 -04:00
LinkInputFiles . AddRange ( CPPCompileEnvironment . CompileFiles ( Target , SourceFilesToBuild . CFiles , Name ) . ObjectFiles ) ;
2014-03-14 14:13:41 -04:00
// Compile CC files directly.
2014-07-31 09:34:11 -04:00
LinkInputFiles . AddRange ( CPPCompileEnvironment . CompileFiles ( Target , SourceFilesToBuild . CCFiles , Name ) . ObjectFiles ) ;
2014-03-14 14:13:41 -04:00
// Compile MM files directly.
2014-07-31 09:34:11 -04:00
LinkInputFiles . AddRange ( CPPCompileEnvironment . CompileFiles ( Target , SourceFilesToBuild . MMFiles , Name ) . ObjectFiles ) ;
2014-03-14 14:13:41 -04:00
// Compile RC files.
2014-07-31 09:34:11 -04:00
LinkInputFiles . AddRange ( CPPCompileEnvironment . CompileRCFiles ( Target , SourceFilesToBuild . RCFiles ) . ObjectFiles ) ;
2014-03-14 14:13:41 -04:00
2014-04-23 20:18:55 -04:00
return LinkInputFiles ;
}
2014-04-24 15:04:34 -04:00
private PrecompileHeaderEnvironment ApplySharedPCH ( CPPEnvironment GlobalCompileEnvironment , CPPEnvironment CompileEnvironment , CPPEnvironment ModuleCompileEnvironment , List < FileItem > CPPFiles , ref FileItem SharedPCHHeaderFile )
2014-04-23 20:18:55 -04:00
{
// Check to see if we have a PCH header already setup that we can use
2014-04-24 15:04:34 -04:00
var SharedPCHHeaderFileCopy = SharedPCHHeaderFile ;
var SharedPCHEnvironment = GlobalCompileEnvironment . SharedPCHEnvironments . Find ( Env = > Env . PrecompiledHeaderIncludeFilename = = SharedPCHHeaderFileCopy ) ;
2014-04-23 20:18:55 -04:00
if ( SharedPCHEnvironment = = null )
2014-07-31 09:34:11 -04:00
{
2014-04-23 20:18:55 -04:00
return null ;
2014-07-31 09:34:11 -04:00
}
2014-04-23 20:18:55 -04:00
// Don't mix CLR modes
if ( SharedPCHEnvironment . CLRMode ! = ModuleCompileEnvironment . Config . CLRMode )
2014-03-14 14:13:41 -04:00
{
2014-07-16 12:13:57 -04:00
Log . TraceVerbose ( "Module {0} cannot use existing Shared PCH '{1}' (from module '{2}') because CLR modes don't match" , Name , SharedPCHEnvironment . PrecompiledHeaderIncludeFilename . AbsolutePath , SharedPCHEnvironment . ModuleName ) ;
2014-04-24 15:04:34 -04:00
SharedPCHHeaderFile = null ;
2014-04-23 20:18:55 -04:00
return null ;
}
2014-12-15 11:34:00 -05:00
// Don't mix RTTI modes
2015-08-28 08:39:42 -04:00
if ( Rules . bUseRTTI )
2014-12-15 11:34:00 -05:00
{
Log . TraceVerbose ( "Module {0} cannot use existing Shared PCH '{1}' (from module '{2}') because RTTI modes don't match" , Name , SharedPCHEnvironment . PrecompiledHeaderIncludeFilename . AbsolutePath , SharedPCHEnvironment . ModuleName ) ;
SharedPCHHeaderFile = null ;
return null ;
}
2014-04-23 20:18:55 -04:00
// Don't mix non-optimized code with optimized code (PCHs won't be compatible)
var SharedPCHCodeOptimization = SharedPCHEnvironment . OptimizeCode ;
var ModuleCodeOptimization = ModuleCompileEnvironment . Config . OptimizeCode ;
2014-06-09 11:12:01 -04:00
if ( CompileEnvironment . Config . Target . Configuration ! = CPPTargetConfiguration . Debug )
2014-04-23 20:18:55 -04:00
{
if ( SharedPCHCodeOptimization = = ModuleRules . CodeOptimization . InNonDebugBuilds )
2014-03-14 14:13:41 -04:00
{
2014-04-23 20:18:55 -04:00
SharedPCHCodeOptimization = ModuleRules . CodeOptimization . Always ;
}
2014-03-14 14:13:41 -04:00
2014-04-23 20:18:55 -04:00
if ( ModuleCodeOptimization = = ModuleRules . CodeOptimization . InNonDebugBuilds )
{
ModuleCodeOptimization = ModuleRules . CodeOptimization . Always ;
2014-03-14 14:13:41 -04:00
}
}
2014-04-23 20:18:55 -04:00
if ( SharedPCHCodeOptimization ! = ModuleCodeOptimization )
{
2014-07-16 12:13:57 -04:00
Log . TraceVerbose ( "Module {0} cannot use existing Shared PCH '{1}' (from module '{2}') because optimization levels don't match" , Name , SharedPCHEnvironment . PrecompiledHeaderIncludeFilename . AbsolutePath , SharedPCHEnvironment . ModuleName ) ;
2014-04-24 15:04:34 -04:00
SharedPCHHeaderFile = null ;
2014-04-23 20:18:55 -04:00
return null ;
}
return SharedPCHEnvironment ;
}
2014-07-31 09:34:11 -04:00
public static FileItem CachePCHUsageForModuleSourceFile ( UEBuildTarget Target , CPPEnvironment ModuleCompileEnvironment , FileItem CPPFile )
{
2014-08-19 08:19:14 -04:00
if ( ! CPPFile . bExists )
{
throw new BuildException ( "Required source file not found: " + CPPFile . AbsolutePath ) ;
}
2014-07-31 09:34:11 -04:00
var PCHCacheTimerStart = DateTime . UtcNow ;
var BuildPlatform = UEBuildPlatform . GetBuildPlatformForCPPTargetPlatform ( ModuleCompileEnvironment . Config . Target . Platform ) ;
Experimental UnrealBuildTool makefile support
UnrealBuildTool 'Makefiles' allow for very fast iterative builds.
- New BuildConfiguration.xml setting added: "bUseExperimentalFastBuildIteration" (disabled by default)
- Turning this on causes Unreal Build Tool to emit 'UBT Makefiles' for targets when they're built the first time.
- Subsequent builds will load these Makefiles and begin outdatedness checking and build invocation very quickly.
- The caveat is that if source files are added or removed to the project, UBT will need to gather information about those in order for your build to complete successfully.
- Currently, you must run the project file generator after adding/removing source files to tell UBT to re-gather this information.
- Events that can invalidate the 'UBT Makefile':
- Adding/removing .cpp files
- Adding/removing .h files with UObjects
- Adding new UObject types to a file that didn't previously have any
- Changing global build settings (most settings in this file qualify.)
- Changed code that affects how Unreal Header Tool works
- You can force regeneration of the 'UBT Makefile' by passing the '-Gather' argument, or simply regenerating project files
- New command-line parameters added:
- "-Gather": Tells UBT to always perform the gather step (slower but will catch project structural changes)
- "-NoGather": Disables the gather step, unless UBT detects that it must be done. This is the default when bUseExperimentalFastBuildIteration is enabled
- "-GatherOnly": Runs the gather step and saves a UBTMakefile, but doesn't build anything
- "-Assemble": Tells UBT to also assemble build products. This always defaults to enabled
- "-NoAssemble": Tells UBT to skip the assemble step, whether we gathered build products or not
- "-AssembleOnly": Tells UBT to only assemble build products and not to gather, unless UBT determines it must
Other changes:
- UBT now keeps track of which targets it was building in an intermediate file, to help it invalidate cached includes in subsequent runs when the targets are different
- C++ includes are now stored in a class separate from the C++ compile enviroment (for easier serialization)
- The method that UBT uses to find the CoreUObject module timestamp was rewritten
- Various '@todo ubtmake' comments added to tag possible remaining Makefile tasks
- The 'FileItem' class had some member variable comments and code cleaned up, while making it serializable
- Cleaned up the comments and member variables in the "Action" class, while making it serializable
- Some UBT classes are now "serializable". This is because we need to store the data in UBTMakefiles.
- Removed support for Actions to tinker with Stdout and Stderror (was not used for anything)
- Moved PrecompileHeaderEnvironment class to the UEBuildModule.cs source file
- Plugin intermediate include directories are now selected on demand rather than cached early
- Toolchain code for gathering prerequisite headers is now shared in a single function (AddPrerequisiteSourceFile)
- Removed Action.StatusDetailedDescription, was not used for anything
- Removed UEBuildConfiguration.bExcludePlugins, was not used for anything
- Removed ECompilationResult.FailedDueToHeaderChange, was not used for anything
[CL 2254472 by Mike Fricker in Main branch]
2014-08-13 08:17:43 -04:00
var IncludePathsToSearch = ModuleCompileEnvironment . Config . CPPIncludeInfo . GetIncludesPathsToSearch ( CPPFile ) ;
2014-07-31 09:34:11 -04:00
// Store the module compile environment along with the .cpp file. This is so that we can use it later on when looking
// for header dependencies
Experimental UnrealBuildTool makefile support
UnrealBuildTool 'Makefiles' allow for very fast iterative builds.
- New BuildConfiguration.xml setting added: "bUseExperimentalFastBuildIteration" (disabled by default)
- Turning this on causes Unreal Build Tool to emit 'UBT Makefiles' for targets when they're built the first time.
- Subsequent builds will load these Makefiles and begin outdatedness checking and build invocation very quickly.
- The caveat is that if source files are added or removed to the project, UBT will need to gather information about those in order for your build to complete successfully.
- Currently, you must run the project file generator after adding/removing source files to tell UBT to re-gather this information.
- Events that can invalidate the 'UBT Makefile':
- Adding/removing .cpp files
- Adding/removing .h files with UObjects
- Adding new UObject types to a file that didn't previously have any
- Changing global build settings (most settings in this file qualify.)
- Changed code that affects how Unreal Header Tool works
- You can force regeneration of the 'UBT Makefile' by passing the '-Gather' argument, or simply regenerating project files
- New command-line parameters added:
- "-Gather": Tells UBT to always perform the gather step (slower but will catch project structural changes)
- "-NoGather": Disables the gather step, unless UBT detects that it must be done. This is the default when bUseExperimentalFastBuildIteration is enabled
- "-GatherOnly": Runs the gather step and saves a UBTMakefile, but doesn't build anything
- "-Assemble": Tells UBT to also assemble build products. This always defaults to enabled
- "-NoAssemble": Tells UBT to skip the assemble step, whether we gathered build products or not
- "-AssembleOnly": Tells UBT to only assemble build products and not to gather, unless UBT determines it must
Other changes:
- UBT now keeps track of which targets it was building in an intermediate file, to help it invalidate cached includes in subsequent runs when the targets are different
- C++ includes are now stored in a class separate from the C++ compile enviroment (for easier serialization)
- The method that UBT uses to find the CoreUObject module timestamp was rewritten
- Various '@todo ubtmake' comments added to tag possible remaining Makefile tasks
- The 'FileItem' class had some member variable comments and code cleaned up, while making it serializable
- Cleaned up the comments and member variables in the "Action" class, while making it serializable
- Some UBT classes are now "serializable". This is because we need to store the data in UBTMakefiles.
- Removed support for Actions to tinker with Stdout and Stderror (was not used for anything)
- Moved PrecompileHeaderEnvironment class to the UEBuildModule.cs source file
- Plugin intermediate include directories are now selected on demand rather than cached early
- Toolchain code for gathering prerequisite headers is now shared in a single function (AddPrerequisiteSourceFile)
- Removed Action.StatusDetailedDescription, was not used for anything
- Removed UEBuildConfiguration.bExcludePlugins, was not used for anything
- Removed ECompilationResult.FailedDueToHeaderChange, was not used for anything
[CL 2254472 by Mike Fricker in Main branch]
2014-08-13 08:17:43 -04:00
CPPFile . CachedCPPIncludeInfo = ModuleCompileEnvironment . Config . CPPIncludeInfo ;
2014-07-31 09:34:11 -04:00
Experimental UnrealBuildTool makefile support
UnrealBuildTool 'Makefiles' allow for very fast iterative builds.
- New BuildConfiguration.xml setting added: "bUseExperimentalFastBuildIteration" (disabled by default)
- Turning this on causes Unreal Build Tool to emit 'UBT Makefiles' for targets when they're built the first time.
- Subsequent builds will load these Makefiles and begin outdatedness checking and build invocation very quickly.
- The caveat is that if source files are added or removed to the project, UBT will need to gather information about those in order for your build to complete successfully.
- Currently, you must run the project file generator after adding/removing source files to tell UBT to re-gather this information.
- Events that can invalidate the 'UBT Makefile':
- Adding/removing .cpp files
- Adding/removing .h files with UObjects
- Adding new UObject types to a file that didn't previously have any
- Changing global build settings (most settings in this file qualify.)
- Changed code that affects how Unreal Header Tool works
- You can force regeneration of the 'UBT Makefile' by passing the '-Gather' argument, or simply regenerating project files
- New command-line parameters added:
- "-Gather": Tells UBT to always perform the gather step (slower but will catch project structural changes)
- "-NoGather": Disables the gather step, unless UBT detects that it must be done. This is the default when bUseExperimentalFastBuildIteration is enabled
- "-GatherOnly": Runs the gather step and saves a UBTMakefile, but doesn't build anything
- "-Assemble": Tells UBT to also assemble build products. This always defaults to enabled
- "-NoAssemble": Tells UBT to skip the assemble step, whether we gathered build products or not
- "-AssembleOnly": Tells UBT to only assemble build products and not to gather, unless UBT determines it must
Other changes:
- UBT now keeps track of which targets it was building in an intermediate file, to help it invalidate cached includes in subsequent runs when the targets are different
- C++ includes are now stored in a class separate from the C++ compile enviroment (for easier serialization)
- The method that UBT uses to find the CoreUObject module timestamp was rewritten
- Various '@todo ubtmake' comments added to tag possible remaining Makefile tasks
- The 'FileItem' class had some member variable comments and code cleaned up, while making it serializable
- Cleaned up the comments and member variables in the "Action" class, while making it serializable
- Some UBT classes are now "serializable". This is because we need to store the data in UBTMakefiles.
- Removed support for Actions to tinker with Stdout and Stderror (was not used for anything)
- Moved PrecompileHeaderEnvironment class to the UEBuildModule.cs source file
- Plugin intermediate include directories are now selected on demand rather than cached early
- Toolchain code for gathering prerequisite headers is now shared in a single function (AddPrerequisiteSourceFile)
- Removed Action.StatusDetailedDescription, was not used for anything
- Removed UEBuildConfiguration.bExcludePlugins, was not used for anything
- Removed ECompilationResult.FailedDueToHeaderChange, was not used for anything
[CL 2254472 by Mike Fricker in Main branch]
2014-08-13 08:17:43 -04:00
var PCHFile = CachePCHUsageForCPPFile ( Target , CPPFile , BuildPlatform , IncludePathsToSearch , ModuleCompileEnvironment . Config . CPPIncludeInfo . IncludeFileSearchDictionary ) ;
2014-07-31 09:34:11 -04:00
if ( BuildConfiguration . bPrintPerformanceInfo )
{
var PCHCacheTime = ( DateTime . UtcNow - PCHCacheTimerStart ) . TotalSeconds ;
TotalPCHCacheTime + = PCHCacheTime ;
}
return PCHFile ;
}
public void CachePCHUsageForModuleSourceFiles ( CPPEnvironment ModuleCompileEnvironment )
2014-04-23 20:18:55 -04:00
{
2014-07-18 14:20:08 -04:00
if ( ProcessedDependencies = = null )
2014-04-23 20:18:55 -04:00
{
2014-07-31 09:34:11 -04:00
var PCHCacheTimerStart = DateTime . UtcNow ;
var BuildPlatform = UEBuildPlatform . GetBuildPlatformForCPPTargetPlatform ( ModuleCompileEnvironment . Config . Target . Platform ) ;
bool bFoundAProblemWithPCHs = false ;
2014-07-18 14:20:08 -04:00
FileItem UniquePCH = null ;
2015-05-14 08:05:11 -04:00
foreach ( var CPPFile in SourceFilesFound . CPPFiles ) // @todo ubtmake: We're not caching CPPEnvironments for .c/.mm files, etc. Even though they don't use PCHs, they still have #includes! This can break dependency checking!
2014-07-18 14:20:08 -04:00
{
2014-07-31 09:34:11 -04:00
// Build a single list of include paths to search.
2015-01-07 14:16:46 -05:00
var IncludePathsToSearch = ModuleCompileEnvironment . Config . CPPIncludeInfo . GetIncludesPathsToSearch ( CPPFile ) ;
2014-07-31 09:34:11 -04:00
// Store the module compile environment along with the .cpp file. This is so that we can use it later on when looking
// for header dependencies
Experimental UnrealBuildTool makefile support
UnrealBuildTool 'Makefiles' allow for very fast iterative builds.
- New BuildConfiguration.xml setting added: "bUseExperimentalFastBuildIteration" (disabled by default)
- Turning this on causes Unreal Build Tool to emit 'UBT Makefiles' for targets when they're built the first time.
- Subsequent builds will load these Makefiles and begin outdatedness checking and build invocation very quickly.
- The caveat is that if source files are added or removed to the project, UBT will need to gather information about those in order for your build to complete successfully.
- Currently, you must run the project file generator after adding/removing source files to tell UBT to re-gather this information.
- Events that can invalidate the 'UBT Makefile':
- Adding/removing .cpp files
- Adding/removing .h files with UObjects
- Adding new UObject types to a file that didn't previously have any
- Changing global build settings (most settings in this file qualify.)
- Changed code that affects how Unreal Header Tool works
- You can force regeneration of the 'UBT Makefile' by passing the '-Gather' argument, or simply regenerating project files
- New command-line parameters added:
- "-Gather": Tells UBT to always perform the gather step (slower but will catch project structural changes)
- "-NoGather": Disables the gather step, unless UBT detects that it must be done. This is the default when bUseExperimentalFastBuildIteration is enabled
- "-GatherOnly": Runs the gather step and saves a UBTMakefile, but doesn't build anything
- "-Assemble": Tells UBT to also assemble build products. This always defaults to enabled
- "-NoAssemble": Tells UBT to skip the assemble step, whether we gathered build products or not
- "-AssembleOnly": Tells UBT to only assemble build products and not to gather, unless UBT determines it must
Other changes:
- UBT now keeps track of which targets it was building in an intermediate file, to help it invalidate cached includes in subsequent runs when the targets are different
- C++ includes are now stored in a class separate from the C++ compile enviroment (for easier serialization)
- The method that UBT uses to find the CoreUObject module timestamp was rewritten
- Various '@todo ubtmake' comments added to tag possible remaining Makefile tasks
- The 'FileItem' class had some member variable comments and code cleaned up, while making it serializable
- Cleaned up the comments and member variables in the "Action" class, while making it serializable
- Some UBT classes are now "serializable". This is because we need to store the data in UBTMakefiles.
- Removed support for Actions to tinker with Stdout and Stderror (was not used for anything)
- Moved PrecompileHeaderEnvironment class to the UEBuildModule.cs source file
- Plugin intermediate include directories are now selected on demand rather than cached early
- Toolchain code for gathering prerequisite headers is now shared in a single function (AddPrerequisiteSourceFile)
- Removed Action.StatusDetailedDescription, was not used for anything
- Removed UEBuildConfiguration.bExcludePlugins, was not used for anything
- Removed ECompilationResult.FailedDueToHeaderChange, was not used for anything
[CL 2254472 by Mike Fricker in Main branch]
2014-08-13 08:17:43 -04:00
CPPFile . CachedCPPIncludeInfo = ModuleCompileEnvironment . Config . CPPIncludeInfo ;
2014-07-31 09:34:11 -04:00
2014-07-18 14:20:08 -04:00
// Find headers used by the source file.
Experimental UnrealBuildTool makefile support
UnrealBuildTool 'Makefiles' allow for very fast iterative builds.
- New BuildConfiguration.xml setting added: "bUseExperimentalFastBuildIteration" (disabled by default)
- Turning this on causes Unreal Build Tool to emit 'UBT Makefiles' for targets when they're built the first time.
- Subsequent builds will load these Makefiles and begin outdatedness checking and build invocation very quickly.
- The caveat is that if source files are added or removed to the project, UBT will need to gather information about those in order for your build to complete successfully.
- Currently, you must run the project file generator after adding/removing source files to tell UBT to re-gather this information.
- Events that can invalidate the 'UBT Makefile':
- Adding/removing .cpp files
- Adding/removing .h files with UObjects
- Adding new UObject types to a file that didn't previously have any
- Changing global build settings (most settings in this file qualify.)
- Changed code that affects how Unreal Header Tool works
- You can force regeneration of the 'UBT Makefile' by passing the '-Gather' argument, or simply regenerating project files
- New command-line parameters added:
- "-Gather": Tells UBT to always perform the gather step (slower but will catch project structural changes)
- "-NoGather": Disables the gather step, unless UBT detects that it must be done. This is the default when bUseExperimentalFastBuildIteration is enabled
- "-GatherOnly": Runs the gather step and saves a UBTMakefile, but doesn't build anything
- "-Assemble": Tells UBT to also assemble build products. This always defaults to enabled
- "-NoAssemble": Tells UBT to skip the assemble step, whether we gathered build products or not
- "-AssembleOnly": Tells UBT to only assemble build products and not to gather, unless UBT determines it must
Other changes:
- UBT now keeps track of which targets it was building in an intermediate file, to help it invalidate cached includes in subsequent runs when the targets are different
- C++ includes are now stored in a class separate from the C++ compile enviroment (for easier serialization)
- The method that UBT uses to find the CoreUObject module timestamp was rewritten
- Various '@todo ubtmake' comments added to tag possible remaining Makefile tasks
- The 'FileItem' class had some member variable comments and code cleaned up, while making it serializable
- Cleaned up the comments and member variables in the "Action" class, while making it serializable
- Some UBT classes are now "serializable". This is because we need to store the data in UBTMakefiles.
- Removed support for Actions to tinker with Stdout and Stderror (was not used for anything)
- Moved PrecompileHeaderEnvironment class to the UEBuildModule.cs source file
- Plugin intermediate include directories are now selected on demand rather than cached early
- Toolchain code for gathering prerequisite headers is now shared in a single function (AddPrerequisiteSourceFile)
- Removed Action.StatusDetailedDescription, was not used for anything
- Removed UEBuildConfiguration.bExcludePlugins, was not used for anything
- Removed ECompilationResult.FailedDueToHeaderChange, was not used for anything
[CL 2254472 by Mike Fricker in Main branch]
2014-08-13 08:17:43 -04:00
var PCH = UEBuildModuleCPP . CachePCHUsageForCPPFile ( Target , CPPFile , BuildPlatform , IncludePathsToSearch , ModuleCompileEnvironment . Config . CPPIncludeInfo . IncludeFileSearchDictionary ) ;
2014-07-31 09:34:11 -04:00
if ( PCH = = null )
{
throw new BuildException ( "Source file \"{0}\" is not including any headers. We expect all modules to include a header file for precompiled header generation. Please add an #include statement." , CPPFile . AbsolutePath ) ;
}
if ( UniquePCH = = null )
{
UniquePCH = PCH ;
}
2015-01-07 14:16:46 -05:00
else if ( ! UniquePCH . Info . Name . Equals ( PCH . Info . Name , StringComparison . InvariantCultureIgnoreCase ) ) // @todo ubtmake: We do a string compare on the file name (not path) here, because sometimes the include resolver will pick an Intermediate copy of a PCH header file and throw off our comparisons
2014-07-31 09:34:11 -04:00
{
// OK, looks like we have multiple source files including a different header file first. We'll keep track of this and print out
// helpful information afterwards.
bFoundAProblemWithPCHs = true ;
}
2014-07-18 14:20:08 -04:00
}
2014-04-23 20:18:55 -04:00
2014-07-18 14:20:08 -04:00
ProcessedDependencies = new ProcessedDependenciesClass { UniquePCHHeaderFile = UniquePCH } ;
2014-07-31 09:34:11 -04:00
if ( bFoundAProblemWithPCHs )
{
// Map from pch header string to the source files that use that PCH
var UsageMapPCH = new Dictionary < string , List < FileItem > > ( StringComparer . InvariantCultureIgnoreCase ) ;
2015-01-07 14:16:46 -05:00
foreach ( var CPPFile in SourceFilesToBuild . CPPFiles )
2014-07-31 09:34:11 -04:00
{
// Create a new entry if not in the pch usage map
UsageMapPCH . GetOrAddNew ( CPPFile . PrecompiledHeaderIncludeFilename ) . Add ( CPPFile ) ;
}
if ( BuildConfiguration . bPrintDebugInfo )
{
Log . TraceVerbose ( "{0} PCH files for module {1}:" , UsageMapPCH . Count , Name ) ;
int MostFilesIncluded = 0 ;
foreach ( var CurPCH in UsageMapPCH )
{
if ( CurPCH . Value . Count > MostFilesIncluded )
{
MostFilesIncluded = CurPCH . Value . Count ;
}
Log . TraceVerbose ( " {0} ({1} files including it: {2}, ...)" , CurPCH . Key , CurPCH . Value . Count , CurPCH . Value [ 0 ] . AbsolutePath ) ;
}
}
if ( UsageMapPCH . Count > 1 )
{
// Keep track of the PCH file that is most used within this module
string MostFilesAreIncludingPCH = string . Empty ;
int MostFilesIncluded = 0 ;
foreach ( var CurPCH in UsageMapPCH . Where ( PCH = > PCH . Value . Count > MostFilesIncluded ) )
{
MostFilesAreIncludingPCH = CurPCH . Key ;
MostFilesIncluded = CurPCH . Value . Count ;
}
// Find all of the files that are not including our "best" PCH header
var FilesNotIncludingBestPCH = new StringBuilder ( ) ;
foreach ( var CurPCH in UsageMapPCH . Where ( PCH = > PCH . Key ! = MostFilesAreIncludingPCH ) )
{
foreach ( var SourceFile in CurPCH . Value )
{
FilesNotIncludingBestPCH . AppendFormat ( "{0} (including {1})\n" , SourceFile . AbsolutePath , CurPCH . Key ) ;
}
}
// Bail out and let the user know which source files may need to be fixed up
throw new BuildException (
"All source files in module \"{0}\" must include the same precompiled header first. Currently \"{1}\" is included by most of the source files. The following source files are not including \"{1}\" as their first include:\n\n{2}" ,
Name ,
MostFilesAreIncludingPCH ,
FilesNotIncludingBestPCH ) ;
}
}
if ( BuildConfiguration . bPrintPerformanceInfo )
{
var PCHCacheTime = ( DateTime . UtcNow - PCHCacheTimerStart ) . TotalSeconds ;
TotalPCHCacheTime + = PCHCacheTime ;
}
2014-07-18 14:20:08 -04:00
}
2014-04-23 20:18:55 -04:00
}
2014-07-31 09:34:11 -04:00
private static FileItem CachePCHUsageForCPPFile ( UEBuildTarget Target , FileItem CPPFile , IUEBuildPlatform BuildPlatform , List < string > IncludePathsToSearch , Dictionary < string , FileItem > IncludeFileSearchDictionary )
2014-04-23 20:18:55 -04:00
{
2015-01-07 14:16:46 -05:00
// @todo ubtmake: We don't really need to scan every file looking for PCH headers, just need one. The rest is just for error checking.
// @todo ubtmake: We don't need all of the direct includes either. We just need the first, unless we want to check for errors.
2015-06-09 11:50:55 -04:00
List < DependencyInclude > DirectIncludeFilenames = CPPEnvironment . GetDirectIncludeDependencies ( Target , CPPFile , BuildPlatform , bOnlyCachedDependencies : false ) ;
2014-04-23 20:18:55 -04:00
if ( BuildConfiguration . bPrintDebugInfo )
{
Log . TraceVerbose ( "Found direct includes for {0}: {1}" , Path . GetFileName ( CPPFile . AbsolutePath ) , string . Join ( ", " , DirectIncludeFilenames . Select ( F = > F . IncludeName ) ) ) ;
}
if ( DirectIncludeFilenames . Count = = 0 )
2014-07-18 14:20:08 -04:00
{
2014-04-23 20:18:55 -04:00
return null ;
2014-07-18 14:20:08 -04:00
}
2014-04-23 20:18:55 -04:00
var FirstInclude = DirectIncludeFilenames [ 0 ] ;
// The pch header should always be the first include in the source file.
// NOTE: This is not an absolute path. This is just the literal include string from the source file!
CPPFile . PCHHeaderNameInCode = FirstInclude . IncludeName ;
// Resolve the PCH header to an absolute path.
// Check NullOrEmpty here because if the file could not be resolved we need to throw an exception
if ( ! string . IsNullOrEmpty ( FirstInclude . IncludeResolvedName ) & &
// ignore any preexisting resolve cache if we are not configured to use it.
BuildConfiguration . bUseIncludeDependencyResolveCache & &
// if we are testing the resolve cache, we force UBT to resolve every time to look for conflicts
! BuildConfiguration . bTestIncludeDependencyResolveCache )
{
CPPFile . PrecompiledHeaderIncludeFilename = FirstInclude . IncludeResolvedName ;
return FileItem . GetItemByFullPath ( CPPFile . PrecompiledHeaderIncludeFilename ) ;
}
// search the include paths to resolve the file.
2014-07-31 09:34:11 -04:00
FileItem PrecompiledHeaderIncludeFile = CPPEnvironment . FindIncludedFile ( CPPFile . PCHHeaderNameInCode , ! BuildConfiguration . bCheckExternalHeadersForModification , IncludePathsToSearch , IncludeFileSearchDictionary ) ;
2014-04-23 20:18:55 -04:00
if ( PrecompiledHeaderIncludeFile = = null )
2014-07-18 16:34:12 -04:00
{
2014-07-31 09:34:11 -04:00
throw new BuildException ( "The first include statement in source file '{0}' is trying to include the file '{1}' as the precompiled header, but that file could not be located in any of the module's include search paths." , CPPFile . AbsolutePath , CPPFile . PCHHeaderNameInCode ) ;
2014-07-18 16:34:12 -04:00
}
2014-04-23 20:18:55 -04:00
2014-07-31 09:34:11 -04:00
CPPEnvironment . IncludeDependencyCache [ Target ] . CacheResolvedIncludeFullPath ( CPPFile , 0 , PrecompiledHeaderIncludeFile . AbsolutePath ) ;
2014-04-23 20:18:55 -04:00
CPPFile . PrecompiledHeaderIncludeFilename = PrecompiledHeaderIncludeFile . AbsolutePath ;
return PrecompiledHeaderIncludeFile ;
}
/// <summary>
/// Creates a compile environment from a base environment based on the module settings.
/// </summary>
/// <param name="BaseCompileEnvironment">An existing environment to base the module compile environment on.</param>
/// <returns>The new module compile environment.</returns>
public CPPEnvironment CreateModuleCompileEnvironment ( CPPEnvironment BaseCompileEnvironment )
{
2014-05-22 04:16:41 -04:00
var Result = BaseCompileEnvironment . DeepCopy ( ) ;
2014-04-23 20:18:55 -04:00
// Override compile environment
2015-08-28 08:39:42 -04:00
Result . Config . bFasterWithoutUnity = Rules . bFasterWithoutUnity ;
Result . Config . OptimizeCode = Rules . OptimizeCode ;
Result . Config . bUseRTTI = Rules . bUseRTTI ;
Result . Config . bUseAVX = Rules . bUseAVX ;
Result . Config . bEnableBufferSecurityChecks = Rules . bEnableBufferSecurityChecks ;
Result . Config . MinSourceFilesForUnityBuildOverride = Rules . MinSourceFilesForUnityBuildOverride ;
Result . Config . MinFilesUsingPrecompiledHeaderOverride = Rules . MinFilesUsingPrecompiledHeaderOverride ;
Result . Config . bBuildLocallyWithSNDBS = Rules . bBuildLocallyWithSNDBS ;
Result . Config . bEnableExceptions = Rules . bEnableExceptions ;
Result . Config . bEnableShadowVariableWarning = Rules . bEnableShadowVariableWarnings ;
2014-09-23 13:55:06 -04:00
Result . Config . bUseStaticCRT = ( Target . Rules ! = null & & Target . Rules . bUseStaticCRT ) ;
2014-04-23 20:18:55 -04:00
Result . Config . OutputDirectory = Path . Combine ( Binary . Config . IntermediateDirectory , Name ) ;
2014-07-08 13:49:35 -04:00
// Switch the optimization flag if we're building a game module. Also pass the definition for building in DebugGame along (see ModuleManager.h for notes).
2014-08-26 11:26:50 -04:00
if ( Target . Configuration = = UnrealTargetConfiguration . DebugGame )
2014-04-23 20:18:55 -04:00
{
2015-04-21 11:27:37 -04:00
if ( ! Utils . IsFileUnderDirectory ( ModuleDirectory , BuildConfiguration . RelativeEnginePath ) )
2014-08-26 11:26:50 -04:00
{
Result . Config . Target . Configuration = CPPTargetConfiguration . Debug ;
Result . Config . Definitions . Add ( "UE_BUILD_DEVELOPMENT_WITH_DEBUGGAME=1" ) ;
}
2014-04-23 20:18:55 -04:00
}
// Add the module's private definitions.
Result . Config . Definitions . AddRange ( Definitions ) ;
// Setup the compile environment for the module.
2015-03-21 11:34:08 -04:00
SetupPrivateCompileEnvironment ( Result . Config . CPPIncludeInfo . IncludePaths , Result . Config . CPPIncludeInfo . SystemIncludePaths , Result . Config . Definitions , Result . Config . AdditionalFrameworks ) ;
2014-04-23 20:18:55 -04:00
2014-12-17 12:37:39 -05:00
// @hack to skip adding definitions to compile environment, they will be baked into source code files
if ( bSkipDefinitionsForCompileEnvironment )
{
Result . Config . Definitions . Clear ( ) ;
2014-12-18 16:32:27 -05:00
Result . Config . CPPIncludeInfo . IncludePaths = new HashSet < string > ( BaseCompileEnvironment . Config . CPPIncludeInfo . IncludePaths ) ;
2014-12-17 12:37:39 -05:00
}
2014-04-23 20:18:55 -04:00
return Result ;
2014-03-14 14:13:41 -04:00
}
2015-06-09 11:50:55 -04:00
public class UHTModuleInfoCacheType
{
public UHTModuleInfoCacheType ( IEnumerable < string > InHeaderFilenames , UHTModuleInfo InInfo )
{
HeaderFilenames = InHeaderFilenames ;
Info = InInfo ;
}
2014-04-23 20:18:55 -04:00
2015-06-09 11:50:55 -04:00
public IEnumerable < string > HeaderFilenames = null ;
public UHTModuleInfo Info = null ;
}
private UHTModuleInfoCacheType UHTModuleInfoCache = null ;
2014-04-23 20:18:55 -04:00
2014-07-31 09:34:11 -04:00
/// Total time spent generating PCHs for modules (not actually compiling, but generating the PCH's input data)
public static double TotalPCHGenTime = 0.0 ;
/// Time spent caching which PCH header is included by each module and source file
public static double TotalPCHCacheTime = 0.0 ;
2014-07-16 12:14:22 -04:00
2014-03-14 14:13:41 -04:00
/// <summary>
/// If any of this module's source files contain UObject definitions, this will return those header files back to the caller
/// </summary>
/// <returns>
2015-06-09 11:50:55 -04:00
public UHTModuleInfoCacheType GetCachedUHTModuleInfo ( )
2014-03-14 14:13:41 -04:00
{
2015-06-09 11:50:55 -04:00
if ( UHTModuleInfoCache = = null )
2014-07-18 14:20:08 -04:00
{
2015-06-09 11:50:55 -04:00
IEnumerable < string > HeaderFilenames = Directory . GetFiles ( ModuleDirectory , "*.h" , SearchOption . AllDirectories ) ;
UHTModuleInfo Info = ExternalExecution . CreateUHTModuleInfo ( HeaderFilenames , Target , Name , ModuleDirectory , Type ) ;
UHTModuleInfoCache = new UHTModuleInfoCacheType ( Info . PublicUObjectHeaders . Concat ( Info . PublicUObjectClassesHeaders ) . Concat ( Info . PrivateUObjectHeaders ) . Select ( x = > x . AbsolutePath ) . ToList ( ) , Info ) ;
2014-07-18 14:20:08 -04:00
}
2014-04-23 20:18:55 -04:00
2015-06-09 11:50:55 -04:00
return UHTModuleInfoCache ;
2014-03-14 14:13:41 -04:00
}
2015-06-09 11:50:55 -04:00
public override void GetAllDependencyModules ( CaselessDictionary < ModuleIndexPair > ReferencedModules , bool bIncludeDynamicallyLoaded , bool bForceCircular , bool bOnlyDirectDependencies )
2014-03-14 14:13:41 -04:00
{
2015-08-28 15:47:20 -04:00
List < UEBuildModule > AllDependencyModules = new List < UEBuildModule > ( ) ;
AllDependencyModules . AddRange ( PrivateDependencyModules ) ;
AllDependencyModules . AddRange ( PublicDependencyModules ) ;
2014-03-14 14:13:41 -04:00
if ( bIncludeDynamicallyLoaded )
{
2015-08-28 15:47:20 -04:00
AllDependencyModules . AddRange ( DynamicallyLoadedModules ) ;
AllDependencyModules . AddRange ( PlatformSpecificDynamicallyLoadedModules ) ;
2014-03-14 14:13:41 -04:00
}
2015-08-28 15:47:20 -04:00
foreach ( UEBuildModule DependencyModule in AllDependencyModules )
2014-03-14 14:13:41 -04:00
{
2015-08-28 15:47:20 -04:00
if ( ! ReferencedModules . ContainsKey ( DependencyModule . Name ) )
2014-03-14 14:13:41 -04:00
{
// Don't follow circular back-references!
2015-08-28 15:47:20 -04:00
bool bIsCircular = HasCircularDependencyOn ( DependencyModule . Name ) ;
2014-03-14 14:13:41 -04:00
if ( bForceCircular | | ! bIsCircular )
{
2015-08-28 15:47:20 -04:00
ReferencedModules [ DependencyModule . Name ] = null ;
2014-03-14 14:13:41 -04:00
2014-07-31 09:34:11 -04:00
if ( ! bOnlyDirectDependencies )
{
// Recurse into dependent modules first
2015-08-28 15:47:20 -04:00
DependencyModule . GetAllDependencyModules ( ReferencedModules , bIncludeDynamicallyLoaded , bForceCircular , bOnlyDirectDependencies ) ;
2014-07-31 09:34:11 -04:00
}
2014-03-14 14:13:41 -04:00
2015-08-28 15:47:20 -04:00
ReferencedModules [ DependencyModule . Name ] = new ModuleIndexPair { Module = DependencyModule , Index = ReferencedModules . Where ( x = > x . Value ! = null ) . Count ( ) - 1 } ;
2014-03-14 14:13:41 -04:00
}
}
}
}
2015-03-20 08:25:23 -04:00
public override void RecursivelyAddPrecompiledModules ( List < UEBuildModule > Modules )
{
if ( ! Modules . Contains ( this ) )
{
Modules . Add ( this ) ;
// Get the dependent modules
2015-08-28 15:47:20 -04:00
List < UEBuildModule > DependentModules = new List < UEBuildModule > ( ) ;
if ( PrivateDependencyModules ! = null )
{
DependentModules . AddRange ( PrivateDependencyModules ) ;
}
if ( PublicDependencyModules ! = null )
{
DependentModules . AddRange ( PublicDependencyModules ) ;
}
if ( DynamicallyLoadedModules ! = null )
{
DependentModules . AddRange ( DynamicallyLoadedModules ) ;
}
if ( PlatformSpecificDynamicallyLoadedModules ! = null )
{
DependentModules . AddRange ( PlatformSpecificDynamicallyLoadedModules ) ;
}
2015-03-20 08:25:23 -04:00
// Find modules for each of them, and add their dependencies too
2015-08-28 15:47:20 -04:00
foreach ( UEBuildModule DependentModule in DependentModules )
2015-03-20 08:25:23 -04:00
{
DependentModule . RecursivelyAddPrecompiledModules ( Modules ) ;
}
}
}
2015-04-11 13:09:16 -04:00
public override void RecursivelyProcessUnboundModules ( )
2014-03-14 14:13:41 -04:00
{
try
{
// Make sure this module is bound to a binary
if ( ! bIncludedInTarget )
{
throw new BuildException ( "Module '{0}' should already have been bound to a binary!" , Name ) ;
}
2015-08-28 15:47:20 -04:00
List < UEBuildModule > AllDependencyModules = new List < UEBuildModule > ( ) ;
AllDependencyModules . AddRange ( PrivateDependencyModules ) ;
AllDependencyModules . AddRange ( PublicDependencyModules ) ;
AllDependencyModules . AddRange ( DynamicallyLoadedModules ) ;
AllDependencyModules . AddRange ( PlatformSpecificDynamicallyLoadedModules ) ;
2014-03-14 14:13:41 -04:00
2015-08-28 15:47:20 -04:00
foreach ( UEBuildModule DependencyModule in AllDependencyModules )
2014-03-14 14:13:41 -04:00
{
// Skip modules that are included with the target (externals)
if ( ! DependencyModule . bIncludedInTarget )
{
2015-08-28 15:47:20 -04:00
bool bIsCrossTarget = Rules . PlatformSpecificDynamicallyLoadedModuleNames . Contains ( DependencyModule . Name ) & & ! Rules . DynamicallyLoadedModuleNames . Contains ( DependencyModule . Name ) ;
2014-03-14 14:13:41 -04:00
2015-04-11 13:09:16 -04:00
// Get the binary that this module should be bound to
2015-08-28 15:47:20 -04:00
UEBuildBinary BinaryToBindTo = Target . FindOrAddBinaryForModule ( DependencyModule . Name , bIsCrossTarget ) ;
2014-03-14 14:13:41 -04:00
2015-04-11 13:09:16 -04:00
// Bind this module
DependencyModule . Binary = BinaryToBindTo ;
DependencyModule . bIncludedInTarget = true ;
2014-03-14 14:13:41 -04:00
2015-04-11 13:09:16 -04:00
// Also add binaries for this module's dependencies
DependencyModule . RecursivelyProcessUnboundModules ( ) ;
2014-03-14 14:13:41 -04:00
}
if ( Target . ShouldCompileMonolithic ( ) = = false )
{
// Check to see if there is a circular relationship between the module and it's referencer
if ( DependencyModule . Binary ! = null )
{
2015-08-28 15:47:20 -04:00
if ( Rules . CircularlyReferencedDependentModules . Contains ( DependencyModule . Name ) )
2014-03-14 14:13:41 -04:00
{
DependencyModule . Binary . SetCreateImportLibrarySeparately ( true ) ;
}
}
}
}
}
catch ( System . Exception ex )
{
throw new ModuleProcessingException ( this , ex ) ;
}
}
2015-04-17 15:21:14 -04:00
}
2014-03-14 14:13:41 -04:00
/** A module that is compiled from C++ CLR code. */
class UEBuildModuleCPPCLR : UEBuildModuleCPP
{
/** The assemblies referenced by the module's private implementation. */
2014-09-11 03:21:51 -04:00
HashSet < string > PrivateAssemblyReferences ;
2014-03-14 14:13:41 -04:00
public UEBuildModuleCPPCLR (
UEBuildTarget InTarget ,
string InName ,
UEBuildModuleType InType ,
string InModuleDirectory ,
2015-04-20 18:05:25 -04:00
string InGeneratedCodeDirectory ,
2014-03-14 14:13:41 -04:00
IntelliSenseGatherer InIntelliSenseGatherer ,
IEnumerable < FileItem > InSourceFiles ,
2015-08-28 08:39:42 -04:00
ModuleRules InRules ,
2015-05-08 15:19:00 -04:00
bool bInBuildSourceFiles ,
2015-08-28 08:39:42 -04:00
string InBuildCsFilename
2014-03-14 14:13:41 -04:00
)
2015-08-28 08:39:42 -04:00
: base ( InTarget , InName , InType , InModuleDirectory , InGeneratedCodeDirectory , InIntelliSenseGatherer ,
InSourceFiles , InRules ,
bInBuildSourceFiles , InBuildCsFilename )
2014-03-14 14:13:41 -04:00
{
2015-08-28 08:39:42 -04:00
PrivateAssemblyReferences = HashSetFromOptionalEnumerableStringParameter ( InRules . PrivateAssemblyReferences ) ;
2014-03-14 14:13:41 -04:00
}
// UEBuildModule interface.
2015-04-10 11:19:40 -04:00
public override List < FileItem > Compile ( CPPEnvironment GlobalCompileEnvironment , CPPEnvironment CompileEnvironment )
2014-03-14 14:13:41 -04:00
{
2014-05-22 04:16:41 -04:00
var ModuleCLREnvironment = CompileEnvironment . DeepCopy ( ) ;
2014-03-14 14:13:41 -04:00
// Setup the module environment for the project CLR mode
ModuleCLREnvironment . Config . CLRMode = CPPCLRMode . CLREnabled ;
// Add the private assembly references to the compile environment.
foreach ( var PrivateAssemblyReference in PrivateAssemblyReferences )
{
ModuleCLREnvironment . AddPrivateAssembly ( PrivateAssemblyReference ) ;
}
// Pass the CLR compilation environment to the standard C++ module compilation code.
2015-04-10 11:19:40 -04:00
return base . Compile ( GlobalCompileEnvironment , ModuleCLREnvironment ) ;
2014-03-14 14:13:41 -04:00
}
public override void SetupPrivateLinkEnvironment (
2015-05-22 08:57:34 -04:00
UEBuildBinary SourceBinary ,
2015-03-21 11:34:08 -04:00
LinkEnvironment LinkEnvironment ,
List < UEBuildBinary > BinaryDependencies ,
Dictionary < UEBuildModule , bool > VisitedModules
2014-03-14 14:13:41 -04:00
)
{
2015-05-22 08:57:34 -04:00
base . SetupPrivateLinkEnvironment ( SourceBinary , LinkEnvironment , BinaryDependencies , VisitedModules ) ;
2014-03-14 14:13:41 -04:00
// Setup the link environment for linking a CLR binary.
LinkEnvironment . Config . CLRMode = CPPCLRMode . CLREnabled ;
}
}
Support for third party iOS framework bundled assets
* Work in progress, works with RPC utility, local mac support incoming
* Changed AdditionalPublicFrameworks from storing just string, to storing the frame work name, zip name, and bundled asset name that needs to be copied
* We also now store the module that added this framework, so we can derive the module project path, etc when we need it for when we create intermediate directories
#Codereview Josh.Adams, Peter.Sauerbrei, Michael.Noland, Gil.Gribb, Robert.Manuszewski
[CL 2068603 by John Pollard in Main branch]
2014-05-09 16:38:26 -04:00
public class UEBuildFramework
{
public UEBuildFramework ( string InFrameworkName )
{
FrameworkName = InFrameworkName ;
}
2014-07-01 11:28:39 -04:00
public UEBuildFramework ( string InFrameworkName , string InFrameworkZipPath )
{
FrameworkName = InFrameworkName ;
FrameworkZipPath = InFrameworkZipPath ;
}
Support for third party iOS framework bundled assets
* Work in progress, works with RPC utility, local mac support incoming
* Changed AdditionalPublicFrameworks from storing just string, to storing the frame work name, zip name, and bundled asset name that needs to be copied
* We also now store the module that added this framework, so we can derive the module project path, etc when we need it for when we create intermediate directories
#Codereview Josh.Adams, Peter.Sauerbrei, Michael.Noland, Gil.Gribb, Robert.Manuszewski
[CL 2068603 by John Pollard in Main branch]
2014-05-09 16:38:26 -04:00
public UEBuildFramework ( string InFrameworkName , string InFrameworkZipPath , string InCopyBundledAssets )
{
FrameworkName = InFrameworkName ;
FrameworkZipPath = InFrameworkZipPath ;
CopyBundledAssets = InCopyBundledAssets ;
}
public UEBuildModule OwningModule = null ;
public string FrameworkName = null ;
public string FrameworkZipPath = null ;
public string CopyBundledAssets = null ;
}
2014-07-28 14:55:48 -04:00
public class UEBuildBundleResource
{
2014-11-21 13:41:17 -05:00
public UEBuildBundleResource ( string InResourcePath , string InBundleContentsSubdir = "Resources" , bool bInShouldLog = true )
2014-07-28 14:55:48 -04:00
{
ResourcePath = InResourcePath ;
BundleContentsSubdir = InBundleContentsSubdir ;
2014-11-21 13:41:17 -05:00
bShouldLog = bInShouldLog ;
2014-07-28 14:55:48 -04:00
}
public string ResourcePath = null ;
public string BundleContentsSubdir = null ;
2014-11-21 13:41:17 -05:00
public bool bShouldLog = true ;
2014-07-28 14:55:48 -04:00
}
Experimental UnrealBuildTool makefile support
UnrealBuildTool 'Makefiles' allow for very fast iterative builds.
- New BuildConfiguration.xml setting added: "bUseExperimentalFastBuildIteration" (disabled by default)
- Turning this on causes Unreal Build Tool to emit 'UBT Makefiles' for targets when they're built the first time.
- Subsequent builds will load these Makefiles and begin outdatedness checking and build invocation very quickly.
- The caveat is that if source files are added or removed to the project, UBT will need to gather information about those in order for your build to complete successfully.
- Currently, you must run the project file generator after adding/removing source files to tell UBT to re-gather this information.
- Events that can invalidate the 'UBT Makefile':
- Adding/removing .cpp files
- Adding/removing .h files with UObjects
- Adding new UObject types to a file that didn't previously have any
- Changing global build settings (most settings in this file qualify.)
- Changed code that affects how Unreal Header Tool works
- You can force regeneration of the 'UBT Makefile' by passing the '-Gather' argument, or simply regenerating project files
- New command-line parameters added:
- "-Gather": Tells UBT to always perform the gather step (slower but will catch project structural changes)
- "-NoGather": Disables the gather step, unless UBT detects that it must be done. This is the default when bUseExperimentalFastBuildIteration is enabled
- "-GatherOnly": Runs the gather step and saves a UBTMakefile, but doesn't build anything
- "-Assemble": Tells UBT to also assemble build products. This always defaults to enabled
- "-NoAssemble": Tells UBT to skip the assemble step, whether we gathered build products or not
- "-AssembleOnly": Tells UBT to only assemble build products and not to gather, unless UBT determines it must
Other changes:
- UBT now keeps track of which targets it was building in an intermediate file, to help it invalidate cached includes in subsequent runs when the targets are different
- C++ includes are now stored in a class separate from the C++ compile enviroment (for easier serialization)
- The method that UBT uses to find the CoreUObject module timestamp was rewritten
- Various '@todo ubtmake' comments added to tag possible remaining Makefile tasks
- The 'FileItem' class had some member variable comments and code cleaned up, while making it serializable
- Cleaned up the comments and member variables in the "Action" class, while making it serializable
- Some UBT classes are now "serializable". This is because we need to store the data in UBTMakefiles.
- Removed support for Actions to tinker with Stdout and Stderror (was not used for anything)
- Moved PrecompileHeaderEnvironment class to the UEBuildModule.cs source file
- Plugin intermediate include directories are now selected on demand rather than cached early
- Toolchain code for gathering prerequisite headers is now shared in a single function (AddPrerequisiteSourceFile)
- Removed Action.StatusDetailedDescription, was not used for anything
- Removed UEBuildConfiguration.bExcludePlugins, was not used for anything
- Removed ECompilationResult.FailedDueToHeaderChange, was not used for anything
[CL 2254472 by Mike Fricker in Main branch]
2014-08-13 08:17:43 -04:00
public class PrecompileHeaderEnvironment
{
/** The name of the module this PCH header is a member of */
public readonly string ModuleName ;
/ * * PCH header file name as it appears in an # include statement in source code ( might include partial , or no relative path . )
This is needed by some compilers to use PCH features . * /
public string PCHHeaderNameInCode ;
/** The source header file that this precompiled header will be generated for */
public readonly FileItem PrecompiledHeaderIncludeFilename ;
/** Whether this precompiled header will be built with CLR features enabled. We won't mix and match CLR PCHs with non-CLR PCHs */
public readonly CPPCLRMode CLRMode ;
/** Whether this precompiled header will be built with code optimization enabled. */
public readonly ModuleRules . CodeOptimization OptimizeCode ;
/** The PCH file we're generating */
public FileItem PrecompiledHeaderFile = null ;
/ * * Object files emitted from the compiler when generating this precompiled header . These will be linked into modules that
include this PCH * /
public readonly List < FileItem > OutputObjectFiles = new List < FileItem > ( ) ;
public PrecompileHeaderEnvironment ( string InitModuleName , string InitPCHHeaderNameInCode , FileItem InitPrecompiledHeaderIncludeFilename , CPPCLRMode InitCLRMode , ModuleRules . CodeOptimization InitOptimizeCode )
{
ModuleName = InitModuleName ;
PCHHeaderNameInCode = InitPCHHeaderNameInCode ;
PrecompiledHeaderIncludeFilename = InitPrecompiledHeaderIncludeFilename ;
CLRMode = InitCLRMode ;
OptimizeCode = InitOptimizeCode ;
}
/// <summary>
/// Creates a precompiled header action to generate a new pch file
/// </summary>
/// <param name="PCHHeaderNameInCode">The precompiled header name as it appeared in an #include statement</param>
/// <param name="PrecompiledHeaderIncludeFilename">Name of the header used for pch.</param>
/// <param name="ProjectCPPEnvironment">The environment the C/C++ files in the project are compiled with.</param>
/// <param name="OutputDirectory">The folder to save the generated PCH file to</param>
/// <param name="ModuleName">Name of the module this PCH is being generated for</param>
/// <param name="bAllowDLLExports">True if we should allow DLLEXPORT definitions for this PCH</param>
/// <returns>the compilation output result of the created pch.</returns>
public static CPPOutput GeneratePCHCreationAction ( UEBuildTarget Target , string PCHHeaderNameInCode , FileItem PrecompiledHeaderIncludeFilename , CPPEnvironment ProjectCPPEnvironment , string OutputDirectory , string ModuleName , bool bAllowDLLExports )
{
// Find the header file to be precompiled. Don't skip external headers
if ( PrecompiledHeaderIncludeFilename . bExists )
{
// Create a Dummy wrapper around the PCH to avoid problems with #pragma once on clang
var ToolChain = UEToolChain . GetPlatformToolChain ( ProjectCPPEnvironment . Config . Target . Platform ) ;
string PCHGuardDefine = Path . GetFileNameWithoutExtension ( PrecompiledHeaderIncludeFilename . AbsolutePath ) . ToUpper ( ) ;
string LocalPCHHeaderNameInCode = ToolChain . ConvertPath ( PrecompiledHeaderIncludeFilename . AbsolutePath ) ;
string TmpPCHHeaderContents = String . Format ( "#ifndef __AUTO_{0}_H__\n#define __AUTO_{0}_H__\n//Last Write: {2}\n#include \"{1}\"\n#endif//__AUTO_{0}_H__" , PCHGuardDefine , LocalPCHHeaderNameInCode , PrecompiledHeaderIncludeFilename . LastWriteTime ) ;
string DummyPath = Path . Combine (
ProjectCPPEnvironment . Config . OutputDirectory ,
Path . GetFileName ( PrecompiledHeaderIncludeFilename . AbsolutePath ) ) ;
FileItem DummyPCH = FileItem . CreateIntermediateTextFile ( DummyPath , TmpPCHHeaderContents ) ;
// Create a new C++ environment that is used to create the PCH.
var ProjectPCHEnvironment = ProjectCPPEnvironment . DeepCopy ( ) ;
ProjectPCHEnvironment . Config . PrecompiledHeaderAction = PrecompiledHeaderAction . Create ;
ProjectPCHEnvironment . Config . PrecompiledHeaderIncludeFilename = PrecompiledHeaderIncludeFilename . AbsolutePath ;
ProjectPCHEnvironment . Config . PCHHeaderNameInCode = PCHHeaderNameInCode ;
ProjectPCHEnvironment . Config . OutputDirectory = OutputDirectory ;
if ( ! bAllowDLLExports )
{
for ( var CurDefinitionIndex = 0 ; CurDefinitionIndex < ProjectPCHEnvironment . Config . Definitions . Count ; + + CurDefinitionIndex )
{
// We change DLLEXPORT to DLLIMPORT for "shared" PCH headers
var OldDefinition = ProjectPCHEnvironment . Config . Definitions [ CurDefinitionIndex ] ;
if ( OldDefinition . EndsWith ( "=DLLEXPORT" ) )
{
ProjectPCHEnvironment . Config . Definitions [ CurDefinitionIndex ] = OldDefinition . Replace ( "DLLEXPORT" , "DLLIMPORT" ) ;
}
}
}
// Cache our CPP environment so that we can check for outdatedness quickly. Only files that have includes need this.
DummyPCH . CachedCPPIncludeInfo = ProjectPCHEnvironment . Config . CPPIncludeInfo ;
Log . TraceVerbose ( "Found PCH file \"{0}\"." , PrecompiledHeaderIncludeFilename ) ;
// Create the action to compile the PCH file.
return ProjectPCHEnvironment . CompileFiles ( Target , new List < FileItem > ( ) { DummyPCH } , ModuleName ) ;
}
throw new BuildException ( "Couldn't find PCH file \"{0}\"." , PrecompiledHeaderIncludeFilename ) ;
}
}
2014-03-14 14:13:41 -04:00
}