Files
UnrealEngineUWP/Engine/Source/Programs/UnrealBuildTool/Android/AndroidToolChain.cs
Chris Babcock 2b886e2c93 Copying //UE4/Dev-Mobile to //UE4/Main (Source: //UE4/Dev-Mobile @ 2945914)
==========================
MAJOR FEATURES + CHANGES
==========================

Change 2911743 on 2016/03/16 by Allan.Bentham

	Fix broken tonemapper when using 32bpp encoded HDR. Fixes UE-28359
	Cleaned up some ronin integration hacks from ronin.

Change 2912053 on 2016/03/16 by Peter.Sauerbrei

	disable Vulkan in Win32 builds for now
	#codereview rolando.caloca
	#jira UE-28465

Change 2914512 on 2016/03/18 by Dmitriy.Dyomin

	Fixed crash on Nexus5 with Android 4.4.2 when TonemapperFilm is enabled

Change 2914944 on 2016/03/18 by Allan.Bentham

	Fix es2 tonemap flip. Fixes UE-25148

Change 2915248 on 2016/03/18 by Chris.Babcock

	Updates to support NDK r11
	#jira UE-28529
	#ue4
	#android

Change 2919192 on 2016/03/22 by Chris.Babcock

	NDK level set above 19 forces minSdkVersion to 21 or above to prevent installing on unsupported devices
	#jira UE-28408
	#ue4
	#android
	#codereview Jack.Porter

Change 2919591 on 2016/03/23 by Allan.Bentham

	Merge ronin's Gaussian DoF to 4.11's dof changes.

	Gaussian DoF will use a single recombine pass with ES31 devices or if no separate translucency is used on SM4+.
	Added permutation to exclude separate translucency from Gaussian recombine shader when not in use.

	#codereview martin.mittring

Change 2920758 on 2016/03/24 by Dmitriy.Dyomin

	Fixed: shifting lighting samples octree
	https://udn.unrealengine.com/questions/276026/lighting-samples-visualization-not-working-with-le.html

Change 2920793 on 2016/03/24 by Dmitriy.Dyomin

	Fixed: When sub-level set to be unloaded but with visbility state set to true, ULevelStreaming::IsStreamingStatePending returns wrong value
	#jira UE-26426

Change 2920981 on 2016/03/24 by Dmitriy.Dyomin

	GPU particles support for iOS Metal (A8+ only)
	#jira UE-11067
	#jira UE-28514
	#codereview Jack.Porter

Change 2921383 on 2016/03/24 by Allan.Bentham

	Fix inverted image on device when framebuffer fetch/bViewRectSource is not used.
	#codereview jack.porter

Change 2925694 on 2016/03/29 by Dmitriy.Dyomin

	Fixed: GPU particles and bloom on S7 Mali

Change 2927065 on 2016/03/29 by Chris.Babcock

	Set the DT_SONAME field in linker (stops warning toast)
	#ue4
	#android
	#codereview Jack.Porter

Change 2927375 on 2016/03/30 by Jack.Porter

	Fixed localization for placement mode Cube, Sphere, Cylinder and Cone

Change 2928643 on 2016/03/30 by Jack.Porter

	Fixed bug introdued by Ronin merge with DepthOfFieldScale setting being locked for BokehDOF

	#code_review: allan.bentham

Change 2932773 on 2016/04/04 by Jack.Porter

	Reapply android Vulkan version fixes

Change 2932853 on 2016/04/05 by Jack.Porter

	Enable VULKAN_CLEAR_SURFACE_ON_CREATE on Android to prevent assertion

Change 2932998 on 2016/04/05 by Jack.Porter

	Native web browser widget on iOS

	#jira UEMOB-20

Change 2933420 on 2016/04/05 by Chris.Babcock

	Removed hard-coded bUseUnityBuild in UBT for Android (contributed by kosz78)
	#jira UE-29066
	#pr #2236
	#ue4
	#android

Change 2934315 on 2016/04/05 by Chris.Babcock

	Allow Android to act as server with OnlineSubsystemNull (contributed by psychogony)
	#jira UE-23937
	#PR #1820
	#ue4
	#android
	#codereview Ryan.Gerleve

Change 2935038 on 2016/04/06 by Chris.Babcock

	Fix OpenGLES31 compile error
	#ue4
	#android
	#codereview Jack.Porter

Change 2936288 on 2016/04/07 by Allan.Bentham

	Planar reflection captures for mobile. (UE-27426)
	Added mobile planar reflection flag to material.

	#codereview jack.porter, daniel.wright

Change 2936297 on 2016/04/07 by Allan.Bentham

	Missed file. Planar reflection captures for mobile. (UE-27426)
	#codereview jack.porter, daniel.wright

Change 2937763 on 2016/04/08 by Dmitriy.Dyomin

	Fix InstancedStaticMesh batches for ES2 (contributed by Grimmick)
	GitHub #2031
	#jira UE-26576
	#codereview Jack.Porter

Change 2937863 on 2016/04/08 by Jack.Porter

	Merged Ronin CLs 2840392, 2860028

	Allow vertex texture fetches on ES2 (requires absolute mip level)

Change 2938461 on 2016/04/08 by Chris.Babcock

	Write Android uninstall batch files
	#ue4
	#android

Change 2939679 on 2016/04/11 by Allan.Bentham

	Remove bStationaryLightUsesCSMForMovableShadows from light component's UI.
	renamed proxy equivalent and infer its state from Inset Shadows For Movable Objects

	#codereview jack.porter, daniel.wright

Change 2939887 on 2016/04/11 by Chris.Babcock

	Android ARM64 libraries
	#jira UEPLAT-1268
	#ue4
	#android

Change 2940125 on 2016/04/11 by Chris.Babcock

	Added requirements to Arm64 and x86_64 tooltips

Change 2941051 on 2016/04/12 by Allan.Bentham

	Fix for inverted RG channels when using filmic tonemapper with ES2.
	#codereview jack.porter

Change 2942523 on 2016/04/13 by Chris.Babcock

	Add cxa_demangle build.cs instead of hiding dependency in UEBuildAndroid.cs
	#ue4
	#android
	#codereview Josh.Adams

Change 2942578 on 2016/04/13 by Chris.Babcock

	Add cxademangle dependency to Core for Android
	#ue4
	#android
	#codereview Josh.Adams

Change 2942997 on 2016/04/13 by Chris.Babcock

	Run Ant with -quiet first and run again without if there is an error for the log
	#ue4
	#android
	#codereview Josh.Adams

Change 2943320 on 2016/04/14 by Jack.Porter

	Fixed planar reflection merge errors

Change 2943352 on 2016/04/14 by Jack.Porter

	Fix NAME_VULKAN_ES3_1_ANDROID shader format name

	#codereview: Rolando.Coloca

Change 2943367 on 2016/04/14 by Dmitriy.Dyomin

	Added cvars to add or strip specific GL extensions from a driver reported extensions string
	#jira UE-29467

Change 2943425 on 2016/04/14 by Dmitriy.Dyomin

	Better logging of MobileHDR mode

Change 2943461 on 2016/04/14 by Dmitriy.Dyomin

	Fixing HDR rendering and bloom on Galaxy S7

Change 2943493 on 2016/04/14 by Dmitriy.Dyomin

	Better HDR fix for devices with ES3 support

Change 2943855 on 2016/04/14 by Allan.Bentham

	Mobile planar reflections.
	 - currently only supports opaque materials
	#codereview jack.porter

