2014-03-14 14:13:41 -04:00
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
using System ;
using System.Collections.Generic ;
using System.Text.RegularExpressions ;
using System.Diagnostics ;
using System.IO ;
2014-09-22 11:23:43 -04:00
using System.Linq ;
2014-03-14 14:13:41 -04:00
namespace UnrealBuildTool
{
class HTML5ToolChain : VCToolChain
{
// cache the location of SDK tools
static string EMCCPath ;
static string PythonPath ;
2014-09-22 11:23:43 -04:00
static string EmscriptenSettingsPath = Path . Combine ( Environment . GetFolderPath ( Environment . SpecialFolder . UserProfile ) , "/.emscripten" ) ;
Dictionary < string , string > ReadEmscriptenSettings ( )
{
2014-09-24 13:56:28 -04:00
// Check HTML5ToolChain.cs for duplicate
2014-09-22 11:23:43 -04:00
if ( ! System . IO . File . Exists ( EmscriptenSettingsPath ) )
{
return new Dictionary < string , string > ( ) ;
}
Dictionary < string , string > Settings = new Dictionary < string , string > ( ) ;
System . IO . StreamReader SettingFile = new System . IO . StreamReader ( EmscriptenSettingsPath ) ;
2014-09-24 13:56:28 -04:00
string EMLine = null ;
while ( ( EMLine = SettingFile . ReadLine ( ) ) ! = null )
2014-09-22 11:23:43 -04:00
{
2014-09-24 13:56:28 -04:00
EMLine = EMLine . Split ( '#' ) [ 0 ] ;
string Pattern1 = @"(\w*)\s*=\s*['\[]?([^'\]\r\n]*)['\]]?" ;
Regex Rgx = new Regex ( Pattern1 , RegexOptions . IgnoreCase ) ;
MatchCollection Matches = Rgx . Matches ( EMLine ) ;
foreach ( Match Matched in Matches )
2014-09-22 11:23:43 -04:00
{
2014-09-24 13:56:28 -04:00
if ( Matched . Groups . Count = = 3 & & Matched . Groups [ 2 ] . ToString ( ) ! = "" )
{
Settings [ Matched . Groups [ 1 ] . ToString ( ) ] = Matched . Groups [ 2 ] . ToString ( ) ;
}
2014-09-22 11:23:43 -04:00
}
}
return Settings ;
}
2014-03-14 14:13:41 -04:00
public override void RegisterToolChain ( )
{
// Make sure the SDK is installed
// look up installed SDK.
2014-04-28 14:10:06 -04:00
string BaseSDKPath = Environment . GetEnvironmentVariable ( "EMSCRIPTEN" ) ;
2014-03-14 14:13:41 -04:00
if ( ! String . IsNullOrEmpty ( BaseSDKPath ) )
{
BaseSDKPath = BaseSDKPath . Replace ( "\"" , "" ) ;
if ( ! String . IsNullOrEmpty ( BaseSDKPath ) )
{
2014-09-22 11:23:43 -04:00
var EmscriptenSettings = ReadEmscriptenSettings ( ) ;
2014-03-14 14:13:41 -04:00
EMCCPath = Path . Combine ( BaseSDKPath , "emcc" ) ;
// also figure out where python lives (if no envvar, assume it's in the path)
2014-09-22 11:23:43 -04:00
if ( EmscriptenSettings . ContainsKey ( "PYTHON" ) )
{
PythonPath = EmscriptenSettings [ "PYTHON" ] ;
}
else
{
PythonPath = Environment . GetEnvironmentVariable ( "PYTHON" ) ;
}
2014-07-30 17:55:43 -04:00
string PythonExeName = Utils . IsRunningOnMono ? "python" : "python.exe" ;
2014-03-14 14:13:41 -04:00
if ( PythonPath = = null )
{
2014-07-30 17:55:43 -04:00
PythonPath = PythonExeName ;
2014-03-14 14:13:41 -04:00
}
2014-07-30 17:55:43 -04:00
else
{
if ( ! PythonPath . EndsWith ( PythonExeName ) )
{
PythonPath + = "/" + PythonExeName ;
}
}
2014-07-30 15:46:41 -04:00
EMCCPath = "\"" + EMCCPath + "\"" ;
2014-03-14 14:13:41 -04:00
// set some environment variable we'll need
//Environment.SetEnvironmentVariable("EMCC_DEBUG", "cache");
Environment . SetEnvironmentVariable ( "EMCC_CORES" , "8" ) ;
Environment . SetEnvironmentVariable ( "EMCC_FORCE_STDLIBS" , "1" ) ;
Environment . SetEnvironmentVariable ( "EMCC_OPTIMIZE_NORMALLY" , "1" ) ;
// finally register the toolchain that is now ready to go
Log . TraceVerbose ( " Registered for {0}" , CPPTargetPlatform . HTML5 . ToString ( ) ) ;
UEToolChain . RegisterPlatformToolChain ( CPPTargetPlatform . HTML5 , this ) ;
}
}
}
static string GetSharedArguments_Global ( CPPTargetConfiguration TargetConfiguration , string Architecture )
{
2014-04-23 17:30:27 -04:00
string Result = " " ;
2014-03-14 14:13:41 -04:00
2014-04-23 17:30:27 -04:00
if ( Architecture = = "-win32" )
{
2014-03-14 14:13:41 -04:00
return Result ;
}
2014-04-23 17:30:27 -04:00
// Result += " -funsigned-char";
// Result += " -fno-strict-aliasing";
Result + = " -fno-exceptions" ;
// Result += " -fno-short-enums";
2014-03-14 14:13:41 -04:00
2014-04-23 17:30:27 -04:00
Result + = " -Wno-unused-value" ; // appErrorf triggers this
Result + = " -Wno-switch" ; // many unhandled cases
Result + = " -Wno-tautological-constant-out-of-range-compare" ; // disables some warnings about comparisons from TCHAR being a char
// this hides the "warning : comparison of unsigned expression < 0 is always false" type warnings due to constant comparisons, which are possible with template arguments
Result + = " -Wno-tautological-compare" ;
2014-03-14 14:13:41 -04:00
2014-04-23 17:30:27 -04:00
// okay, in UE4, we'd fix the code for these, but in UE3, not worth it
Result + = " -Wno-logical-op-parentheses" ; // appErrorf triggers this
Result + = " -Wno-array-bounds" ; // some VectorLoads go past the end of the array, but it's okay in that case
2014-03-14 14:13:41 -04:00
Result + = " -Wno-invalid-offsetof" ; // too many warnings kills windows clang.
2014-04-23 17:30:27 -04:00
// JavsScript option overrides (see src/settings.js)
2014-03-14 14:13:41 -04:00
2014-04-23 17:30:27 -04:00
// we have to specify the full amount of memory with Asm.JS (1.5 G)
2014-03-14 14:13:41 -04:00
// I wonder if there's a per game way to change this.
2014-06-10 17:14:29 -04:00
int TotalMemory = 256 * 1024 * 1024 ;
2014-05-22 15:14:51 -04:00
Result + = " -s TOTAL_MEMORY=" + TotalMemory . ToString ( ) ;
2014-03-14 14:13:41 -04:00
2014-04-23 17:30:27 -04:00
// no need for exceptions
Result + = " -s DISABLE_EXCEPTION_CATCHING=1" ;
// enable checking for missing functions at link time as opposed to runtime
Result + = " -s WARN_ON_UNDEFINED_SYMBOLS=1" ;
// we want full ES2
Result + = " -s FULL_ES2=1 " ;
// export console command handler. Export main func too because default exports ( e.g Main ) are overridden if we use custom exported functions.
2014-07-14 10:54:28 -04:00
Result + = " -s EXPORTED_FUNCTIONS=\"['_main', '_resize_game']\" " ;
2014-03-14 14:13:41 -04:00
2014-04-23 17:30:27 -04:00
// NOTE: This may slow down the compiler's startup time!
{
2014-05-22 15:14:51 -04:00
Result + = " -s NO_EXIT_RUNTIME=1 --memory-init-file 1" ;
2014-04-23 17:30:27 -04:00
}
2014-03-14 14:13:41 -04:00
2014-04-23 17:30:27 -04:00
return Result ;
2014-03-14 14:13:41 -04:00
}
static string GetCLArguments_Global ( CPPEnvironment CompileEnvironment )
{
2014-06-09 11:12:01 -04:00
string Result = GetSharedArguments_Global ( CompileEnvironment . Config . Target . Configuration , CompileEnvironment . Config . Target . Architecture ) ;
2014-03-14 14:13:41 -04:00
2014-06-09 11:12:01 -04:00
if ( CompileEnvironment . Config . Target . Architecture ! = "-win32" )
2014-03-14 14:13:41 -04:00
{
// do we want debug info?
/ * if ( CompileEnvironment . Config . bCreateDebugInfo )
{
Result + = " -g" ;
} * /
Result + = " -Wno-warn-absolute-paths " ;
2014-05-22 15:14:51 -04:00
2014-06-09 11:12:01 -04:00
if ( CompileEnvironment . Config . Target . Configuration = = CPPTargetConfiguration . Debug )
2014-05-22 15:14:51 -04:00
{
Result + = " -O0" ;
}
2014-06-09 11:12:01 -04:00
if ( CompileEnvironment . Config . Target . Configuration = = CPPTargetConfiguration . Debug | | CompileEnvironment . Config . Target . Configuration = = CPPTargetConfiguration . Development )
2014-05-22 15:14:51 -04:00
{
Result + = " -s GL_ASSERTIONS=1 " ;
}
2014-06-09 11:12:01 -04:00
if ( CompileEnvironment . Config . Target . Configuration = = CPPTargetConfiguration . Development )
2014-05-22 15:14:51 -04:00
{
if ( UEBuildConfiguration . bCompileForSize )
{
Result + = " -Oz -s ASM_JS=1 -s OUTLINING_LIMIT=40000" ;
}
else
{
Result + = " -O2 -s ASM_JS=1 -s OUTLINING_LIMIT=110000" ;
}
}
2014-06-09 11:12:01 -04:00
if ( CompileEnvironment . Config . Target . Configuration = = CPPTargetConfiguration . Shipping )
2014-05-22 15:14:51 -04:00
{
if ( UEBuildConfiguration . bCompileForSize )
{
Result + = " -Oz -s ASM_JS=1 -s OUTLINING_LIMIT=40000" ;
}
else
{
Result + = " -O3 -s ASM_JS=1 -s OUTLINING_LIMIT=110000" ;
}
}
2014-03-14 14:13:41 -04:00
}
return Result ;
}
static string GetCLArguments_CPP ( CPPEnvironment CompileEnvironment )
{
string Result = "" ;
2014-06-09 11:12:01 -04:00
if ( CompileEnvironment . Config . Target . Architecture ! = "-win32" )
2014-03-14 14:13:41 -04:00
{
Result = " -std=c++11" ;
}
return Result ;
}
static string GetCLArguments_C ( string Architecture )
{
string Result = "" ;
return Result ;
}
static string GetLinkArguments ( LinkEnvironment LinkEnvironment )
{
2014-06-09 11:12:01 -04:00
string Result = GetSharedArguments_Global ( LinkEnvironment . Config . Target . Configuration , LinkEnvironment . Config . Target . Architecture ) ;
2014-03-14 14:13:41 -04:00
2014-06-09 11:12:01 -04:00
if ( LinkEnvironment . Config . Target . Architecture ! = "-win32" )
2014-03-14 14:13:41 -04:00
{
// enable verbose mode
Result + = " -v" ;
2014-06-09 11:12:01 -04:00
if ( LinkEnvironment . Config . Target . Configuration = = CPPTargetConfiguration . Debug )
2014-03-14 14:13:41 -04:00
{
// check for alignment/etc checking
//Result += " -s SAFE_HEAP=1";
//Result += " -s CHECK_HEAP_ALIGN=1";
//Result += " -s SAFE_DYNCALLS=1";
// enable assertions in non-Shipping/Release builds
Result + = " -s ASSERTIONS=1" ;
}
2014-06-09 11:12:01 -04:00
if ( LinkEnvironment . Config . Target . Configuration = = CPPTargetConfiguration . Debug )
2014-05-22 15:14:51 -04:00
{
Result + = " -O0" ;
}
2014-06-09 11:12:01 -04:00
if ( LinkEnvironment . Config . Target . Configuration = = CPPTargetConfiguration . Debug | | LinkEnvironment . Config . Target . Configuration = = CPPTargetConfiguration . Development )
2014-05-22 15:14:51 -04:00
{
Result + = " -s GL_ASSERTIONS=1 " ;
}
2014-06-09 11:12:01 -04:00
if ( LinkEnvironment . Config . Target . Configuration = = CPPTargetConfiguration . Development )
2014-05-22 15:14:51 -04:00
{
2014-07-09 18:55:25 -04:00
Result + = " -O2 -s ASM_JS=1 -s OUTLINING_LIMIT=110000 -g2 " ;
2014-05-22 15:14:51 -04:00
}
2014-06-09 11:12:01 -04:00
if ( LinkEnvironment . Config . Target . Configuration = = CPPTargetConfiguration . Shipping )
2014-05-22 15:14:51 -04:00
{
Result + = " -O3 -s ASM_JS=1 -s OUTLINING_LIMIT=40000" ;
}
2014-03-14 14:13:41 -04:00
Result + = " -s CASE_INSENSITIVE_FS=1 " ;
string BaseSDKPath = Environment . GetEnvironmentVariable ( "EMSCRIPTEN" ) ;
Result + = " --js-library \"" + BaseSDKPath + "/Src/library_openal.js\" " ;
}
return Result ;
}
static string GetLibArguments ( LinkEnvironment LinkEnvironment )
{
string Result = "" ;
2014-06-09 11:12:01 -04:00
if ( LinkEnvironment . Config . Target . Architecture = = "-win32" )
2014-03-14 14:13:41 -04:00
{
// Prevents the linker from displaying its logo for each invocation.
Result + = " /NOLOGO" ;
// Prompt the user before reporting internal errors to Microsoft.
Result + = " /errorReport:prompt" ;
// Win32 build
Result + = " /MACHINE:x86" ;
// Always CONSOLE because of main()
Result + = " /SUBSYSTEM:CONSOLE" ;
//
// Shipping & LTCG
//
2014-06-09 11:12:01 -04:00
if ( LinkEnvironment . Config . Target . Configuration = = CPPTargetConfiguration . Shipping )
2014-03-14 14:13:41 -04:00
{
// Use link-time code generation.
Result + = " /ltcg" ;
}
return Result ;
}
return Result ;
}
public static void CompileOutputReceivedDataEventHandler ( Object Sender , DataReceivedEventArgs Line )
{
var Output = Line . Data ;
if ( Output = = null )
{
return ;
}
Output = Output . Replace ( "\\" , "/" ) ;
// Need to match following for clickable links
string RegexFilePath = @"^([\/A-Za-z0-9_\-\.]*)+\.(cpp|c|mm|m|hpp|h)" ;
string RegexFilePath2 = @"^([A-Z]:[\/A-Za-z0-9_\-\.]*)+\.(cpp|c|mm|m|hpp|h)" ;
string RegexLineNumber = @"\:\d+\:\d+\:" ;
string RegexDescription = @"(\serror:\s|\swarning:\s).*" ;
// Get Matches
string MatchFilePath = Regex . Match ( Output , RegexFilePath ) . Value ;
if ( MatchFilePath . Length = = 0 )
{
MatchFilePath = Regex . Match ( Output , RegexFilePath2 ) . Value ;
}
string MatchLineNumber = Regex . Match ( Output , RegexLineNumber ) . Value ;
string MatchDescription = Regex . Match ( Output , RegexDescription ) . Value ;
// If any of the above matches failed, do nothing
if ( MatchFilePath . Length = = 0 | |
MatchLineNumber . Length = = 0 | |
MatchDescription . Length = = 0 )
{
Log . TraceWarning ( Output ) ;
return ;
}
// Convert Path
string RegexStrippedPath = @"(Engine\/|[A-Za-z0-9_\-\.]*\/).*" ;
string ConvertedFilePath = Regex . Match ( MatchFilePath , RegexStrippedPath ) . Value ;
ConvertedFilePath = Path . GetFullPath ( /*"..\\..\\" +*/ ConvertedFilePath ) ;
// Extract Line + Column Number
string ConvertedLineNumber = Regex . Match ( MatchLineNumber , @"\d+" ) . Value ;
string ConvertedColumnNumber = Regex . Match ( MatchLineNumber , @"(?<=:\d+:)\d+" ) . Value ;
// Write output
string ConvertedExpression = " " + ConvertedFilePath + "(" + ConvertedLineNumber + "," + ConvertedColumnNumber + "):" + MatchDescription ;
Log . TraceInformation ( ConvertedExpression ) ; // To create clickable vs link
Log . TraceInformation ( Output ) ; // To preserve readable output log
}
2014-07-31 09:34:11 -04:00
public override CPPOutput CompileCPPFiles ( UEBuildTarget Target , CPPEnvironment CompileEnvironment , List < FileItem > SourceFiles , string ModuleName )
2014-03-14 14:13:41 -04:00
{
2014-06-09 11:12:01 -04:00
if ( CompileEnvironment . Config . Target . Architecture = = "-win32" )
2014-03-14 14:13:41 -04:00
{
2014-07-31 09:34:11 -04:00
return base . CompileCPPFiles ( Target , CompileEnvironment , SourceFiles , ModuleName ) ;
2014-03-14 14:13:41 -04:00
}
string Arguments = GetCLArguments_Global ( CompileEnvironment ) ;
CPPOutput Result = new CPPOutput ( ) ;
// Add include paths to the argument list.
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
foreach ( string IncludePath in CompileEnvironment . Config . CPPIncludeInfo . IncludePaths )
2014-03-14 14:13:41 -04:00
{
Arguments + = string . Format ( " -I\"{0}\"" , IncludePath ) ;
}
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
foreach ( string IncludePath in CompileEnvironment . Config . CPPIncludeInfo . SystemIncludePaths )
2014-03-14 14:13:41 -04:00
{
Arguments + = string . Format ( " -I\"{0}\"" , IncludePath ) ;
}
2014-09-12 11:36:37 -04:00
2014-03-14 14:13:41 -04:00
// Add preprocessor definitions to the argument list.
foreach ( string Definition in CompileEnvironment . Config . Definitions )
{
Arguments + = string . Format ( " -D{0}" , Definition ) ;
}
2014-07-31 09:34:11 -04:00
var BuildPlatform = UEBuildPlatform . GetBuildPlatformForCPPTargetPlatform ( CompileEnvironment . Config . Target . Platform ) ;
2014-03-14 14:13:41 -04:00
foreach ( FileItem SourceFile in SourceFiles )
{
Action CompileAction = new Action ( ActionType . Compile ) ;
bool bIsPlainCFile = Path . GetExtension ( SourceFile . AbsolutePath ) . ToUpperInvariant ( ) = = ".C" ;
// Add the C++ source file and its included files to the prerequisite item list.
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
AddPrerequisiteSourceFile ( Target , BuildPlatform , CompileEnvironment , SourceFile , CompileAction . PrerequisiteItems ) ;
2014-03-14 14:13:41 -04:00
// Add the source file path to the command-line.
2014-04-28 14:10:06 -04:00
string FileArguments = string . Format ( " \"{0}\"" , SourceFile . AbsolutePath ) ;
2014-06-05 12:11:58 -04:00
var ObjectFileExtension = UEBuildPlatform . BuildPlatformDictionary [ UnrealTargetPlatform . HTML5 ] . GetBinaryExtension ( UEBuildBinaryType . Object ) ;
2014-03-14 14:13:41 -04:00
// Add the object file to the produced item list.
FileItem ObjectFile = FileItem . GetItemByPath (
Path . Combine (
CompileEnvironment . Config . OutputDirectory ,
2014-06-05 12:11:58 -04:00
Path . GetFileName ( SourceFile . AbsolutePath ) + ObjectFileExtension
2014-03-14 14:13:41 -04:00
)
) ;
CompileAction . ProducedItems . Add ( ObjectFile ) ;
FileArguments + = string . Format ( " -o \"{0}\"" , ObjectFile . AbsolutePath ) ;
// Add C or C++ specific compiler arguments.
if ( bIsPlainCFile )
{
2014-06-09 11:12:01 -04:00
FileArguments + = GetCLArguments_C ( CompileEnvironment . Config . Target . Architecture ) ;
2014-03-14 14:13:41 -04:00
}
else
{
FileArguments + = GetCLArguments_CPP ( CompileEnvironment ) ;
}
CompileAction . WorkingDirectory = Path . GetFullPath ( "." ) ;
CompileAction . CommandPath = PythonPath ;
2014-07-30 15:46:41 -04:00
2014-04-28 14:10:06 -04:00
CompileAction . CommandArguments = EMCCPath + Arguments + FileArguments + CompileEnvironment . Config . AdditionalArguments ;
2014-07-30 15:46:41 -04:00
2014-03-14 14:13:41 -04:00
System . Console . WriteLine ( CompileAction . CommandArguments ) ;
CompileAction . StatusDescription = Path . GetFileName ( SourceFile . AbsolutePath ) ;
CompileAction . OutputEventHandler = new DataReceivedEventHandler ( CompileOutputReceivedDataEventHandler ) ;
// Don't farm out creation of precomputed headers as it is the critical path task.
CompileAction . bCanExecuteRemotely = CompileEnvironment . Config . PrecompiledHeaderAction ! = PrecompiledHeaderAction . Create ;
// this is the final output of the compile step (a .abc file)
Result . ObjectFiles . Add ( ObjectFile ) ;
// VC++ always outputs the source file name being compiled, so we don't need to emit this ourselves
CompileAction . bShouldOutputStatusDescription = true ;
// Don't farm out creation of precompiled headers as it is the critical path task.
CompileAction . bCanExecuteRemotely =
CompileEnvironment . Config . PrecompiledHeaderAction ! = PrecompiledHeaderAction . Create | |
BuildConfiguration . bAllowRemotelyCompiledPCHs ;
}
return Result ;
}
2014-07-31 09:34:11 -04:00
public override CPPOutput CompileRCFiles ( UEBuildTarget Target , CPPEnvironment Environment , List < FileItem > RCFiles )
2014-03-14 14:13:41 -04:00
{
CPPOutput Result = new CPPOutput ( ) ;
2014-06-09 11:12:01 -04:00
if ( Environment . Config . Target . Architecture = = "-win32" )
2014-03-14 14:13:41 -04:00
{
2014-07-31 09:34:11 -04:00
return base . CompileRCFiles ( Target , Environment , RCFiles ) ;
2014-03-14 14:13:41 -04:00
}
return Result ;
}
/ * *
* Translates clang output warning / error messages into vs - clickable messages
*
* @param sender Sending object
* @param e Event arguments ( In this case , the line of string output )
* /
protected void RemoteOutputReceivedEventHandler ( object sender , DataReceivedEventArgs e )
{
var Output = e . Data ;
if ( Output = = null )
{
return ;
}
if ( Utils . IsRunningOnMono )
{
Log . TraceInformation ( Output ) ;
}
else
{
// Need to match following for clickable links
string RegexFilePath = @"^(\/[A-Za-z0-9_\-\.]*)+\.(cpp|c|mm|m|hpp|h)" ;
string RegexLineNumber = @"\:\d+\:\d+\:" ;
string RegexDescription = @"(\serror:\s|\swarning:\s).*" ;
// Get Matches
string MatchFilePath = Regex . Match ( Output , RegexFilePath ) . Value . Replace ( "Engine/Source/../../" , "" ) ;
string MatchLineNumber = Regex . Match ( Output , RegexLineNumber ) . Value ;
string MatchDescription = Regex . Match ( Output , RegexDescription ) . Value ;
// If any of the above matches failed, do nothing
if ( MatchFilePath . Length = = 0 | |
MatchLineNumber . Length = = 0 | |
MatchDescription . Length = = 0 )
{
Log . TraceInformation ( Output ) ;
return ;
}
// Convert Path
string RegexStrippedPath = @"\/Engine\/.*" ; //@"(Engine\/|[A-Za-z0-9_\-\.]*\/).*";
string ConvertedFilePath = Regex . Match ( MatchFilePath , RegexStrippedPath ) . Value ;
ConvertedFilePath = Path . GetFullPath ( "..\\.." + ConvertedFilePath ) ;
// Extract Line + Column Number
string ConvertedLineNumber = Regex . Match ( MatchLineNumber , @"\d+" ) . Value ;
string ConvertedColumnNumber = Regex . Match ( MatchLineNumber , @"(?<=:\d+:)\d+" ) . Value ;
// Write output
string ConvertedExpression = " " + ConvertedFilePath + "(" + ConvertedLineNumber + "," + ConvertedColumnNumber + "):" + MatchDescription ;
Log . TraceInformation ( ConvertedExpression ) ; // To create clickable vs link
// Log.TraceInformation(Output); // To preserve readable output log
}
}
public override FileItem LinkFiles ( LinkEnvironment LinkEnvironment , bool bBuildImportLibraryOnly )
{
2014-06-09 11:12:01 -04:00
if ( LinkEnvironment . Config . Target . Architecture = = "-win32" )
2014-03-14 14:13:41 -04:00
{
return base . LinkFiles ( LinkEnvironment , bBuildImportLibraryOnly ) ;
}
FileItem OutputFile ;
// Make the final javascript file
Action LinkAction = new Action ( ActionType . Link ) ;
LinkAction . bCanExecuteRemotely = false ;
LinkAction . WorkingDirectory = Path . GetFullPath ( "." ) ;
LinkAction . CommandPath = PythonPath ;
2014-04-28 14:10:06 -04:00
LinkAction . CommandArguments = EMCCPath ;
2014-03-14 14:13:41 -04:00
LinkAction . CommandArguments + = GetLinkArguments ( LinkEnvironment ) ;
// Add the input files to a response file, and pass the response file on the command-line.
foreach ( FileItem InputFile in LinkEnvironment . InputFiles )
{
System . Console . WriteLine ( "File {0} " , InputFile . AbsolutePath ) ;
2014-04-28 14:10:06 -04:00
LinkAction . CommandArguments + = string . Format ( " \"{0}\"" , InputFile . AbsolutePath ) ;
2014-03-14 14:13:41 -04:00
LinkAction . PrerequisiteItems . Add ( InputFile ) ;
}
foreach ( string InputFile in LinkEnvironment . Config . AdditionalLibraries )
{
2014-08-04 08:08:56 -04:00
FileItem Item = FileItem . GetItemByPath ( InputFile ) ;
if ( Item . AbsolutePath . Contains ( ".lib" ) )
continue ;
2014-03-14 14:13:41 -04:00
if ( Item ! = null )
{
2014-05-22 15:14:51 -04:00
if ( Item . ToString ( ) . Contains ( ".js" ) )
LinkAction . CommandArguments + = string . Format ( " --js-library \"{0}\"" , Item . AbsolutePath ) ;
else
LinkAction . CommandArguments + = string . Format ( " \"{0}\"" , Item . AbsolutePath ) ;
2014-03-14 14:13:41 -04:00
LinkAction . PrerequisiteItems . Add ( Item ) ;
}
}
// make the file we will create
OutputFile = FileItem . GetItemByPath ( LinkEnvironment . Config . OutputFilePath ) ;
LinkAction . ProducedItems . Add ( OutputFile ) ;
LinkAction . CommandArguments + = string . Format ( " -o \"{0}\"" , OutputFile . AbsolutePath ) ;
2014-04-28 14:10:06 -04:00
FileItem OutputBC = FileItem . GetItemByPath ( LinkEnvironment . Config . OutputFilePath . Replace ( ".js" , ".bc" ) . Replace ( ".html" , ".bc" ) ) ;
LinkAction . ProducedItems . Add ( OutputBC ) ;
LinkAction . CommandArguments + = string . Format ( " --save-bc \"{0}\"" , OutputBC . AbsolutePath ) ;
2014-03-14 14:13:41 -04:00
LinkAction . StatusDescription = Path . GetFileName ( OutputFile . AbsolutePath ) ;
LinkAction . OutputEventHandler = new DataReceivedEventHandler ( RemoteOutputReceivedEventHandler ) ;
return OutputFile ;
}
public override void CompileCSharpProject ( CSharpEnvironment CompileEnvironment , string ProjectFileName , string DestinationFile )
{
throw new BuildException ( "HTML5 cannot compile C# files" ) ;
}
2014-07-29 13:38:03 -04:00
public override void AddFilesToManifest ( ref FileManifest Manifest , UEBuildBinary Binary )
{
// we need to include the generated .mem file.
string MemFile = Binary . Config . OutputFilePath + ".mem" ;
// make sure we don't add mem files more than once.
Manifest . AddBinaryNames ( MemFile , null ) ;
}
2014-03-14 14:13:41 -04:00
} ;
}