Files
UnrealEngineUWP/Engine/Source/Programs/UnrealBuildTool/ToolChain/AppleToolChain.cs
jonathan adamczewski 94b14ee042 UnrealBuildTool: move some path constants into BuildUtilities
RootDirectory, EngineDirectory, UnrealBuildToolPath are now found in BuildUtilities' UnrealBuild namesapce.

The way these are computed has changed. Previously, it was assumed that the application is UnrealBuildTool, and paths were constructed relative to that assembly.

Now, the assumption is that the process is located under a "Engine/Build/DotNET" sub-path and paths are constructed relative to that.

#jira none

[CL 16607440 by jonathan adamczewski in ue5-main branch]
2021-06-09 12:54:42 -04:00

302 lines
9.0 KiB
C#

// Copyright Epic Games, Inc. All Rights Reserved.
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Diagnostics;
using System.Text;
using EpicGames.Core;
using System.Text.RegularExpressions;
using UnrealBuildBase;
#nullable disable
namespace UnrealBuildTool
{
abstract class AppleToolChainSettings
{
/// <summary>
/// Which developer directory to root from? If this is "xcode-select", UBT will query for the currently selected Xcode
/// </summary>
public string XcodeDeveloperDir = "xcode-select";
public AppleToolChainSettings(bool bVerbose)
{
SelectXcode(ref XcodeDeveloperDir, bVerbose);
}
private static void SelectXcode(ref string DeveloperDir, bool bVerbose)
{
string Reason = "hardcoded";
if (DeveloperDir == "xcode-select")
{
Reason = "xcode-select";
// on the Mac, run xcode-select directly
DeveloperDir = Utils.RunLocalProcessAndReturnStdOut("xcode-select", "--print-path");
// make sure we get a full path
if (Directory.Exists(DeveloperDir) == false)
{
throw new BuildException("Selected Xcode ('{0}') doesn't exist, cannot continue.", DeveloperDir);
}
if (DeveloperDir.EndsWith("/") == false)
{
// we expect this to end with a slash
DeveloperDir += "/";
}
}
if (bVerbose && !DeveloperDir.StartsWith("/Applications/Xcode.app"))
{
Log.TraceInformationOnce("Compiling with non-standard Xcode ({0}): {1}", Reason, DeveloperDir);
}
// Installed engine requires Xcode 11
if (UnrealBuildTool.IsEngineInstalled())
{
string XcodeBuilderVersionOutput = Utils.RunLocalProcessAndReturnStdOut("xcodebuild", "-version");
if (XcodeBuilderVersionOutput.Length > 10)
{
string[] Version = XcodeBuilderVersionOutput.Substring(6, 4).Split('.');
if (Version.Length == 2)
{
if (int.Parse(Version[0]) < 11)
{
throw new BuildException("Building for macOS, iOS and tvOS requires Xcode 11 or newer, Xcode " + Version[0] + "." + Version[1] + " detected");
}
}
else
{
Log.TraceWarning("Failed to query Xcode version");
}
}
else
{
Log.TraceWarning("Failed to query Xcode version");
}
}
}
protected void SelectSDK(string BaseSDKDir, string OSPrefix, ref string PlatformSDKVersion, bool bVerbose)
{
if (PlatformSDKVersion == "latest")
{
PlatformSDKVersion = "";
try
{
// on the Mac, we can just get the directory name
string[] SubDirs = System.IO.Directory.GetDirectories(BaseSDKDir);
// loop over the subdirs and parse out the version
int MaxSDKVersionMajor = 0;
int MaxSDKVersionMinor = 0;
string MaxSDKVersionString = null;
foreach (string SubDir in SubDirs)
{
string SubDirName = Path.GetFileNameWithoutExtension(SubDir);
if (SubDirName.StartsWith(OSPrefix))
{
// get the SDK version from the directory name
string SDKString = SubDirName.Replace(OSPrefix, "");
int Major = 0;
int Minor = 0;
// parse it into whole and fractional parts (since 10.10 > 10.9 in versions, but not in math)
try
{
string[] Tokens = SDKString.Split(".".ToCharArray());
if (Tokens.Length == 2)
{
Major = int.Parse(Tokens[0]);
Minor = int.Parse(Tokens[1]);
}
}
catch (Exception)
{
// weirdly formatted SDKs
continue;
}
// update largest SDK version number
if (Major > MaxSDKVersionMajor || (Major == MaxSDKVersionMajor && Minor > MaxSDKVersionMinor))
{
MaxSDKVersionString = SDKString;
MaxSDKVersionMajor = Major;
MaxSDKVersionMinor = Minor;
}
}
}
// use the largest version
if (MaxSDKVersionString != null)
{
PlatformSDKVersion = MaxSDKVersionString;
}
}
catch (Exception Ex)
{
// on any exception, just use the backup version
Log.TraceInformation("Triggered an exception while looking for SDK directory in Xcode.app");
Log.TraceInformation("{0}", Ex.ToString());
}
}
// make sure we have a valid SDK directory
if (!RuntimePlatform.IsWindows && !Directory.Exists(Path.Combine(BaseSDKDir, OSPrefix + PlatformSDKVersion + ".sdk")))
{
throw new BuildException("Invalid SDK {0}{1}.sdk, not found in {2}", OSPrefix, PlatformSDKVersion, BaseSDKDir);
}
if (bVerbose && !ProjectFileGenerator.bGenerateProjectFiles)
{
Log.TraceInformation("Compiling with {0} SDK {1}", OSPrefix, PlatformSDKVersion);
}
}
}
abstract class AppleToolChain : ISPCToolChain
{
protected FileReference ProjectFile;
public AppleToolChain(FileReference InProjectFile)
{
ProjectFile = InProjectFile;
}
protected DirectoryReference GetMacDevSrcRoot()
{
return UnrealBuildTool.EngineSourceDirectory;
}
protected void StripSymbolsWithXcode(FileReference SourceFile, FileReference TargetFile, string ToolchainDir)
{
if (SourceFile != TargetFile)
{
// Strip command only works in place so we need to copy original if target is different
File.Copy(SourceFile.FullName, TargetFile.FullName, true);
}
ProcessStartInfo StartInfo = new ProcessStartInfo();
StartInfo.FileName = Path.Combine(ToolchainDir, "strip");
StartInfo.Arguments = String.Format("\"{0}\" -S", TargetFile.FullName);
StartInfo.UseShellExecute = false;
StartInfo.CreateNoWindow = true;
Utils.RunLocalProcessAndLogOutput(StartInfo);
}
static Version ClangVersion = null;
static string FullClangVersion = null;
protected Version GetClangVersion()
{
if (ClangVersion == null)
{
FileReference ClangLocation = new FileReference("/usr/bin/clang");
ClangVersion = RunToolAndCaptureVersion(ClangLocation, "--version");
}
return ClangVersion;
}
protected string GetFullClangVersion()
{
if (FullClangVersion == null)
{
// get the first line that has the full clang and build number
FileReference ClangLocation = new FileReference("/usr/bin/clang");
FullClangVersion = RunToolAndCaptureOutput(ClangLocation, "--version", "(.*)");
}
return FullClangVersion;
}
protected static string GetCppStandardCompileArgument(CppStandardVersion Version)
{
switch (Version)
{
case CppStandardVersion.Cpp14:
return " -std=c++14";
case CppStandardVersion.Cpp17:
return " -std=c++17";
case CppStandardVersion.Latest:
case CppStandardVersion.Cpp20:
return " -std=c++20";
default:
throw new BuildException($"Unsupported C++ standard type set: {Version}");
}
}
protected string GetDsymutilPath(out string ExtraOptions, bool bIsForLTOBuild=false)
{
FileReference DsymutilLocation = new FileReference("/usr/bin/dsymutil");
// dsymutil before 10.0.1 has a bug that causes issues, it's fixed in autosdks but not everyone has those set up so for the timebeing we have
// a version in P4 - first determine if we need it
string DsymutilVersionString = Utils.RunLocalProcessAndReturnStdOut(DsymutilLocation.FullName, "-version");
bool bUseInstalledDsymutil = true;
int Major = 0, Minor = 0, Patch = 0;
// tease out the version number
string[] Tokens = DsymutilVersionString.Split(" ".ToCharArray());
// sanity check
if (Tokens.Length < 4 || Tokens[3].Contains(".") == false)
{
Log.TraceInformationOnce("Unable to parse dsymutil version out of: {0}", DsymutilVersionString);
}
else
{
string[] Versions = Tokens[3].Split(".".ToCharArray());
if (Versions.Length < 3)
{
Log.TraceInformationOnce("Unable to parse version token: {0}", Tokens[3]);
}
else
{
if (!int.TryParse(Versions[0], out Major) || !int.TryParse(Versions[1], out Minor) || !int.TryParse(Versions[2], out Patch))
{
Log.TraceInformationOnce("Unable to parse version tokens: {0}", Tokens[3]);
}
else
{
if (Major < 12)
{
Log.TraceInformationOnce("dsymutil version is {0}.{1}.{2}. Using bundled version.", Major, Minor, Patch);
bUseInstalledDsymutil = false;
}
}
}
}
// if the installed one is too old, use a fixed up one if it can
if (bUseInstalledDsymutil == false)
{
FileReference PatchedDsymutilLocation = FileReference.Combine(UnrealBuild.EngineDirectory, "Restricted/NotForLicensees/Binaries/Mac/LLVM/bin/dsymutil");
if (File.Exists(PatchedDsymutilLocation.FullName))
{
DsymutilLocation = PatchedDsymutilLocation;
}
DirectoryReference AutoSdkDir;
if (UEBuildPlatformSDK.TryGetHostPlatformAutoSDKDir(out AutoSdkDir))
{
FileReference AutoSdkDsymutilLocation = FileReference.Combine(AutoSdkDir, "Mac", "LLVM", "bin", "dsymutil");
if (FileReference.Exists(AutoSdkDsymutilLocation))
{
DsymutilLocation = AutoSdkDsymutilLocation;
}
}
}
// 10.0.1 has an issue with LTO builds where we need to limit the number of threads
ExtraOptions = (bIsForLTOBuild && Major == 10 && Minor == 0 && Patch == 1) ? "-j 1" : "";
return DsymutilLocation.FullName;
}
};
}