You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
Force ThirdParty libs to be linked in always last. Linker may refuse to link in archives if they are linked in before the linker encounters dependent symbols. (fixes unresolved symbols in html5 rocket build ) [CL 2409758 by Ankit Khare in Main branch]
525 lines
19 KiB
C#
525 lines
19 KiB
C#
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text.RegularExpressions;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Linq;
|
|
|
|
namespace UnrealBuildTool
|
|
{
|
|
class HTML5ToolChain : VCToolChain
|
|
{
|
|
static string EMCCPath;
|
|
static string PythonPath;
|
|
|
|
// cache the location of SDK tools
|
|
public override void RegisterToolChain()
|
|
{
|
|
if (HTML5SDKInfo.IsSDKInstalled() && HTML5SDKInfo.IsPythonInstalled())
|
|
{
|
|
EMCCPath = "\"" + HTML5SDKInfo.EmscriptenCompiler() + "\"";
|
|
PythonPath = HTML5SDKInfo.PythonPath();
|
|
|
|
// 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)
|
|
{
|
|
string Result = " ";
|
|
|
|
if (Architecture == "-win32")
|
|
{
|
|
return Result;
|
|
}
|
|
|
|
// Result += " -funsigned-char";
|
|
// Result += " -fno-strict-aliasing";
|
|
Result += " -fno-exceptions";
|
|
// Result += " -fno-short-enums";
|
|
|
|
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";
|
|
|
|
// 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
|
|
Result += " -Wno-invalid-offsetof"; // too many warnings kills windows clang.
|
|
|
|
|
|
// JavsScript option overrides (see src/settings.js)
|
|
|
|
// we have to specify the full amount of memory with Asm.JS (1.5 G)
|
|
// I wonder if there's a per game way to change this.
|
|
int TotalMemory = 256 * 1024 * 1024;
|
|
Result += " -s TOTAL_MEMORY=" + TotalMemory.ToString();
|
|
|
|
// 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.
|
|
Result += " -s EXPORTED_FUNCTIONS=\"['_main', '_resize_game', '_on_fatal']\" ";
|
|
|
|
// NOTE: This may slow down the compiler's startup time!
|
|
{
|
|
Result += " -s NO_EXIT_RUNTIME=1 --memory-init-file 1";
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
static string GetCLArguments_Global(CPPEnvironment CompileEnvironment)
|
|
{
|
|
string Result = GetSharedArguments_Global(CompileEnvironment.Config.Target.Configuration, CompileEnvironment.Config.Target.Architecture);
|
|
|
|
if (CompileEnvironment.Config.Target.Architecture != "-win32")
|
|
{
|
|
// do we want debug info?
|
|
/* if (CompileEnvironment.Config.bCreateDebugInfo)
|
|
{
|
|
Result += " -g";
|
|
}*/
|
|
|
|
Result += " -Wno-warn-absolute-paths ";
|
|
|
|
if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug)
|
|
{
|
|
Result += " -O0";
|
|
}
|
|
if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug || CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Development)
|
|
{
|
|
Result += " -s GL_ASSERTIONS=1 ";
|
|
}
|
|
if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Development)
|
|
{
|
|
if (UEBuildConfiguration.bCompileForSize)
|
|
{
|
|
Result += " -Oz -s ASM_JS=1 -s OUTLINING_LIMIT=40000";
|
|
}
|
|
else
|
|
{
|
|
Result += " -O2 -s ASM_JS=1 -s OUTLINING_LIMIT=110000";
|
|
}
|
|
}
|
|
if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Shipping)
|
|
{
|
|
if (UEBuildConfiguration.bCompileForSize)
|
|
{
|
|
Result += " -Oz -s ASM_JS=1 -s OUTLINING_LIMIT=40000";
|
|
}
|
|
else
|
|
{
|
|
Result += " -O3 -s ASM_JS=1 -s OUTLINING_LIMIT=110000";
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
static string GetCLArguments_CPP(CPPEnvironment CompileEnvironment)
|
|
{
|
|
string Result = "";
|
|
|
|
if (CompileEnvironment.Config.Target.Architecture != "-win32")
|
|
{
|
|
Result = " -std=c++11";
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
static string GetCLArguments_C(string Architecture)
|
|
{
|
|
string Result = "";
|
|
return Result;
|
|
}
|
|
|
|
static string GetLinkArguments(LinkEnvironment LinkEnvironment)
|
|
{
|
|
string Result = GetSharedArguments_Global(LinkEnvironment.Config.Target.Configuration, LinkEnvironment.Config.Target.Architecture);
|
|
|
|
if (LinkEnvironment.Config.Target.Architecture != "-win32")
|
|
{
|
|
|
|
// enable verbose mode
|
|
Result += " -v";
|
|
|
|
if (LinkEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug)
|
|
{
|
|
// 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";
|
|
}
|
|
|
|
if (LinkEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug)
|
|
{
|
|
Result += " -O0";
|
|
}
|
|
if (LinkEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug || LinkEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Development)
|
|
{
|
|
Result += " -s GL_ASSERTIONS=1 ";
|
|
}
|
|
if (LinkEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Development)
|
|
{
|
|
Result += " -O2 -s ASM_JS=1 -s OUTLINING_LIMIT=110000 -g2 ";
|
|
}
|
|
if (LinkEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Shipping)
|
|
{
|
|
Result += " -O3 -s ASM_JS=1 -s OUTLINING_LIMIT=40000";
|
|
}
|
|
|
|
Result += " -s CASE_INSENSITIVE_FS=1 ";
|
|
|
|
|
|
string BaseSDKPath = HTML5SDKInfo.EmscriptenSDKPath();
|
|
Result += " --js-library \"" + BaseSDKPath + "/Src/library_openal.js\" ";
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
static string GetLibArguments(LinkEnvironment LinkEnvironment)
|
|
{
|
|
string Result = "";
|
|
|
|
if (LinkEnvironment.Config.Target.Architecture == "-win32")
|
|
{
|
|
// 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
|
|
//
|
|
if (LinkEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Shipping)
|
|
{
|
|
// 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
|
|
}
|
|
|
|
public override CPPOutput CompileCPPFiles(UEBuildTarget Target, CPPEnvironment CompileEnvironment, List<FileItem> SourceFiles, string ModuleName)
|
|
{
|
|
if (CompileEnvironment.Config.Target.Architecture == "-win32")
|
|
{
|
|
return base.CompileCPPFiles(Target, CompileEnvironment, SourceFiles, ModuleName);
|
|
}
|
|
|
|
string Arguments = GetCLArguments_Global(CompileEnvironment);
|
|
|
|
CPPOutput Result = new CPPOutput();
|
|
|
|
// Add include paths to the argument list.
|
|
foreach (string IncludePath in CompileEnvironment.Config.CPPIncludeInfo.IncludePaths)
|
|
{
|
|
Arguments += string.Format(" -I\"{0}\"", IncludePath);
|
|
}
|
|
foreach (string IncludePath in CompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths)
|
|
{
|
|
Arguments += string.Format(" -I\"{0}\"", IncludePath);
|
|
}
|
|
|
|
|
|
// Add preprocessor definitions to the argument list.
|
|
foreach (string Definition in CompileEnvironment.Config.Definitions)
|
|
{
|
|
Arguments += string.Format(" -D{0}", Definition);
|
|
}
|
|
|
|
|
|
var BuildPlatform = UEBuildPlatform.GetBuildPlatformForCPPTargetPlatform(CompileEnvironment.Config.Target.Platform);
|
|
|
|
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.
|
|
AddPrerequisiteSourceFile( Target, BuildPlatform, CompileEnvironment, SourceFile, CompileAction.PrerequisiteItems );
|
|
|
|
// Add the source file path to the command-line.
|
|
string FileArguments = string.Format(" \"{0}\"", SourceFile.AbsolutePath);
|
|
var ObjectFileExtension = UEBuildPlatform.BuildPlatformDictionary[UnrealTargetPlatform.HTML5].GetBinaryExtension(UEBuildBinaryType.Object);
|
|
// Add the object file to the produced item list.
|
|
FileItem ObjectFile = FileItem.GetItemByPath(
|
|
Path.Combine(
|
|
CompileEnvironment.Config.OutputDirectory,
|
|
Path.GetFileName(SourceFile.AbsolutePath) + ObjectFileExtension
|
|
)
|
|
);
|
|
CompileAction.ProducedItems.Add(ObjectFile);
|
|
FileArguments += string.Format(" -o \"{0}\"", ObjectFile.AbsolutePath);
|
|
|
|
// Add C or C++ specific compiler arguments.
|
|
if (bIsPlainCFile)
|
|
{
|
|
FileArguments += GetCLArguments_C(CompileEnvironment.Config.Target.Architecture);
|
|
}
|
|
else
|
|
{
|
|
FileArguments += GetCLArguments_CPP(CompileEnvironment);
|
|
}
|
|
|
|
CompileAction.WorkingDirectory = Path.GetFullPath(".");
|
|
CompileAction.CommandPath = PythonPath;
|
|
|
|
CompileAction.CommandArguments = EMCCPath + " " + Arguments + FileArguments + CompileEnvironment.Config.AdditionalArguments;
|
|
|
|
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;
|
|
}
|
|
|
|
public override CPPOutput CompileRCFiles(UEBuildTarget Target, CPPEnvironment Environment, List<FileItem> RCFiles)
|
|
{
|
|
CPPOutput Result = new CPPOutput();
|
|
|
|
if (Environment.Config.Target.Architecture == "-win32")
|
|
{
|
|
return base.CompileRCFiles(Target, Environment, RCFiles);
|
|
}
|
|
|
|
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)
|
|
{
|
|
if (LinkEnvironment.Config.Target.Architecture == "-win32")
|
|
{
|
|
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;
|
|
LinkAction.CommandArguments = EMCCPath;
|
|
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);
|
|
LinkAction.CommandArguments += string.Format(" \"{0}\"", InputFile.AbsolutePath);
|
|
LinkAction.PrerequisiteItems.Add(InputFile);
|
|
}
|
|
if (!LinkEnvironment.Config.bIsBuildingLibrary)
|
|
{
|
|
// Make sure ThirdParty libs are at the end.
|
|
List<string> ThirdParty = (from Lib in LinkEnvironment.Config.AdditionalLibraries
|
|
where Lib.Contains("ThirdParty")
|
|
select Lib).ToList();
|
|
|
|
LinkEnvironment.Config.AdditionalLibraries.RemoveAll(Element => Element.Contains("ThirdParty"));
|
|
LinkEnvironment.Config.AdditionalLibraries.AddRange(ThirdParty);
|
|
|
|
foreach (string InputFile in LinkEnvironment.Config.AdditionalLibraries)
|
|
{
|
|
FileItem Item = FileItem.GetItemByPath(InputFile);
|
|
|
|
if (Item.AbsolutePath.Contains(".lib"))
|
|
continue;
|
|
|
|
if (Item != null)
|
|
{
|
|
if (Item.ToString().Contains(".js"))
|
|
LinkAction.CommandArguments += string.Format(" --js-library \"{0}\"", Item.AbsolutePath);
|
|
else
|
|
LinkAction.CommandArguments += string.Format(" \"{0}\"", Item.AbsolutePath);
|
|
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);
|
|
|
|
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);
|
|
|
|
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");
|
|
}
|
|
|
|
public override void AddFilesToManifest(BuildManifest Manifest, UEBuildBinary Binary)
|
|
{
|
|
// we need to include the generated .mem file.
|
|
Manifest.AddBuildProduct(Binary.Config.OutputFilePath + ".mem");
|
|
}
|
|
|
|
public override UnrealTargetPlatform GetPlatform()
|
|
{
|
|
return UnrealTargetPlatform.HTML5;
|
|
}
|
|
};
|
|
}
|