2014-12-07 19:09:38 -05:00
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
using System ;
using System.Collections.Generic ;
using System.Linq ;
using System.Text ;
2014-04-23 16:46:39 -04:00
using System.IO ;
2014-03-14 14:13:41 -04:00
using AutomationTool ;
using UnrealBuildTool ;
public class MacPlatform : Platform
{
public MacPlatform ( )
: base ( UnrealTargetPlatform . Mac )
2014-08-18 13:29:39 -04:00
{
2014-03-14 14:13:41 -04:00
}
2014-08-18 13:29:39 -04:00
public override string GetCookPlatform ( bool bDedicatedServer , bool bIsClientOnly , string CookFlavor )
{
2014-12-15 15:29:48 -05:00
const string NoEditorCookPlatform = "MacNoEditor" ;
2014-08-18 13:29:39 -04:00
const string ServerCookPlatform = "MacServer" ;
2014-12-15 15:29:48 -05:00
const string ClientCookPlatform = "MacClient" ;
if ( bDedicatedServer )
{
return ServerCookPlatform ;
}
else if ( bIsClientOnly )
{
return ClientCookPlatform ;
}
else
{
return NoEditorCookPlatform ;
}
2014-08-18 13:29:39 -04:00
}
2014-03-14 14:13:41 -04:00
2014-08-18 13:29:39 -04:00
public override string GetEditorCookPlatform ( )
{
return "Mac" ;
}
2014-03-14 14:13:41 -04:00
2015-03-18 10:12:32 -04:00
private void StageAppBundle ( DeploymentContext SC , StagedFileType InStageFileType , string InPath , string NewName )
2014-04-23 16:46:39 -04:00
{
2015-03-18 10:12:32 -04:00
SC . StageFiles ( InStageFileType , InPath , "*" , true , null , NewName , false , true , null ) ;
2014-04-23 16:46:39 -04:00
}
2014-03-14 14:13:41 -04:00
public override void GetFilesToDeployOrStage ( ProjectParams Params , DeploymentContext SC )
{
2015-03-30 14:45:04 -04:00
if ( Params . StageNonMonolithic )
2014-03-14 14:13:41 -04:00
{
2015-03-30 14:45:04 -04:00
if ( SC . DedicatedServer )
2014-03-14 14:13:41 -04:00
{
2015-03-30 14:45:04 -04:00
if ( SC . StageTargetConfigurations . Contains ( UnrealTargetConfiguration . Development ) )
2015-02-01 12:33:30 -05:00
{
2015-03-30 14:45:04 -04:00
SC . StageFiles ( StagedFileType . NonUFS , CombinePaths ( SC . LocalRoot , "Engine/Binaries" , SC . PlatformDir , "UE4Server.app" ) ) ;
SC . StageFiles ( StagedFileType . NonUFS , CombinePaths ( SC . ProjectRoot , "Binaries" , SC . PlatformDir ) , "UE4Server-" + SC . ShortProjectName + ".dylib" ) ;
}
if ( SC . StageTargetConfigurations . Contains ( UnrealTargetConfiguration . Test ) )
{
SC . StageFiles ( StagedFileType . NonUFS , CombinePaths ( SC . LocalRoot , "Engine/Binaries" , SC . PlatformDir , "UE4Server-Mac-Test.app" ) ) ;
2015-04-03 18:35:07 -04:00
SC . StageFiles ( StagedFileType . NonUFS , CombinePaths ( SC . ProjectRoot , "Binaries" , SC . PlatformDir ) , "UE4Server-" + SC . ShortProjectName + "-Mac-Test.dylib" ) ;
2015-03-30 14:45:04 -04:00
}
if ( SC . StageTargetConfigurations . Contains ( UnrealTargetConfiguration . Shipping ) )
{
SC . StageFiles ( StagedFileType . NonUFS , CombinePaths ( SC . LocalRoot , "Engine/Binaries" , SC . PlatformDir , "UE4Server-Mac-Shipping.app" ) ) ;
2015-04-03 18:35:07 -04:00
SC . StageFiles ( StagedFileType . NonUFS , CombinePaths ( SC . ProjectRoot , "Binaries" , SC . PlatformDir ) , "UE4Server-" + SC . ShortProjectName + "-Mac-Shipping.dylib" ) ;
2015-02-01 12:33:30 -05:00
}
2015-03-30 14:45:04 -04:00
SC . StageFiles ( StagedFileType . NonUFS , CombinePaths ( SC . LocalRoot , "Engine/Plugins" ) , "UE4Server-*.dylib" , true ) ;
SC . StageFiles ( StagedFileType . NonUFS , CombinePaths ( SC . ProjectRoot , "Plugins" ) , "UE4Server-*.dylib" , true ) ;
2014-10-30 12:36:31 -04:00
}
2015-03-30 14:45:04 -04:00
else
2014-10-30 12:36:31 -04:00
{
2015-03-30 14:45:04 -04:00
if ( SC . StageTargetConfigurations . Contains ( UnrealTargetConfiguration . Development ) )
2015-03-16 12:46:31 -04:00
{
2015-03-30 14:45:04 -04:00
SC . StageFiles ( StagedFileType . NonUFS , CombinePaths ( SC . LocalRoot , "Engine/Binaries" , SC . PlatformDir , "UE4.app" ) ) ;
SC . StageFiles ( StagedFileType . NonUFS , CombinePaths ( SC . ProjectRoot , "Binaries" , SC . PlatformDir ) , "UE4-" + SC . ShortProjectName + ".dylib" ) ;
}
if ( SC . StageTargetConfigurations . Contains ( UnrealTargetConfiguration . Test ) )
{
SC . StageFiles ( StagedFileType . NonUFS , CombinePaths ( SC . LocalRoot , "Engine/Binaries" , SC . PlatformDir , "UE4-Mac-Test.app" ) ) ;
2015-04-03 18:35:07 -04:00
SC . StageFiles ( StagedFileType . NonUFS , CombinePaths ( SC . ProjectRoot , "Binaries" , SC . PlatformDir ) , "UE4-" + SC . ShortProjectName + "-Mac-Test.dylib" ) ;
2015-03-30 14:45:04 -04:00
}
if ( SC . StageTargetConfigurations . Contains ( UnrealTargetConfiguration . Shipping ) )
{
SC . StageFiles ( StagedFileType . NonUFS , CombinePaths ( SC . LocalRoot , "Engine/Binaries" , SC . PlatformDir , "UE4-Mac-Shipping.app" ) ) ;
2015-04-03 18:35:07 -04:00
SC . StageFiles ( StagedFileType . NonUFS , CombinePaths ( SC . ProjectRoot , "Binaries" , SC . PlatformDir ) , "UE4-" + SC . ShortProjectName + "-Mac-Shipping.dylib" ) ;
2015-03-16 12:46:31 -04:00
}
2015-03-18 10:12:32 -04:00
2015-03-30 14:45:04 -04:00
SC . StageFiles ( StagedFileType . NonUFS , CombinePaths ( SC . LocalRoot , "Engine/Plugins" ) , "UE4-*.dylib" , true ) ;
SC . StageFiles ( StagedFileType . NonUFS , CombinePaths ( SC . ProjectRoot , "Plugins" ) , "UE4-*.dylib" , true , null , null , true ) ;
}
2014-03-14 14:13:41 -04:00
}
2015-03-30 14:45:04 -04:00
else
{
// the first app is the "main" one, the rest are marked as debug files for exclusion from chunking/distribution
StagedFileType WorkingFileType = StagedFileType . NonUFS ;
2014-03-14 14:13:41 -04:00
2015-03-30 14:45:04 -04:00
List < string > Exes = GetExecutableNames ( SC ) ;
foreach ( var Exe in Exes )
{
string AppBundlePath = "" ;
if ( Exe . StartsWith ( CombinePaths ( SC . RuntimeProjectRootDir , "Binaries" , SC . PlatformDir ) ) )
{
AppBundlePath = CombinePaths ( SC . ShortProjectName , "Binaries" , SC . PlatformDir , Path . GetFileNameWithoutExtension ( Exe ) + ".app" ) ;
StageAppBundle ( SC , WorkingFileType , CombinePaths ( SC . ProjectRoot , "Binaries" , SC . PlatformDir , Path . GetFileNameWithoutExtension ( Exe ) + ".app" ) , AppBundlePath ) ;
}
else if ( Exe . StartsWith ( CombinePaths ( SC . RuntimeRootDir , "Engine/Binaries" , SC . PlatformDir ) ) )
{
AppBundlePath = CombinePaths ( "Engine/Binaries" , SC . PlatformDir , Path . GetFileNameWithoutExtension ( Exe ) + ".app" ) ;
string AbsoluteBundlePath = CombinePaths ( SC . LocalRoot , AppBundlePath ) ;
// ensure the ue4game binary exists, if applicable
2015-04-08 16:59:20 -04:00
if ( ! SC . IsCodeBasedProject & & ! Directory . Exists ( AbsoluteBundlePath ) & & ! SC . bIsCombiningMultiplePlatforms )
2015-03-30 14:45:04 -04:00
{
Log ( "Failed to find app bundle " + AbsoluteBundlePath ) ;
AutomationTool . ErrorReporter . Error ( "Stage Failed." , ( int ) AutomationTool . ErrorCodes . Error_MissingExecutable ) ;
throw new AutomationException ( "Could not find app bundle {0}. You may need to build the UE4 project with your target configuration and platform." , AbsoluteBundlePath ) ;
}
StageAppBundle ( SC , WorkingFileType , CombinePaths ( SC . LocalRoot , "Engine/Binaries" , SC . PlatformDir , Path . GetFileNameWithoutExtension ( Exe ) + ".app" ) , AppBundlePath ) ;
}
if ( ! string . IsNullOrEmpty ( AppBundlePath ) )
{
SC . StageFiles ( WorkingFileType , CombinePaths ( SC . ProjectRoot , "Build/Mac" ) , "Application.icns" , false , null , CombinePaths ( AppBundlePath , "Contents/Resources" ) , true ) ;
if ( Params . bUsesSteam )
{
SC . StageFiles ( StagedFileType . NonUFS , CombinePaths ( SC . LocalRoot , "Engine/Source/ThirdParty/Steamworks/Steamv132/sdk/redistributable_bin/osx32" ) , "libsteam_api.dylib" , false , null , CombinePaths ( AppBundlePath , "Contents/MacOS" ) , true ) ;
}
}
// the first app is the "main" one, the rest are marked as debug files for exclusion from chunking/distribution
WorkingFileType = StagedFileType . DebugNonUFS ;
}
}
2015-06-12 11:26:33 -04:00
if ( SC . bStageCrashReporter )
{
string CrashReportClientPath = CombinePaths ( "Engine/Binaries" , SC . PlatformDir , "CrashReportClient.app" ) ;
StageAppBundle ( SC , StagedFileType . NonUFS , CombinePaths ( SC . LocalRoot , "Engine/Binaries" , SC . PlatformDir , "CrashReportClient.app" ) , CrashReportClientPath ) ;
}
2014-03-14 14:13:41 -04:00
// Copy the splash screen, Mac specific
SC . StageFiles ( StagedFileType . NonUFS , CombinePaths ( SC . ProjectRoot , "Content/Splash" ) , "Splash.bmp" , false , null , null , true ) ;
2015-01-16 09:04:57 -05:00
// CEF3 files
2015-02-18 09:19:43 -05:00
if ( Params . bUsesCEF3 )
{
SC . StageFiles ( StagedFileType . NonUFS , CombinePaths ( SC . LocalRoot , "Engine/Binaries/ThirdParty/CEF3/Mac/" ) , "*" , true , null , null , true ) ;
string UnrealCEFSubProcessPath = CombinePaths ( "Engine/Binaries" , SC . PlatformDir , "UnrealCEFSubProcess.app" ) ;
2015-03-18 10:12:32 -04:00
StageAppBundle ( SC , StagedFileType . NonUFS , CombinePaths ( SC . LocalRoot , "Engine/Binaries" , SC . PlatformDir , "UnrealCEFSubProcess.app" ) , UnrealCEFSubProcessPath ) ;
2015-02-18 09:19:43 -05:00
}
2014-08-18 13:29:39 -04:00
}
2014-03-14 14:13:41 -04:00
public override void Package ( ProjectParams Params , DeploymentContext SC , int WorkingCL )
{
// package up the program, potentially with an installer for Mac
PrintRunTime ( ) ;
}
2015-04-16 14:27:20 -04:00
public override void ProcessArchivedProject ( ProjectParams Params , DeploymentContext SC )
{
string ExeName = SC . StageExecutables [ 0 ] ;
string BundlePath = CombinePaths ( SC . ArchiveDirectory , SC . ShortProjectName + ".app" ) ;
if ( SC . bIsCombiningMultiplePlatforms )
{
// when combining multiple platforms, don't merge the content into the .app, use the one in the Binaries directory
BundlePath = CombinePaths ( SC . ArchiveDirectory , SC . ShortProjectName , "Binaries" , "Mac" , ExeName + ".app" ) ;
if ( ! Directory . Exists ( BundlePath ) )
{
// if the .app wasn't there, just skip out (we don't require executables when combining)
return ;
}
}
string TargetPath = CombinePaths ( BundlePath , "Contents" , "UE4" ) ;
if ( ! SC . bIsCombiningMultiplePlatforms )
{
2015-06-12 11:26:33 -04:00
if ( Directory . Exists ( BundlePath ) )
2015-04-16 14:27:20 -04:00
{
2015-06-12 11:26:33 -04:00
Directory . Delete ( BundlePath , true ) ;
2015-04-16 14:27:20 -04:00
}
2015-06-12 11:26:33 -04:00
string SourceBundlePath = CombinePaths ( SC . ArchiveDirectory , SC . ShortProjectName , "Binaries" , "Mac" , ExeName + ".app" ) ;
if ( ! Directory . Exists ( SourceBundlePath ) )
{
SourceBundlePath = CombinePaths ( SC . ArchiveDirectory , "Engine" , "Binaries" , "Mac" , ExeName + ".app" ) ;
}
Directory . Move ( SourceBundlePath , BundlePath ) ;
2015-04-16 14:27:20 -04:00
if ( DirectoryExists ( TargetPath ) )
{
Directory . Delete ( TargetPath , true ) ;
}
// First, move all files and folders inside he app bundle
string [ ] StagedFiles = Directory . GetFiles ( SC . ArchiveDirectory , "*" , SearchOption . TopDirectoryOnly ) ;
foreach ( string FilePath in StagedFiles )
{
string TargetFilePath = CombinePaths ( TargetPath , Path . GetFileName ( FilePath ) ) ;
Directory . CreateDirectory ( Path . GetDirectoryName ( TargetFilePath ) ) ;
File . Move ( FilePath , TargetFilePath ) ;
}
string [ ] StagedDirectories = Directory . GetDirectories ( SC . ArchiveDirectory , "*" , SearchOption . TopDirectoryOnly ) ;
foreach ( string DirPath in StagedDirectories )
{
string DirName = Path . GetFileName ( DirPath ) ;
if ( ! DirName . EndsWith ( ".app" ) )
{
string TargetDirPath = CombinePaths ( TargetPath , DirName ) ;
Directory . CreateDirectory ( Path . GetDirectoryName ( TargetDirPath ) ) ;
Directory . Move ( DirPath , TargetDirPath ) ;
}
}
}
// Update executable name, icon and entry in Info.plist
string UE4GamePath = CombinePaths ( BundlePath , "Contents" , "MacOS" , ExeName ) ;
if ( ExeName ! = SC . ShortProjectName & & File . Exists ( UE4GamePath ) )
{
string GameExePath = CombinePaths ( BundlePath , "Contents" , "MacOS" , SC . ShortProjectName ) ;
File . Delete ( GameExePath ) ;
File . Move ( UE4GamePath , GameExePath ) ;
string DefaultIconPath = CombinePaths ( BundlePath , "Contents" , "Resources" , "UE4.icns" ) ;
string CustomIconSrcPath = CombinePaths ( BundlePath , "Contents" , "Resources" , "Application.icns" ) ;
string CustomIconDestPath = CombinePaths ( BundlePath , "Contents" , "Resources" , SC . ShortProjectName + ".icns" ) ;
if ( File . Exists ( CustomIconSrcPath ) )
{
File . Delete ( DefaultIconPath ) ;
File . Move ( CustomIconSrcPath , CustomIconDestPath ) ;
}
else
{
File . Move ( DefaultIconPath , CustomIconDestPath ) ;
}
string InfoPlistPath = CombinePaths ( BundlePath , "Contents" , "Info.plist" ) ;
string InfoPlistContents = File . ReadAllText ( InfoPlistPath ) ;
InfoPlistContents = InfoPlistContents . Replace ( ExeName , SC . ShortProjectName ) ;
InfoPlistContents = InfoPlistContents . Replace ( "<string>UE4</string>" , "<string>" + SC . ShortProjectName + "</string>" ) ;
File . Delete ( InfoPlistPath ) ;
File . WriteAllText ( InfoPlistPath , InfoPlistContents ) ;
}
2015-04-21 14:25:42 -04:00
if ( ! SC . bIsCombiningMultiplePlatforms )
{
// creating this directory when the content isn't moved into the application causes it
// to fail to load, and isn't needed
Directory . CreateDirectory ( CombinePaths ( TargetPath , ExeName . StartsWith ( "UE4Game" ) ? "Engine" : SC . ShortProjectName , "Binaries" , "Mac" ) ) ;
}
2015-04-16 14:27:20 -04:00
}
2014-04-24 16:39:25 -04:00
public override ProcessResult RunClient ( ERunOptions ClientRunFlags , string ClientApp , string ClientCmdLine , ProjectParams Params )
{
if ( ! File . Exists ( ClientApp ) )
{
if ( Directory . Exists ( ClientApp + ".app" ) )
{
ClientApp + = ".app/Contents/MacOS/" + Path . GetFileName ( ClientApp ) ;
}
else
{
Int32 BaseDirLen = Params . BaseStageDirectory . Length ;
string StageSubDir = ClientApp . Substring ( BaseDirLen , ClientApp . IndexOf ( "/" , BaseDirLen + 1 ) - BaseDirLen ) ;
ClientApp = CombinePaths ( Params . BaseStageDirectory , StageSubDir , Params . ShortProjectName + ".app/Contents/MacOS/" + Params . ShortProjectName ) ;
}
}
PushDir ( Path . GetDirectoryName ( ClientApp ) ) ;
// Always start client process and don't wait for exit.
ProcessResult ClientProcess = Run ( ClientApp , ClientCmdLine , null , ClientRunFlags | ERunOptions . NoWaitForExit ) ;
PopDir ( ) ;
return ClientProcess ;
}
2014-03-14 14:13:41 -04:00
public override bool IsSupported { get { return true ; } }
2014-08-18 13:29:39 -04:00
public override bool ShouldUseManifestForUBTBuilds ( string AddArgs )
2014-03-14 14:13:41 -04:00
{
// don't use the manifest to set up build products if we are compiling Mac under Windows and we aren't going to copy anything back to the PC
2014-08-06 07:05:15 -04:00
bool bIsBuildingRemotely = UnrealBuildTool . BuildHostPlatform . Current . Platform ! = UnrealTargetPlatform . Mac ;
2014-08-18 13:29:39 -04:00
bool bUseManifest = ! bIsBuildingRemotely | | AddArgs . IndexOf ( "-CopyAppBundleBackToDevice" , StringComparison . InvariantCultureIgnoreCase ) > 0 ;
2014-03-14 14:13:41 -04:00
return bUseManifest ;
}
2014-08-18 13:29:39 -04:00
public override List < string > GetDebugFileExtentions ( )
{
return new List < string > { ".dsym" } ;
}
public override bool CanHostPlatform ( UnrealTargetPlatform Platform )
{
if ( Platform = = UnrealTargetPlatform . IOS | | Platform = = UnrealTargetPlatform . Mac )
{
return true ;
}
return false ;
}
2014-03-14 14:13:41 -04:00
}