You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
292 lines
12 KiB
C#
292 lines
12 KiB
C#
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
using System;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.IO;
|
|
using AutomationTool;
|
|
using UnrealBuildTool;
|
|
using EpicGames.Core;
|
|
using UnrealBuildBase;
|
|
using System.Diagnostics;
|
|
using System.Collections.Generic;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
public abstract class ApplePlatform : Platform
|
|
{
|
|
public ApplePlatform(UnrealTargetPlatform TargetPlatform)
|
|
: base(TargetPlatform)
|
|
{
|
|
}
|
|
|
|
#region SDK
|
|
|
|
public override bool GetSDKInstallCommand(out string Command, out string Params, ref bool bRequiresPrivilegeElevation, ref bool bCreateWindow, ITurnkeyContext TurnkeyContext)
|
|
{
|
|
Command = "";
|
|
Params = "";
|
|
|
|
if (UnrealBuildTool.BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac)
|
|
{
|
|
TurnkeyContext.Log("Moving your original Xcode application from /Applications to the Trash, and unzipping the new version into /Applications");
|
|
|
|
// put current Xcode in the trash, and unzip a new one. Xcode in the dock will have to be fixed up tho!
|
|
Command = "osascript";
|
|
Params =
|
|
" -e \"try\"" +
|
|
" -e \"tell application \\\"Finder\\\" to delete POSIX file \\\"/Applications/Xcode.app\\\"\"" +
|
|
" -e \"end try\"" +
|
|
" -e \"do shell script \\\"cd /Applications; xip --expand $(CopyOutputPath);\\\"\"" +
|
|
" -e \"try\"" +
|
|
" -e \"do shell script \\\"xcode-select -s /Applications/Xcode.app; xcode-select --install; xcodebuild -license accept; xcodebuild -runFirstLaunch\\\" with administrator privileges\"" +
|
|
" -e \"end try\"";
|
|
}
|
|
else if (UnrealBuildTool.BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Win64)
|
|
{
|
|
|
|
TurnkeyContext.Log("Uninstalling old iTunes and preparing the new one to be installed.");
|
|
|
|
Command = "$(EngineDir)/Extras/iTunes/Install_iTunes.bat";
|
|
Params = "$(CopyOutputPath)";
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public override bool OnSDKInstallComplete(int ExitCode, ITurnkeyContext TurnkeyContext, DeviceInfo Device)
|
|
{
|
|
if (Device == null)
|
|
{
|
|
if (ExitCode == 0)
|
|
{
|
|
if (UnrealBuildTool.BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac)
|
|
{
|
|
TurnkeyContext.PauseForUser("If you had Xcode in your Dock, you will need to remove it and add the new one (even though it was in the same location). macOS follows the move to the Trash for the Dock icon");
|
|
}
|
|
}
|
|
}
|
|
|
|
return ExitCode == 0;
|
|
}
|
|
|
|
#endregion
|
|
|
|
public override void PreBuildAgenda(UnrealBuild Build, UnrealBuild.BuildAgenda Agenda, ProjectParams Params)
|
|
{
|
|
if (AppleExports.UseModernXcode(Params.RawProjectPath))
|
|
{
|
|
// any building before we stage should not pull the stage dir into the .app, and we will unset it below when we build again after staging
|
|
Environment.SetEnvironmentVariable("UE_SKIP_STAGEDDATA_SYNC", "1", EnvironmentVariableTarget.Process);
|
|
}
|
|
|
|
base.PreBuildAgenda(Build, Agenda, Params);
|
|
}
|
|
|
|
private string MakeContentOnlyTargetName(TargetReceipt Target, string GameName)
|
|
{
|
|
// for a BP project, with a uproject, where the TargetName is one of the Unreal targets, the xcode project actually makes
|
|
// a <ProjectName><Type> scheme/target, so we need to use it for the -SingleTarget param, and the scheme we xcodebuild
|
|
// note: this must match the code in ProjectFileGenerator.cs / AddProjectsForAllTargets, like this:
|
|
// ProjectFile = FindOrAddProject(GetProjectLocation($"{ProjectName}{EngineTarget.TargetRules!.Type}"), ContentOnlyGameProject.Directory, ...
|
|
// in the "if (bAllowContentOnlyProjects)" block
|
|
return $"{GameName}{Target.TargetType}";
|
|
}
|
|
|
|
public override void PostStagingFileCopy(ProjectParams Params, DeploymentContext SC)
|
|
{
|
|
if (AppleExports.UseModernXcode(Params.RawProjectPath))
|
|
{
|
|
// now reset the envvar so the following build will process the staged data
|
|
Environment.SetEnvironmentVariable("UE_SKIP_STAGEDDATA_SYNC", "0", EnvironmentVariableTarget.Process);
|
|
|
|
foreach (TargetReceipt Target in SC.StageTargets.Select(x => x.Receipt))
|
|
{
|
|
string ExtraOptions =
|
|
// fiddle with some envvars to redirect the .app into root of Staging directory, without going under any build subdirectories
|
|
$"SYMROOT=\"{SC.StageDirectory.ParentDirectory}\" " +
|
|
$"EFFECTIVE_PLATFORM_NAME={SC.StageDirectory.GetDirectoryName()} " +
|
|
// set where the stage directory is
|
|
$"UE_OVERRIDE_STAGE_DIR=\"{SC.StageDirectory}\"";
|
|
|
|
string TargetName = Target.TargetName;
|
|
if (!Params.IsCodeBasedProject)
|
|
{
|
|
// instead of staging an UnrealGame.app, stage something with the project name, like say MyProjectClient-IOS-Shipping.app
|
|
string ProductName = AppleExports.MakeBinaryFileName(SC.ShortProjectName, Target.Platform, Target.Configuration, Target.Architectures, UnrealTargetConfiguration.Development, null);
|
|
ExtraOptions += $" PRODUCT_NAME={ProductName}";
|
|
|
|
if (Params.RawProjectPath != null)
|
|
{
|
|
TargetName = MakeContentOnlyTargetName(Target, Params.ShortProjectName);
|
|
}
|
|
}
|
|
|
|
AppleExports.BuildWithStubXcodeProject(SC.RawProjectPath, Target.Platform, Target.Architectures, Target.Configuration, TargetName, AppleExports.XcodeBuildMode.Stage, Logger, ExtraOptions);
|
|
}
|
|
}
|
|
}
|
|
|
|
private DirectoryReference GetArchivePath(StageTarget Target, DeploymentContext SC)
|
|
{
|
|
DirectoryReference UserDir = new DirectoryReference(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile));
|
|
DirectoryReference Library = DirectoryReference.Combine(UserDir, "Library/Developer/Xcode/Archives");
|
|
|
|
// order date named folders (use creating data, not name, but same thing)
|
|
List<DirectoryReference> DateDirs = DirectoryReference.EnumerateDirectories(Library).ToList();
|
|
DateDirs.SortBy(x => Directory.GetCreationTime(x.FullName));
|
|
DateDirs.Reverse();
|
|
|
|
|
|
// go through each folder, starting at most recent, looking for an archive for the target
|
|
foreach (DirectoryReference DateDir in DateDirs)
|
|
{
|
|
Logger.LogInformation("Looking in Xcode archive dir {0}...", DateDir);
|
|
|
|
// find the most recent archive for this target (based on name of target, this ignores Development vs Shipping, but
|
|
// since Distribution is meant only for Shipping it's ok
|
|
string Wildcard = $"{Target.Receipt.TargetName} *.xcarchive";
|
|
List<DirectoryReference> XcArchives = DirectoryReference.EnumerateDirectories(DateDir, Wildcard).ToList();
|
|
if (XcArchives.Count > 0)
|
|
{
|
|
XcArchives.SortBy(x => Directory.GetCreationTime(x.FullName));
|
|
DirectoryReference XcArchive = XcArchives.Last();
|
|
|
|
Logger.LogInformation("Found xcarchive dir {0}", XcArchive);
|
|
return XcArchive;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private DirectoryReference GetFinalAppPath(StageTarget Target, DeploymentContext SC)
|
|
{
|
|
// content only projects have to not use the executable, but make a path to a .app
|
|
if (!SC.IsCodeBasedProject)
|
|
{
|
|
string AppBundleName = AppleExports.MakeBinaryFileName(SC.ShortProjectName, Target.Receipt.Platform, Target.Receipt.Configuration,
|
|
Target.Receipt.Architectures, UnrealTargetConfiguration.Development, ".app");
|
|
|
|
return DirectoryReference.Combine(SC.ProjectRoot, "Binaries", Target.Receipt.Platform.ToString(), AppBundleName);
|
|
}
|
|
|
|
DirectoryReference AppDir;
|
|
// get the executable from the receipt
|
|
FileReference Executable = Target.Receipt.BuildProducts.First(x => x.Type == BuildProductType.Executable).Path;
|
|
|
|
// if we are in a .app, then use that
|
|
if (Executable.FullName.Contains(".app/"))
|
|
{
|
|
AppDir = Executable.Directory;
|
|
// go up until we find the .app - Mac and IOS are different, so this handles both cases
|
|
while (AppDir.HasExtension(".app") == false)
|
|
{
|
|
AppDir = AppDir.ParentDirectory;
|
|
}
|
|
}
|
|
// otherwise use the .app next to the executable
|
|
else
|
|
{
|
|
AppDir = new DirectoryReference(Executable.FullName + ".app");
|
|
}
|
|
|
|
return AppDir;
|
|
}
|
|
|
|
public override void Package(ProjectParams Params, DeploymentContext SC, int WorkingCL)
|
|
{
|
|
if (AppleExports.UseModernXcode(Params.RawProjectPath))
|
|
{
|
|
foreach (StageTarget Target in SC.StageTargets)
|
|
{
|
|
TargetReceipt Receipt = Target.Receipt;
|
|
string TargetName = Receipt.TargetName;
|
|
|
|
string ExtraOptions =
|
|
// set where the stage directory is
|
|
$"UE_OVERRIDE_STAGE_DIR=\"{SC.StageDirectory}\"";
|
|
if (!Params.IsCodeBasedProject)
|
|
{
|
|
// override where the .app will be located and named
|
|
ExtraOptions += $" SYMROOT=\"{SC.ProjectRoot}/Binaries\"";
|
|
string ProductName = AppleExports.MakeBinaryFileName(SC.ShortProjectName, Receipt.Platform, Receipt.Configuration, Receipt.Architectures, UnrealTargetConfiguration.Development, null);
|
|
ExtraOptions += $" PRODUCT_NAME={ProductName}";
|
|
|
|
if (Params.RawProjectPath != null)
|
|
{
|
|
TargetName = MakeContentOnlyTargetName(Receipt, Params.ShortProjectName);
|
|
}
|
|
}
|
|
|
|
|
|
// if we we packaging for distrbution, we will create a .xcarchive which can be used to submit to app stores, or exported for other distribution methods
|
|
// the archive will be created in the standard Archives location accessible via Xcode. Using -archive will copy it out into
|
|
// the specified location for use as needed
|
|
AppleExports.XcodeBuildMode BuildMode = Params.Distribution ? AppleExports.XcodeBuildMode.Distribute : AppleExports.XcodeBuildMode.Package;
|
|
if (AppleExports.BuildWithStubXcodeProject(Params.RawProjectPath, Receipt.Platform, Receipt.Architectures, Receipt.Configuration, TargetName, BuildMode, Logger, ExtraOptions) == 0)
|
|
{
|
|
Logger.LogInformation("=====================================================================================");
|
|
if (Params.Distribution)
|
|
{
|
|
Logger.LogInformation("Created .xcarchive in Xcode's Library, which can be seen in Xcode's Organizer window");
|
|
Logger.LogInformation("You may use this to validate and prepare for various distribution methods");
|
|
}
|
|
else
|
|
{
|
|
Logger.LogInformation("Finalized {App} for running fully self-contained", GetFinalAppPath(Target, SC));
|
|
}
|
|
Logger.LogInformation("=====================================================================================");
|
|
}
|
|
}
|
|
}
|
|
|
|
// package up the program, potentially with an installer for Mac
|
|
PrintRunTime();
|
|
}
|
|
|
|
public override void GetFilesToArchive(ProjectParams Params, DeploymentContext SC)
|
|
{
|
|
if (!AppleExports.UseModernXcode(Params.RawProjectPath))
|
|
{
|
|
base.GetFilesToArchive(Params, SC);
|
|
return;
|
|
}
|
|
|
|
Logger.LogInformation("staging targets: '{tagets}', '{configs}'", string.Join(", ", Params.ClientCookedTargets),
|
|
string.Join(", ", SC.StageTargetConfigurations));
|
|
foreach (StageTarget Target in SC.StageTargets)
|
|
{
|
|
//// copy the xcarchive and any exported files
|
|
//string ExportMode = "Development";
|
|
//DirectoryReference ExportPath = GetExportPath(ExportMode, SC);
|
|
|
|
// distribution mode we want to archive the .xcarchive that was created during Package
|
|
DirectoryReference ArchiveSource;
|
|
if (Params.Distribution)
|
|
{
|
|
// find the most recent .xcarchive in the Xcode archives library
|
|
ArchiveSource = GetArchivePath(Target, SC);
|
|
|
|
if (ArchiveSource == null)
|
|
{
|
|
Logger.LogError("Unable to find a .xcarchive in Xcode's Library to archive to {ArchiveDir}", SC.ArchiveDirectory);
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ArchiveSource = GetFinalAppPath(Target, SC);
|
|
if (!DirectoryReference.Exists(ArchiveSource))
|
|
{
|
|
Logger.LogError("Unable to find the expected application ({App}) for achiving", ArchiveSource);
|
|
return;
|
|
}
|
|
}
|
|
|
|
Logger.LogInformation("=====================================================================================");
|
|
Logger.LogInformation("Copying {Type} package {ArchiveSource} to archive directory {ArchiveDir}", Params.Distribution ? "Distribution" : "Development", ArchiveSource, SC.ArchiveDirectory);
|
|
Logger.LogInformation("=====================================================================================");
|
|
|
|
SC.ArchiveFiles(ArchiveSource.FullName, NewPath: ArchiveSource.GetDirectoryName());
|
|
}
|
|
}
|
|
}
|