Change 2944721 on 2016/04/14 by Chris.Babcock

	Allow Vulkan-only Android builds
	#ue4
	#android
	#codereview Allan.Bentham,Jack.Porter

Change 2944771 on 2016/04/14 by Dmitriy.Dyomin

	Fixed: mesh particles crash in ES2

Change 2944827 on 2016/04/15 by Dmitriy.Dyomin

	Fixed: GPU particles not working on S6 with Android 6.0.1

Change 2944836 on 2016/04/15 by Jack.Porter

	Disable FX system calls in forward renderer when particles showflag is off

Change 2944840 on 2016/04/15 by Jack.Porter

	Re-enabled non-radial TDeferredLightVS on ES2 for planar and put  #if FEATURE_LEVEL >= FEATURE_LEVEL_SM4  around the radial shader code which was tripping up ES2.

	#codereview: Allan.Bentham, Chris.Babcock, Daniel.Wright

Change 2944914 on 2016/04/15 by Jack.Porter

	Device profiles to detect Galaxy S7 Mali and Adreno variants in Vulkan mode

Change 2945020 on 2016/04/15 by Gareth.Martin

	Cloning changes across from Dev-Landscape to Dev-Mobile due to feature deadline for 4.12.

	Change 2943560 on 2016/04/14 by Gareth.Martin

	        Added ability to expand landscape bounds
	        #jira UE-28928
	        #jira UE-25230

	Change 2943538 on 2016/04/14 by Gareth.Martin

	        Fix a crash with saving a level >2GB in size.
	        There may still be other crashes with >2GB levels.

	Change 2943477 on 2016/04/14 by Gareth.Martin

	        Fixed LODFalloff setting on landscape getting reset when using the "Change Landscape Component Size" tool
	        Also moved all the LOD settings together in LandscapeProxy.h because it was messy

	Change 2942113 on 2016/04/13 by Gareth.Martin

	        Updating comment to clarify behaviour of Foliage Align-To-Normal when Random-Yaw is disabled.

	Change 2941030 on 2016/04/12 by Gareth.Martin

	        Cleanup and commenting

	Change 2940994 on 2016/04/12 by Gareth.Martin

	        Implement random scale option for Landscape Grass.
	        #jira UE-25743

	Change 2940993 on 2016/04/12 by Gareth.Martin

	        Remove unused BuildFlatTree function from HierarchicalInstancedStaticMeshComponent

	Change 2940150 on 2016/04/11 by Gareth.Martin

	        Harden UHierarchicalInstancedStaticMeshComponent::UpdateInstanceTransform

	Change 2940101 on 2016/04/11 by Gareth.Martin

	        Additional checks for bad static mesh when building the HISMC tree

Change 2945560 on 2016/04/15 by Rolando.Caloca

	DM - Fix for newer Vulkan sdks

Change 2945638 on 2016/04/15 by Chris.Babcock

	Fix permissions on uninstall script on Mac
	#jira UE-29236
	#ue4
	#android
	#lockdown Jack.Porter

Change 2945856 on 2016/04/15 by Rolando.Caloca

	DM - vk - Fix mapped allocations on mobile

#lockdown nick.penwarden

[CL 2945995 by Chris Babcock in Main branch]
2016-04-15 18:19:26 -04:00

1285 lines
47 KiB
C#

// Copyright 1998-2016 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;
using Microsoft.Win32;
namespace UnrealBuildTool
{
public class AndroidToolChain : UEToolChain
{
private FileReference ProjectFile;
// the number of the clang version being used to compile
private float ClangVersionFloat = 0;
// the list of architectures we will compile for
private List<string> Arches = null;
// the list of GPU architectures we will compile for
private List<string> GPUArchitectures = null;
// a list of all architecture+GPUArchitecture names (-armv7-es2, etc)
private List<string> AllComboNames = null;
static private Dictionary<string, string[]> AllArchNames = new Dictionary<string, string[]> {
{ "-armv7", new string[] { "armv7", "armeabi-v7a", } },
{ "-arm64", new string[] { "arm64", "arm64-v8a", } },
{ "-x86", new string[] { "x86", } },
{ "-x64", new string[] { "x64", "x86_64", } },
};
static private Dictionary<string, string[]> LibrariesToSkip = new Dictionary<string, string[]> {
{ "-armv7", new string[] { } },
{ "-arm64", new string[] { "nvToolsExt", "nvToolsExtStub", "oculus", "vrapi", "ovrkernel", "systemutils", "openglloader", "gpg", } },
{ "-x86", new string[] { "nvToolsExt", "nvToolsExtStub", "oculus", "vrapi", "ovrkernel", "systemutils", "openglloader", } },
{ "-x64", new string[] { "nvToolsExt", "nvToolsExtStub", "oculus", "vrapi", "ovrkernel", "systemutils", "openglloader", "gpg", } },
};
static private Dictionary<string, string[]> ModulesToSkip = new Dictionary<string, string[]> {
{ "-armv7", new string[] { } },
{ "-arm64", new string[] { "OnlineSubsystemGooglePlay", } },
{ "-x86", new string[] { } },
{ "-x64", new string[] { "OnlineSubsystemGooglePlay", } },
};
public AndroidToolChain(FileReference InProjectFile)
: base(CPPTargetPlatform.Android)
{
ProjectFile = InProjectFile;
string NDKPath = Environment.GetEnvironmentVariable("NDKROOT");
// don't register if we don't have an NDKROOT specified
if (String.IsNullOrEmpty(NDKPath))
{
throw new BuildException("NDKROOT is not specified; cannot use Android toolchain.");
}
NDKPath = NDKPath.Replace("\"", "");
string ClangVersion = "";
string GccVersion = "";
string ArchitecturePath = "";
string ArchitecturePathWindows32 = @"prebuilt/windows";
string ArchitecturePathWindows64 = @"prebuilt/windows-x86_64";
string ArchitecturePathMac = @"prebuilt/darwin-x86_64";
string ExeExtension = ".exe";
if (Directory.Exists(Path.Combine(NDKPath, ArchitecturePathWindows64)))
{
Log.TraceVerbose(" Found Windows 64 bit versions of toolchain");
ArchitecturePath = ArchitecturePathWindows64;
}
else if (Directory.Exists(Path.Combine(NDKPath, ArchitecturePathWindows32)))
{
Log.TraceVerbose(" Found Windows 32 bit versions of toolchain");
ArchitecturePath = ArchitecturePathWindows32;
}
else if (Directory.Exists(Path.Combine(NDKPath, ArchitecturePathMac)))
{
Log.TraceVerbose(" Found Mac versions of toolchain");
ArchitecturePath = ArchitecturePathMac;
ExeExtension = "";
}
else
{
throw new BuildException("Couldn't find 32-bit or 64-bit versions of the Android toolchain");
}
// prefer clang 3.6, but fall back if needed for now
if (Directory.Exists(Path.Combine(NDKPath, @"toolchains/llvm-3.6")))
{
ClangVersionFloat = 3.6f;
ClangVersion = "-3.6";
GccVersion = "4.9";
}
else if (Directory.Exists(Path.Combine(NDKPath, @"toolchains/llvm-3.5")))
{
ClangVersionFloat = 3.5f;
ClangVersion = "-3.5";
GccVersion = "4.9";
}
else if (Directory.Exists(Path.Combine(NDKPath, @"toolchains/llvm-3.3")))
{
ClangVersionFloat = 3.3f;
ClangVersion = "-3.3";
GccVersion = "4.8";
}
else if (Directory.Exists(Path.Combine(NDKPath, @"toolchains/llvm-3.1")))
{
ClangVersionFloat = 3.1f;
ClangVersion = "-3.1";
GccVersion = "4.6";
}
else if (Directory.Exists(Path.Combine(NDKPath, @"toolchains/llvm")))
{
// look for version in AndroidVersion.txt (fail if not found)
string VersionFilename = Path.Combine(NDKPath, @"toolchains/llvm/", ArchitecturePath, @"AndroidVersion.txt");
if (!File.Exists(VersionFilename))
{
throw new BuildException("Cannot find supported Android toolchain");
}
string[] VersionFile = File.ReadAllLines(VersionFilename);
string[] VersionParts = VersionFile[0].Split('.');
ClangVersionFloat = float.Parse(VersionParts[0] + "." + VersionParts[1], System.Globalization.CultureInfo.InvariantCulture);
ClangVersion = "";
GccVersion = "4.9";
}
else
{
throw new BuildException("Cannot find supported Android toolchain");
}
// set up the path to our toolchains
ClangPath = Path.Combine(NDKPath, @"toolchains/llvm" + ClangVersion, ArchitecturePath, @"bin/clang++" + ExeExtension);
ArPathArm = Path.Combine(NDKPath, @"toolchains/arm-linux-androideabi-" + GccVersion, ArchitecturePath, @"bin/arm-linux-androideabi-ar" + ExeExtension); //@todo android: use llvm-ar.exe instead?
ArPathArm64 = Path.Combine(NDKPath, @"toolchains/aarch64-linux-android-" + GccVersion, ArchitecturePath, @"bin/aarch64-linux-android-ar" + ExeExtension); //@todo android: use llvm-ar.exe instead?
ArPathx86 = Path.Combine(NDKPath, @"toolchains/x86-" + GccVersion, ArchitecturePath, @"bin/i686-linux-android-ar" + ExeExtension); //@todo android: verify x86 toolchain
ArPathx64 = Path.Combine(NDKPath, @"toolchains/x86_64-" + GccVersion, ArchitecturePath, @"bin/x86_64-linux-android-ar" + ExeExtension); //@todo android: verify x64 toolchain
// NDK setup (use no less than 21 for 64-bit targets)
int NDKApiLevelInt = GetNdkApiLevelInt();
string NDKApiLevel32Bit = GetNdkApiLevel();
string NDKApiLevel64Bit = NDKApiLevel32Bit;
if (NDKApiLevelInt < 21)
{
NDKApiLevel64Bit = "android-21";
}
// toolchain params
ToolchainParamsArm = " -target armv7-none-linux-androideabi" +
" --sysroot=\"" + Path.Combine(NDKPath, "platforms", NDKApiLevel32Bit, "arch-arm") + "\"" +
" -gcc-toolchain \"" + Path.Combine(NDKPath, @"toolchains/arm-linux-androideabi-" + GccVersion, ArchitecturePath) + "\"";
ToolchainParamsArm64 = " -target aarch64-none-linux-android" +
" --sysroot=\"" + Path.Combine(NDKPath, "platforms", NDKApiLevel64Bit, "arch-arm64") + "\"" +
" -gcc-toolchain \"" + Path.Combine(NDKPath, @"toolchains/aarch64-linux-android-" + GccVersion, ArchitecturePath) + "\"";
ToolchainParamsx86 = " -target i686-none-linux-android" +
" --sysroot=\"" + Path.Combine(NDKPath, "platforms", NDKApiLevel32Bit, "arch-x86") + "\"" +
" -gcc-toolchain \"" + Path.Combine(NDKPath, @"toolchains/x86-" + GccVersion, ArchitecturePath) + "\"";
ToolchainParamsx64 = " -target x86_64-none-linux-android" +
" --sysroot=\"" + Path.Combine(NDKPath, "platforms", NDKApiLevel64Bit, "arch-x86_64") + "\"" +
" -gcc-toolchain \"" + Path.Combine(NDKPath, @"toolchains\x86_64-" + GccVersion, ArchitecturePath) + "\"";
}
public void ParseArchitectures()
{
// look in ini settings for what platforms to compile for
ConfigCacheIni Ini = ConfigCacheIni.CreateConfigCacheIni(UnrealTargetPlatform.Android, "Engine", DirectoryReference.FromFile(ProjectFile));
Arches = new List<string>();
bool bBuild = true;
if (Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bBuildForArmV7", out bBuild) && bBuild)
{
Arches.Add("-armv7");
}
if (Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bBuildForArm64", out bBuild) && bBuild)
{
Arches.Add("-arm64");
}
if (Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bBuildForx86", out bBuild) && bBuild)
{
Arches.Add("-x86");
}
if (Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bBuildForx8664", out bBuild) && bBuild)
{
Arches.Add("-x64");
}
// force armv7 if something went wrong
if (Arches.Count == 0)
{
Arches.Add("-armv7");
}
// Parse selected GPU architectures
GPUArchitectures = new List<string>();
if (Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bBuildForES2", out bBuild) && bBuild)
{
GPUArchitectures.Add("-es2");
}
if (Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bBuildForES31", out bBuild) && bBuild)
{
GPUArchitectures.Add("-es31");
}
if (Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bBuildForGL4", out bBuild) && bBuild)
{
GPUArchitectures.Add("-gl4");
}
if (GPUArchitectures.Count == 0)
{
GPUArchitectures.Add("-es2");
}
AllComboNames = (from Arch in Arches
from GPUArch in GPUArchitectures
select Arch + GPUArch).ToList();
}
static public string GetGLESVersionFromGPUArch(string GPUArch)
{
GPUArch = GPUArch.Substring(1); // drop the '-' from the start
string GLESversion = "";
switch (GPUArch)
{
case "es2":
GLESversion = "0x00020000";
break;
case "es31":
GLESversion = "0x00030001";
break;
default:
GLESversion = "0x00020000";
break;
}
return GLESversion;
}
public override void SetUpGlobalEnvironment()
{
base.SetUpGlobalEnvironment();
ParseArchitectures();
}
public List<string> GetAllArchitectures()
{
if (Arches == null)
{
ParseArchitectures();
}
return Arches;
}
public List<string> GetAllGPUArchitectures()
{
if (GPUArchitectures == null)
{
ParseArchitectures();
}
return GPUArchitectures;
}
public int GetNdkApiLevelInt(int MinNdk = 19)
{
string NDKVersion = GetNdkApiLevel();
int NDKVersionInt = MinNdk;
if (NDKVersion.Contains("-"))
{
int Version;
if (int.TryParse(NDKVersion.Substring(NDKVersion.LastIndexOf('-') + 1), out Version))
{
if (Version > NDKVersionInt)
NDKVersionInt = Version;
}
}
return NDKVersionInt;
}
public string GetNdkApiLevel()
{
// ask the .ini system for what version to use
ConfigCacheIni Ini = ConfigCacheIni.CreateConfigCacheIni(UnrealTargetPlatform.Android, "Engine", DirectoryReference.FromFile(ProjectFile));
string NDKLevel;
Ini.GetString("/Script/AndroidPlatformEditor.AndroidSDKSettings", "NDKAPILevel", out NDKLevel);
if (NDKLevel == "latest")
{
// get a list of NDK platforms
string PlatformsDir = Environment.ExpandEnvironmentVariables("%NDKROOT%/platforms");
if (!Directory.Exists(PlatformsDir))
{
throw new BuildException("No platforms found in {0}", PlatformsDir);
}
// return the largest of them
NDKLevel = GetLargestApiLevel(Directory.GetDirectories(PlatformsDir));
}
return NDKLevel;
}
public string GetLargestApiLevel(string[] ApiLevels)
{
int LargestLevel = 0;
string LargestString = null;
// look for largest integer
foreach (string Level in ApiLevels)
{
string LocalLevel = Path.GetFileName(Level);
string[] Tokens = LocalLevel.Split("-".ToCharArray());
if (Tokens.Length >= 2)
{
try
{
int ParsedLevel = int.Parse(Tokens[1]);
// bigger? remember it
if (ParsedLevel > LargestLevel)
{
LargestLevel = ParsedLevel;
LargestString = LocalLevel;
}
}
catch (Exception)
{
// ignore poorly formed string
}
}
}
return LargestString;
}
string GetCLArguments_Global(CPPEnvironment CompileEnvironment, string Architecture)
{
string Result = "";
switch (Architecture)
{
case "-armv7": Result += ToolchainParamsArm; break;
case "-arm64": Result += ToolchainParamsArm64; break;
case "-x86": Result += ToolchainParamsx86; break;
case "-x64": Result += ToolchainParamsx64; break;
default: Result += ToolchainParamsArm; break;
}
// build up the commandline common to C and C++
Result += " -c";
Result += " -fdiagnostics-format=msvc";
Result += " -Wall";
Result += " -Wno-unused-variable";
// this will hide the warnings about static functions in headers that aren't used in every single .cpp file
Result += " -Wno-unused-function";
// this hides the "enumeration value 'XXXXX' not handled in switch [-Wswitch]" warnings - we should maybe remove this at some point and add UE_LOG(, Fatal, ) to default cases
Result += " -Wno-switch";
// 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";
//This will prevent the issue of warnings for unused private variables.
Result += " -Wno-unused-private-field";
Result += " -Wno-local-type-template-args"; // engine triggers this
Result += " -Wno-return-type-c-linkage"; // needed for PhysX
Result += " -Wno-reorder"; // member initialization order
Result += " -Wno-unknown-pragmas"; // probably should kill this one, sign of another issue in PhysX?
Result += " -Wno-invalid-offsetof"; // needed to suppress warnings about using offsetof on non-POD types.
Result += " -Wno-logical-op-parentheses"; // needed for external headers we can't change
if (CompileEnvironment.Config.bEnableShadowVariableWarning)
{
Result += " -Wshadow -Wno-error=shadow";
}
// new for clang4.5 warnings:
if (ClangVersionFloat >= 3.5f)
{
Result += " -Wno-undefined-bool-conversion"; // 'this' pointer cannot be null in well-defined C++ code; pointer may be assumed to always convert to true (if (this))
// we use this feature to allow static FNames.
Result += " -Wno-gnu-string-literal-operator-template";
}
if (ClangVersionFloat >= 3.6f)
{
Result += " -Wno-unused-local-typedef"; // clang is being overly strict here? PhysX headers trigger this.
Result += " -Wno-inconsistent-missing-override"; // these have to be suppressed for UE 4.8, should be fixed later.
}
// shipping builds will cause this warning with "ensure", so disable only in those case
if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Shipping)
{
Result += " -Wno-unused-value";
}
// debug info
if (CompileEnvironment.Config.bCreateDebugInfo)
{
Result += " -g2 -gdwarf-2";
}
// optimization level
if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug)
{
Result += " -O0";
}
else
{
if (UEBuildConfiguration.bCompileForSize)
{
Result += " -Oz";
}
else
{
Result += " -O3";
}
}
//@todo android: these are copied verbatim from UE3 and probably need adjustment
if (Architecture == "-armv7")
{
// Result += " -mthumb-interwork"; // Generates code which supports calling between ARM and Thumb instructions, w/o it you can't reliability use both together
Result += " -funwind-tables"; // Just generates any needed static data, affects no code
Result += " -fstack-protector"; // Emits extra code to check for buffer overflows
// Result += " -mlong-calls"; // Perform function calls by first loading the address of the function into a reg and then performing the subroutine call
Result += " -fno-strict-aliasing"; // Prevents unwanted or invalid optimizations that could produce incorrect code
Result += " -fpic"; // Generates position-independent code (PIC) suitable for use in a shared library
Result += " -fno-exceptions"; // Do not enable exception handling, generates extra code needed to propagate exceptions
Result += " -fno-rtti"; //
Result += " -fno-short-enums"; // Do not allocate to an enum type only as many bytes as it needs for the declared range of possible values
// Result += " -finline-limit=64"; // GCC limits the size of functions that can be inlined, this flag allows coarse control of this limit
// Result += " -Wno-psabi"; // Warn when G++ generates code that is probably not compatible with the vendor-neutral C++ ABI
Result += " -march=armv7-a";
Result += " -mfloat-abi=softfp";
Result += " -mfpu=vfpv3-d16"; //@todo android: UE3 was just vfp. arm7a should all support v3 with 16 registers
// Add flags for on-device debugging
if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug)
{
Result += " -fno-omit-frame-pointer"; // Disable removing the save/restore frame pointer for better debugging
if (ClangVersionFloat >= 3.6f)
{
Result += " -fno-function-sections"; // Improve breakpoint location
}
}
// Some switches interfere with on-device debugging
if (CompileEnvironment.Config.Target.Configuration != CPPTargetConfiguration.Debug)
{
Result += " -ffunction-sections"; // Places each function in its own section of the output file, linker may be able to perform opts to improve locality of reference
}
Result += " -fsigned-char"; // Treat chars as signed //@todo android: any concerns about ABI compatibility with libs here?
}
else if (Architecture == "-arm64")
{
Result += " -funwind-tables"; // Just generates any needed static data, affects no code
Result += " -fstack-protector"; // Emits extra code to check for buffer overflows
Result += " -fno-strict-aliasing"; // Prevents unwanted or invalid optimizations that could produce incorrect code
Result += " -fpic"; // Generates position-independent code (PIC) suitable for use in a shared library
Result += " -fno-exceptions"; // Do not enable exception handling, generates extra code needed to propagate exceptions
Result += " -fno-rtti"; //
Result += " -fno-short-enums"; // Do not allocate to an enum type only as many bytes as it needs for the declared range of possible values
Result += " -D__arm64__"; // for some reason this isn't defined and needed for PhysX
Result += " -march=armv8-a";
//Result += " -mfloat-abi=softfp";
//Result += " -mfpu=vfpv3-d16"; //@todo android: UE3 was just vfp. arm7a should all support v3 with 16 registers
// Some switches interfere with on-device debugging
if (CompileEnvironment.Config.Target.Configuration != CPPTargetConfiguration.Debug)
{
Result += " -ffunction-sections"; // Places each function in its own section of the output file, linker may be able to perform opts to improve locality of reference
}
Result += " -fsigned-char"; // Treat chars as signed //@todo android: any concerns about ABI compatibility with libs here?
}
else if (Architecture == "-x86")
{
Result += " -fstrict-aliasing";
Result += " -fno-omit-frame-pointer";
Result += " -fno-strict-aliasing";
Result += " -fno-short-enums";
Result += " -fno-exceptions";
Result += " -fno-rtti";
Result += " -march=atom";
}
else if (Architecture == "-x64")
{
Result += " -fstrict-aliasing";
Result += " -fno-omit-frame-pointer";
Result += " -fno-strict-aliasing";
Result += " -fno-short-enums";
Result += " -fno-exceptions";
Result += " -fno-rtti";
Result += " -march=atom";
}
return Result;
}
static string GetCompileArguments_CPP(bool bDisableOptimizations)
{
string Result = "";
Result += " -x c++";
Result += " -std=c++11";
// optimization level
if (bDisableOptimizations)
{
Result += " -O0";
}
else
{
Result += " -O3";
}
return Result;
}
static string GetCompileArguments_C(bool bDisableOptimizations)
{
string Result = "";
Result += " -x c";
// optimization level
if (bDisableOptimizations)
{
Result += " -O0";
}
else
{
Result += " -O3";
}
return Result;
}
static string GetCompileArguments_PCH(bool bDisableOptimizations)
{
string Result = "";
Result += " -x c++-header";
Result += " -std=c++11";
// optimization level
if (bDisableOptimizations)
{
Result += " -O0";
}
else
{
Result += " -O3";
}
return Result;
}
string GetLinkArguments(LinkEnvironment LinkEnvironment, string Architecture)
{
string Result = "";
Result += " -nostdlib";
Result += " -Wl,-shared,-Bsymbolic";
Result += " -Wl,--no-undefined";
if (Architecture == "-arm64")
{
Result += ToolchainParamsArm64;
Result += " -march=armv8-a";
}
else if (Architecture == "-x86")
{
Result += ToolchainParamsx86;
Result += " -march=atom";
}
else if (Architecture == "-x64")
{
Result += ToolchainParamsx64;
Result += " -march=atom";
}
else // if (Architecture == "-armv7")
{
Result += ToolchainParamsArm;
Result += " -march=armv7-a";
Result += " -Wl,--fix-cortex-a8"; // required to route around a CPU bug in some Cortex-A8 implementations
}
if (BuildConfiguration.bUseUnityBuild && ClangVersionFloat >= 3.6f && ClangVersionFloat < 3.8f)
{
Result += " -fuse-ld=gold"; // ld.gold is available in r10e (clang 3.6)
}
// make sure the DT_SONAME field is set properly (or we can a warning toast at startup on new Android)
Result += " -Wl,-soname,libUE4.so";
// verbose output from the linker
// Result += " -v";
return Result;
}
static string GetArArguments(LinkEnvironment LinkEnvironment)
{
string Result = "";
Result += " -r";
return Result;
}
static bool IsDirectoryForArch(string Dir, string Arch)
{
// make sure paths use one particular slash
Dir = Dir.Replace("\\", "/").ToLowerInvariant();
// look for other architectures in the Dir path, and fail if it finds it
foreach (var Pair in AllArchNames)
{
if (Pair.Key != Arch)
{
foreach (var ArchName in Pair.Value)
{
// if there's a directory in the path with a bad architecture name, reject it
if (Regex.IsMatch(Dir, "/" + ArchName + "$") || Regex.IsMatch(Dir, "/" + ArchName + "/"))
{
return false;
}
}
}
}
// if nothing was found, we are okay
return true;
}
static bool ShouldSkipModule(string ModuleName, string Arch)
{
foreach (var ModName in ModulesToSkip[Arch])
{
if (ModName == ModuleName)
{
return true;
}
}
// if nothing was found, we are okay
return false;
}
bool ShouldSkipLib(string Lib, string Arch, string GPUArchitecture)
{
// reject any libs we outright don't want to link with
foreach (var LibName in LibrariesToSkip[Arch])
{
if (LibName == Lib)
{
return true;
}
}
// if another architecture is in the filename, reject it
foreach (string ComboName in AllComboNames)
{
if (ComboName != Arch + GPUArchitecture)
{
if (Path.GetFileNameWithoutExtension(Lib).EndsWith(ComboName))
{
return true;
}
}
}
// if nothing was found, we are okay
return false;
}
static void ConditionallyAddNDKSourceFiles(List<FileItem> SourceFiles, string ModuleName)
{
// We need to add the extra glue and cpu code only to Launch module.
if (ModuleName.Equals("Launch"))
{
SourceFiles.Add(FileItem.GetItemByPath(Environment.GetEnvironmentVariable("NDKROOT") + "/sources/android/native_app_glue/android_native_app_glue.c"));
// Newer NDK cpu_features.c uses getauxval() which causes a SIGSEGV in libhoudini.so (ARM on Intel translator) in older versions of Houdini
// so we patch the file to use alternative methods of detecting CPU features if libhoudini.so is detected
// The basis for this patch is from here: https://android-review.googlesource.com/#/c/110650/
string CpuFeaturesPath = Environment.GetEnvironmentVariable("NDKROOT") + "/sources/android/cpufeatures/";
string CpuFeaturesPatchedFile = CpuFeaturesPath + "cpu-features-patched.c";
if (!File.Exists(CpuFeaturesPatchedFile))
{
// Either make a copy or patch it
string[] CpuFeaturesLines = File.ReadAllLines(CpuFeaturesPath + "cpu-features.c");
// Look for get_elf_hwcap_from_getauxval in the file
bool NeedsPatch = false;
int LineIndex;
for (LineIndex = 0; LineIndex < CpuFeaturesLines.Length; ++LineIndex)
{
if (CpuFeaturesLines[LineIndex].Contains("get_elf_hwcap_from_getauxval"))
{
NeedsPatch = true;
// Make sure it doesn't already have the patch (r10c and 10d have it already, but removed in 10e)
for (int LineIndex2 = LineIndex; LineIndex2 < CpuFeaturesLines.Length; ++LineIndex2)
{
if (CpuFeaturesLines[LineIndex2].Contains("has_houdini_binary_translator(void)"))
{
NeedsPatch = false;
break;
}
}
break;
}
}
// Apply patch or write unchanged
if (NeedsPatch)
{
List<string> CpuFeaturesList = new List<string>(CpuFeaturesLines);
// Skip down to section to add Houdini check function for arm
while (!CpuFeaturesList[++LineIndex].StartsWith("#if defined(__arm__)")) ;
CpuFeaturesList.Insert(++LineIndex, "/* Check Houdini Binary Translator is installed on the system.");
CpuFeaturesList.Insert(++LineIndex, " *");
CpuFeaturesList.Insert(++LineIndex, " * If this function returns 1, get_elf_hwcap_from_getauxval() function");
CpuFeaturesList.Insert(++LineIndex, " * will causes SIGSEGV while calling getauxval() function.");
CpuFeaturesList.Insert(++LineIndex, " */");
CpuFeaturesList.Insert(++LineIndex, "static int");
CpuFeaturesList.Insert(++LineIndex, "has_houdini_binary_translator(void) {");
CpuFeaturesList.Insert(++LineIndex, " int found = 0;");
CpuFeaturesList.Insert(++LineIndex, " if (access(\"/system/lib/libhoudini.so\", F_OK) != -1) {");
CpuFeaturesList.Insert(++LineIndex, " D(\"Found Houdini binary translator\\n\");");
CpuFeaturesList.Insert(++LineIndex, " found = 1;");
CpuFeaturesList.Insert(++LineIndex, " }");
CpuFeaturesList.Insert(++LineIndex, " return found;");
CpuFeaturesList.Insert(++LineIndex, "}");
CpuFeaturesList.Insert(++LineIndex, "");
// Add the Houdini check call
while (!CpuFeaturesList[++LineIndex].Contains("/* Extract the list of CPU features from ELF hwcaps */")) ;
CpuFeaturesList.Insert(LineIndex++, " /* Check Houdini binary translator is installed */");
CpuFeaturesList.Insert(LineIndex++, " int has_houdini = has_houdini_binary_translator();");
CpuFeaturesList.Insert(LineIndex++, "");
// Make the get_elf_hwcap_from_getauxval() calls conditional
while (!CpuFeaturesList[++LineIndex].Contains("hwcaps = get_elf_hwcap_from_getauxval(AT_HWCAP);")) ;
CpuFeaturesList.Insert(LineIndex++, " if (!has_houdini) {");
CpuFeaturesList.Insert(++LineIndex, " }");
while (!CpuFeaturesList[++LineIndex].Contains("hwcaps2 = get_elf_hwcap_from_getauxval(AT_HWCAP2);")) ;
CpuFeaturesList.Insert(LineIndex++, " if (!has_houdini) {");
CpuFeaturesList.Insert(++LineIndex, " }");
File.WriteAllLines(CpuFeaturesPatchedFile, CpuFeaturesList.ToArray());
}
else
{
File.WriteAllLines(CpuFeaturesPatchedFile, CpuFeaturesLines);
}
}
SourceFiles.Add(FileItem.GetItemByPath(CpuFeaturesPatchedFile));
}
}
void GenerateEmptyLinkFunctionsForRemovedModules(List<FileItem> SourceFiles, string ModuleName, DirectoryReference OutputDirectory)
{
// Only add to UELinkerFixups module
if (!ModuleName.Equals("Launch"))
{
return;
}
string LinkerExceptionsName = "../UELinkerExceptions";
FileReference LinkerExceptionsCPPFilename = FileReference.Combine(OutputDirectory, LinkerExceptionsName + ".cpp");
// Create the cpp filename
if (!LinkerExceptionsCPPFilename.Exists())
{
// Create a dummy file in case it doesn't exist yet so that the module does not complain it's not there
ResponseFile.Create(LinkerExceptionsCPPFilename, new List<string>());
}
var Result = new List<string>();
foreach (string Arch in Arches)
{
switch (Arch)
{
case "-armv7": Result.Add("#if PLATFORM_ANDROID_ARM"); break;
case "-arm64": Result.Add("#if PLATFORM_ANDROID_ARM64"); break;
case "-x86": Result.Add("#if PLATFORM_ANDROID_X86"); break;
case "-x64": Result.Add("#if PLATFORM_ANDROID_X64"); break;
default: Result.Add("#if PLATFORM_ANDROID_ARM"); break;
}
foreach (var ModName in ModulesToSkip[Arch])
{
Result.Add(" void EmptyLinkFunctionForStaticInitialization" + ModName + "(){}");
}
Result.Add("#endif");
}
// Determine if the file changed. Write it if it either doesn't exist or the contents are different.
bool bShouldWriteFile = true;
if (LinkerExceptionsCPPFilename.Exists())
{
string[] ExistingExceptionText = File.ReadAllLines(LinkerExceptionsCPPFilename.FullName);
string JoinedNewContents = string.Join("", Result.ToArray());
string JoinedOldContents = string.Join("", ExistingExceptionText);
bShouldWriteFile = (JoinedNewContents != JoinedOldContents);
}
// If we determined that we should write the file, write it now.
if (bShouldWriteFile)
{
ResponseFile.Create(LinkerExceptionsCPPFilename, Result);
}
SourceFiles.Add(FileItem.GetItemByFileReference(LinkerExceptionsCPPFilename));
}
// cache the location of NDK tools
static string ClangPath;
static string ToolchainParamsArm;
static string ToolchainParamsArm64;
static string ToolchainParamsx86;
static string ToolchainParamsx64;
static string ArPathArm;
static string ArPathArm64;
static string ArPathx86;
static string ArPathx64;
static public string GetStripExecutablePath(string UE4Arch)
{
string StripPath;
switch (UE4Arch)
{
case "-armv7": StripPath = ArPathArm; break;
case "-arm64": StripPath = ArPathArm64; break;
case "-x86": StripPath = ArPathx86; break;
case "-x64": StripPath = ArPathx64; break;
default: StripPath = ArPathArm; break;
}
return StripPath.Replace("-ar", "-strip");
}
static private bool bHasPrintedApiLevel = false;
public override CPPOutput CompileCPPFiles(UEBuildTarget Target, CPPEnvironment CompileEnvironment, List<FileItem> SourceFiles, string ModuleName)
{
if (Arches.Count == 0)
{
throw new BuildException("At least one architecture (armv7, x86, etc) needs to be selected in the project settings to build");
}
if (!bHasPrintedApiLevel)
{
Console.WriteLine("Compiling Native code with NDK API '{0}'", GetNdkApiLevel());
bHasPrintedApiLevel = true;
}
string BaseArguments = "";
if (CompileEnvironment.Config.PrecompiledHeaderAction != PrecompiledHeaderAction.Create)
{
BaseArguments += " -Werror";
}
// Directly added NDK files for NDK extensions
ConditionallyAddNDKSourceFiles(SourceFiles, ModuleName);
// Deal with dynamic modules removed by architecture
GenerateEmptyLinkFunctionsForRemovedModules(SourceFiles, ModuleName, CompileEnvironment.Config.OutputDirectory);
// Add preprocessor definitions to the argument list.
foreach (string Definition in CompileEnvironment.Config.Definitions)
{
BaseArguments += string.Format(" -D \"{0}\"", Definition);
}
var BuildPlatform = UEBuildPlatform.GetBuildPlatformForCPPTargetPlatform(CompileEnvironment.Config.Target.Platform);
var NDKRoot = Environment.GetEnvironmentVariable("NDKROOT").Replace("\\", "/");
string BasePCHName = "";
var PCHExtension = UEBuildPlatform.GetBuildPlatform(UnrealTargetPlatform.Android).GetBinaryExtension(UEBuildBinaryType.PrecompiledHeader);
if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Include)
{
BasePCHName = RemoveArchName(CompileEnvironment.PrecompiledHeaderFile.AbsolutePath).Replace(PCHExtension, "");
}
// Create a compile action for each source file.
CPPOutput Result = new CPPOutput();
foreach (string Arch in Arches)
{
if (ShouldSkipModule(ModuleName, Arch))
{
continue;
}
foreach (string GPUArchitecture in GPUArchitectures)
{
// which toolchain to use
string Arguments = GetCLArguments_Global(CompileEnvironment, Arch) + BaseArguments;
switch (Arch)
{
case "-armv7": Arguments += " -DPLATFORM_64BITS=0 -DPLATFORM_ANDROID_ARM=1"; break;
case "-arm64": Arguments += " -DPLATFORM_64BITS=1 -DPLATFORM_ANDROID_ARM64=1"; break;
case "-x86": Arguments += " -DPLATFORM_64BITS=0 -DPLATFORM_ANDROID_X86=1"; break;
case "-x64": Arguments += " -DPLATFORM_64BITS=1 -DPLATFORM_ANDROID_X64=1"; break;
default: Arguments += " -DPLATFORM_64BITS=0 -DPLATFORM_ANDROID_ARM=1"; break;
}
if (GPUArchitecture == "-gl4")
{
Arguments += " -DPLATFORM_ANDROIDGL4=1";
}
else if (GPUArchitecture == "-es31")
{
Arguments += " -DPLATFORM_ANDROIDES31=1";
}
// which PCH file to include
string PCHArguments = "";
if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Include)
{
// Add the precompiled header file's path to the include path so Clang can find it.
// This needs to be before the other include paths to ensure Clang uses it instead of the source header file.
PCHArguments += string.Format(" -include \"{0}\"", InlineArchName(BasePCHName, Arch, GPUArchitecture));
}
// Add include paths to the argument list (filtered by architecture)
foreach (string IncludePath in CompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths)
{
if (IsDirectoryForArch(IncludePath, Arch))
{
Arguments += string.Format(" -I\"{0}\"", IncludePath);
}
}
foreach (string IncludePath in CompileEnvironment.Config.CPPIncludeInfo.IncludePaths)
{
if (IsDirectoryForArch(IncludePath, Arch))
{
Arguments += string.Format(" -I\"{0}\"", IncludePath);
}
}
foreach (FileItem SourceFile in SourceFiles)
{
Action CompileAction = new Action(ActionType.Compile);
string FileArguments = "";
bool bIsPlainCFile = Path.GetExtension(SourceFile.AbsolutePath).ToUpperInvariant() == ".C";
bool bDisableShadowWarning = false;
// should we disable optimizations on this file?
// @todo android - We wouldn't need this if we could disable optimizations per function (via pragma)
bool bDisableOptimizations = false;// SourceFile.AbsolutePath.ToUpperInvariant().IndexOf("\\SLATE\\") != -1;
if (bDisableOptimizations && CompileEnvironment.Config.Target.Configuration != CPPTargetConfiguration.Debug)
{
Log.TraceWarning("Disabling optimizations on {0}", SourceFile.AbsolutePath);
}
bDisableOptimizations = bDisableOptimizations || CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug;
// Add C or C++ specific compiler arguments.
if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Create)
{
FileArguments += GetCompileArguments_PCH(bDisableOptimizations);
}
else if (bIsPlainCFile)
{
FileArguments += GetCompileArguments_C(bDisableOptimizations);
// remove shadow variable warnings for NDK files
if (SourceFile.AbsolutePath.Replace("\\", "/").StartsWith(NDKRoot))
{
bDisableShadowWarning = true;
}
}
else
{
FileArguments += GetCompileArguments_CPP(bDisableOptimizations);
// only use PCH for .cpp files
FileArguments += PCHArguments;
}
// Add the C++ source file and its included files to the prerequisite item list.
AddPrerequisiteSourceFile(Target, BuildPlatform, CompileEnvironment, SourceFile, CompileAction.PrerequisiteItems);
if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Create)
{
// Add the precompiled header file to the produced item list.
FileItem PrecompiledHeaderFile = FileItem.GetItemByFileReference(
FileReference.Combine(
CompileEnvironment.Config.OutputDirectory,
Path.GetFileName(InlineArchName(SourceFile.AbsolutePath, Arch, GPUArchitecture) + PCHExtension)
)
);
CompileAction.ProducedItems.Add(PrecompiledHeaderFile);
Result.PrecompiledHeaderFile = PrecompiledHeaderFile;
// Add the parameters needed to compile the precompiled header file to the command-line.
FileArguments += string.Format(" -o \"{0}\"", PrecompiledHeaderFile.AbsolutePath, false);
}
else
{
if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Include)
{
CompileAction.bIsUsingPCH = true;
FileItem ArchPrecompiledHeaderFile = FileItem.GetItemByPath(InlineArchName(BasePCHName, Arch, GPUArchitecture) + PCHExtension);
CompileAction.PrerequisiteItems.Add(ArchPrecompiledHeaderFile);
}
var ObjectFileExtension = UEBuildPlatform.GetBuildPlatform(UnrealTargetPlatform.Android).GetBinaryExtension(UEBuildBinaryType.Object);
// Add the object file to the produced item list.
FileItem ObjectFile = FileItem.GetItemByFileReference(
FileReference.Combine(
CompileEnvironment.Config.OutputDirectory,
InlineArchName(Path.GetFileName(SourceFile.AbsolutePath) + ObjectFileExtension, Arch, GPUArchitecture)
)
);
CompileAction.ProducedItems.Add(ObjectFile);
Result.ObjectFiles.Add(ObjectFile);
FileArguments += string.Format(" -o \"{0}\"", ObjectFile.AbsolutePath, false);
}
// Add the source file path to the command-line.
FileArguments += string.Format(" \"{0}\"", SourceFile.AbsolutePath);
// Build a full argument list
string AllArguments = Arguments + FileArguments + CompileEnvironment.Config.AdditionalArguments;
AllArguments = ActionThread.ExpandEnvironmentVariables(AllArguments);
AllArguments = AllArguments.Replace("\\", "/");
// Remove shadow warning for this file if requested
if (bDisableShadowWarning)
{
int WarningIndex = AllArguments.IndexOf(" -Wshadow");
if (WarningIndex > 0)
{
AllArguments = AllArguments.Remove(WarningIndex, 9);
}
}
// Create the response file
FileReference ResponseFileName = CompileAction.ProducedItems[0].Reference + ".response";
string ResponseArgument = string.Format("@\"{0}\"", ResponseFile.Create(ResponseFileName, new List<string> { AllArguments }).FullName);
CompileAction.WorkingDirectory = UnrealBuildTool.EngineSourceDirectory.FullName;
CompileAction.CommandPath = ClangPath;
CompileAction.CommandArguments = ResponseArgument;
CompileAction.StatusDescription = string.Format("{0} [{1}-{2}]", Path.GetFileName(SourceFile.AbsolutePath), Arch.Replace("-", ""), GPUArchitecture.Replace("-", ""));
// 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 pre-compiled headers as it is the critical path task.
CompileAction.bCanExecuteRemotely =
CompileEnvironment.Config.PrecompiledHeaderAction != PrecompiledHeaderAction.Create ||
BuildConfiguration.bAllowRemotelyCompiledPCHs;
}
}
}
return Result;
}
public override FileItem LinkFiles(LinkEnvironment LinkEnvironment, bool bBuildImportLibraryOnly)
{
return null;
}
static public string InlineArchName(string Pathname, string Arch, string GPUArchitecture)
{
return Path.Combine(Path.GetDirectoryName(Pathname), Path.GetFileNameWithoutExtension(Pathname) + Arch + GPUArchitecture + Path.GetExtension(Pathname));
}
public string RemoveArchName(string Pathname)
{
// remove all architecture names
foreach (string Arch in GetAllArchitectures())
{
foreach (string GPUArchitecture in GetAllGPUArchitectures())
{
Pathname = Path.Combine(Path.GetDirectoryName(Pathname), Path.GetFileName(Pathname).Replace(Arch + GPUArchitecture, ""));
}
}
return Pathname;
}
public override FileItem[] LinkAllFiles(LinkEnvironment LinkEnvironment, bool bBuildImportLibraryOnly)
{
List<FileItem> Outputs = new List<FileItem>();
for (int ArchIndex = 0; ArchIndex < Arches.Count; ArchIndex++)
{
string Arch = Arches[ArchIndex];
for (int GPUArchIndex = 0; GPUArchIndex < GPUArchitectures.Count; GPUArchIndex++)
{
string GPUArchitecture = GPUArchitectures[GPUArchIndex];
int OutputPathIndex = ArchIndex * GPUArchitectures.Count + GPUArchIndex;
// Android will have an array of outputs
if (LinkEnvironment.Config.OutputFilePaths.Count < OutputPathIndex ||
!LinkEnvironment.Config.OutputFilePaths[OutputPathIndex].GetFileNameWithoutExtension().EndsWith(Arch + GPUArchitecture))
{
throw new BuildException("The OutputFilePaths array didn't match the Arches array in AndroidToolChain.LinkAllFiles");
}
// Create an action that invokes the linker.
Action LinkAction = new Action(ActionType.Link);
LinkAction.WorkingDirectory = UnrealBuildTool.EngineSourceDirectory.FullName;
if (LinkEnvironment.Config.bIsBuildingLibrary)
{
switch (Arch)
{
case "-armv7": LinkAction.CommandPath = ArPathArm; break;
case "-arm64": LinkAction.CommandPath = ArPathArm64; break;
case "-x86": LinkAction.CommandPath = ArPathx86; ; break;
case "-x64": LinkAction.CommandPath = ArPathx64; ; break;
default: LinkAction.CommandPath = ArPathArm; ; break;
}
}
else
{
LinkAction.CommandPath = ClangPath;
}
string LinkerPath = LinkAction.WorkingDirectory;
LinkAction.WorkingDirectory = LinkEnvironment.Config.IntermediateDirectory.FullName;
// Get link arguments.
LinkAction.CommandArguments = LinkEnvironment.Config.bIsBuildingLibrary ? GetArArguments(LinkEnvironment) : GetLinkArguments(LinkEnvironment, Arch);
// Add the output file as a production of the link action.
FileItem OutputFile;
OutputFile = FileItem.GetItemByFileReference(LinkEnvironment.Config.OutputFilePaths[OutputPathIndex]);
Outputs.Add(OutputFile);
LinkAction.ProducedItems.Add(OutputFile);
LinkAction.StatusDescription = string.Format("{0}", Path.GetFileName(OutputFile.AbsolutePath));
// LinkAction.bPrintDebugInfo = true;
// Add the output file to the command-line.
if (LinkEnvironment.Config.bIsBuildingLibrary)
{
LinkAction.CommandArguments += string.Format(" \"{0}\"", OutputFile.AbsolutePath);
}
else
{
LinkAction.CommandArguments += string.Format(" -o \"{0}\"", OutputFile.AbsolutePath);
}
// Add the input files to a response file, and pass the response file on the command-line.
List<string> InputFileNames = new List<string>();
foreach (FileItem InputFile in LinkEnvironment.InputFiles)
{
// make sure it's for current Arch
if (Path.GetFileNameWithoutExtension(InputFile.AbsolutePath).EndsWith(Arch + GPUArchitecture))
{
string AbsolutePath = InputFile.AbsolutePath.Replace("\\", "/");
AbsolutePath = AbsolutePath.Replace(LinkEnvironment.Config.IntermediateDirectory.FullName.Replace("\\", "/"), "");
AbsolutePath = AbsolutePath.TrimStart(new char[] { '/' });
InputFileNames.Add(string.Format("\"{0}\"", AbsolutePath));
LinkAction.PrerequisiteItems.Add(InputFile);
}
}
FileReference ResponseFileName = GetResponseFileName(LinkEnvironment, OutputFile);
LinkAction.CommandArguments += string.Format(" @\"{0}\"", ResponseFile.Create(ResponseFileName, InputFileNames));
// libs don't link in other libs
if (!LinkEnvironment.Config.bIsBuildingLibrary)
{
// Add the library paths to the argument list.
foreach (string LibraryPath in LinkEnvironment.Config.LibraryPaths)
{
// LinkerPaths could be relative or absolute
string AbsoluteLibraryPath = ActionThread.ExpandEnvironmentVariables(LibraryPath);
if (IsDirectoryForArch(AbsoluteLibraryPath, Arch))
{
// environment variables aren't expanded when using the $( style
if (Path.IsPathRooted(AbsoluteLibraryPath) == false)
{
AbsoluteLibraryPath = Path.Combine(LinkerPath, AbsoluteLibraryPath);
}
LinkAction.CommandArguments += string.Format(" -L\"{0}\"", AbsoluteLibraryPath);
}
}
// add libraries in a library group
LinkAction.CommandArguments += string.Format(" -Wl,--start-group");
foreach (string AdditionalLibrary in LinkEnvironment.Config.AdditionalLibraries)
{
if (!ShouldSkipLib(AdditionalLibrary, Arch, GPUArchitecture))
{
if (String.IsNullOrEmpty(Path.GetDirectoryName(AdditionalLibrary)))
{
LinkAction.CommandArguments += string.Format(" \"-l{0}\"", AdditionalLibrary);
}
else
{
// full pathed libs are compiled by us, so we depend on linking them
LinkAction.CommandArguments += string.Format(" \"{0}\"", Path.GetFullPath(AdditionalLibrary));
LinkAction.PrerequisiteItems.Add(FileItem.GetItemByPath(AdditionalLibrary));
}
}
}
LinkAction.CommandArguments += string.Format(" -Wl,--end-group");
}
// Add the additional arguments specified by the environment.
LinkAction.CommandArguments += LinkEnvironment.Config.AdditionalArguments;
LinkAction.CommandArguments = LinkAction.CommandArguments.Replace("\\", "/");
// Only execute linking on the local PC.
LinkAction.bCanExecuteRemotely = false;
}
}
return Outputs.ToArray();
}
public override void ModifyBuildProducts(UEBuildBinary Binary, Dictionary<FileReference, BuildProductType> BuildProducts)
{
// the binary will have all of the .so's in the output files, we need to trim down to the shared apk (which is what needs to go into the manifest)
if (Binary.Config.Type != UEBuildBinaryType.StaticLibrary)
{
foreach (FileReference BinaryPath in Binary.Config.OutputFilePaths)
{
FileReference ApkFile = BinaryPath.ChangeExtension(".apk");
BuildProducts.Add(ApkFile, BuildProductType.Executable);
}
}
}
public override void CompileCSharpProject(CSharpEnvironment CompileEnvironment, FileReference ProjectFileName, FileReference DestinationFile)
{
throw new BuildException("Android cannot compile C# files");
}
public static void OutputReceivedDataEventHandler(Object Sender, DataReceivedEventArgs Line)
{
if ((Line != null) && (Line.Data != null))
{
Log.TraceInformation(Line.Data);
}
}
public override void StripSymbols(string SourceFileName, string TargetFileName)
{
File.Copy(SourceFileName, TargetFileName, true);
ProcessStartInfo StartInfo = new ProcessStartInfo();
if (SourceFileName.Contains("-armv7"))
{
StartInfo.FileName = ArPathArm.Replace("-ar.exe", "-strip.exe");
}
else
{
throw new BuildException("Couldn't determine Android architecture to strip symbols from {0}", SourceFileName);
}
StartInfo.Arguments = "--strip-debug " + TargetFileName;
StartInfo.UseShellExecute = false;
StartInfo.CreateNoWindow = true;
Utils.RunLocalProcessAndLogOutput(StartInfo);
}
};
}