2019-12-26 23:01:54 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
using System ;
using AutomationTool ;
2022-04-18 14:37:50 -04:00
using UnrealBuildBase ;
2014-03-14 14:13:41 -04:00
using UnrealBuildTool ;
2022-04-18 14:37:50 -04:00
using System.Linq ;
using EpicGames.Core ;
using System.IO ;
using System.Collections.Generic ;
2023-03-08 12:43:35 -05:00
using Microsoft.Extensions.Logging ;
2014-03-14 14:13:41 -04:00
[Help(@"Generates IOS debug symbols for a remote project.")]
[Help("project=Name", @"Project name (required), i.e: -project=QAGame")]
[Help("config=Configuration", @"Project configuration (required), i.e: -config=Development")]
public class GenerateDSYM : BuildCommand
{
public override void ExecuteBuild ( )
2014-08-18 13:29:39 -04:00
{
2022-04-18 14:37:50 -04:00
if ( OperatingSystem . IsMacOS ( ) )
{
bool bSaveFlat = ParseParamBool ( "flat" ) ;
2014-03-14 14:13:41 -04:00
2022-04-18 14:37:50 -04:00
List < string > Binaries = new List < string > ( ) ;
string FileList = ParseParamValue ( "file=" ) ;
if ( ! string . IsNullOrEmpty ( FileList ) )
{
Binaries . AddRange ( FileList . Split ( ',' ) ) ;
}
else
{
string PlatformName = ParseParamValue ( "platform" ) ;
FileReference ProjectFile = ParseProjectParam ( ) ;
string TargetName = ParseOptionalStringParam ( "target" ) ? ? System . IO . Path . GetFileNameWithoutExtension ( ProjectFile ? . FullName ? ? "" ) ;
UnrealTargetConfiguration Configuration = ParseOptionalEnumParam < UnrealTargetConfiguration > ( "config" ) ? ? UnrealTargetConfiguration . Development ;
2014-03-14 14:13:41 -04:00
2022-04-18 14:37:50 -04:00
if ( ProjectFile = = null | | PlatformName = = null | | TargetName = = null )
{
2023-03-09 14:51:40 -05:00
Logger . LogError ( "Must specify a file(s) with -file=, or other parameters to find the binaries:-project=<Path or name of project>\n" +
2023-03-02 12:41:54 -05:00
"-platform=<Mac|IOS|TVOS>\n" +
"-target=<TargetName> (Optional, defaults to the ProjectName)\n" +
2022-04-18 14:37:50 -04:00
"-config=<Debug|DebugGame|Development|Test|Shipping> (Optional - defaults to Development)\n" +
"Ex: -project=EngineTest -platform=Mac -target=EngineTestEditor -config=Test\n\n" +
"Other options:\n" +
"-flat (Options, if specified, the .dSYMs will be flat files that are easier to copy around between computers/servers/etc\n\n" ) ;
return ;
}
UnrealTargetPlatform Platform ;
if ( ! UnrealTargetPlatform . TryParse ( PlatformName , out Platform ) | | ! Platform . IsInGroup ( UnrealPlatformGroup . Apple ) )
{
2023-03-08 12:43:35 -05:00
Logger . LogError ( "Platform must be one of Mac, IOS, TVOS" ) ;
2022-04-18 14:37:50 -04:00
return ;
}
2023-03-02 12:41:54 -05:00
// Apple platforms don't need the architecture pass in because they RequiresArchitectureFilenames returns false, but if that ever changes, we pass in the active architecture anyway
UnrealArchitectures Architectures = UnrealArchitectureConfig . ForPlatform ( Platform ) . ActiveArchitectures ( ProjectFile , TargetName ) ;
FileReference ReceiptFile = TargetReceipt . GetDefaultPath ( DirectoryReference . FromFile ( ProjectFile ) ? ? Unreal . EngineDirectory , TargetName , Platform , Configuration , Architectures ) ;
2022-04-18 14:37:50 -04:00
TargetReceipt Receipt = TargetReceipt . Read ( ReceiptFile ) ;
// get the products that we can dsym (duylibs and executables)
IEnumerable < BuildProduct > Products = Receipt . BuildProducts . Where ( x = > x . Type = = BuildProductType . Executable | | x . Type = = BuildProductType . DynamicLibrary ) ;
Binaries . AddRange ( Products . Select ( x = > x . Path . FullName ) ) ;
}
// sort binaries by size so we start with large ones first to try to not have a single long tent pole hanging out at the end
// in one test, doing this sped up some tests by around 30%
if ( Binaries . Count > 5 )
{
2023-03-08 12:43:35 -05:00
Logger . LogInformation ( "Sorting binaries by size..." ) ;
2022-04-18 14:37:50 -04:00
Binaries . Sort ( ( A , B ) = > new FileInfo ( B ) . Length . CompareTo ( new FileInfo ( A ) . Length ) ) ;
}
DateTime Start = DateTime . Now ;
Dictionary < string , TimeSpan > Timers = new Dictionary < string , TimeSpan > ( ) ;
Int64 TotalAmountProcessed = 0 ;
int Counter = 1 ;
2023-03-08 12:43:35 -05:00
Logger . LogInformation ( "Starting dSYM generation..." ) ;
2022-04-18 14:37:50 -04:00
System . Threading . Tasks . Parallel . ForEach ( Binaries , ( Binary ) = >
{
int Index ;
long Filesize = new FileInfo ( Binary ) . Length ;
lock ( Timers )
{
Index = Counter + + ;
}
//Log.TraceInformation(" [{0}/{1}] {2}, source is {3:N2} mb", Index, Binaries.Count, Path.GetFileName(Binary), Filesize / 1024.0 / 1024.0);
// put dSYM next to the binary
string dSYM = Path . ChangeExtension ( Binary , ".dSYM" ) ;
2023-04-13 17:01:24 -04:00
if ( Binary . Contains ( ".app/" ) )
{
// or the .app if the binary is inside one
dSYM = Path . Combine ( Path . GetDirectoryName ( Binary . Substring ( 0 , Binary . LastIndexOf ( ".app" ) ) ) , Path . GetFileName ( dSYM ) ) ;
}
2023-04-13 17:01:34 -04:00
Logger . LogInformation ( " Generating for {Binary} -> {dSYM}" , Binary , dSYM ) ;
2023-04-13 17:01:24 -04:00
string Command ;
if ( bSaveFlat )
{
Command = string . Format ( "-c 'rm -rf \"{0}\"; dsymutil -o \"{0}\" {2} \"{1}\"'" , dSYM , Binary , bSaveFlat ? "--flat" : "" ) ;
}
else
{
Command = $"-c '{Unreal.EngineDirectory}/Build/BatchFiles/Mac/GenerateUniversalDSYM.sh \" { Binary } \ " \"{dSYM}\"'" ;
}
2022-04-18 14:37:50 -04:00
DateTime RunStart = DateTime . Now ;
Run ( "bash" , Command , Options : ERunOptions . NoLoggingOfRunCommand ) ;
TimeSpan Diff = DateTime . Now - RunStart ;
lock ( Timers )
{
Timers . Add ( dSYM , Diff ) ;
TotalAmountProcessed + = Filesize ;
}
2023-03-08 12:43:35 -05:00
Logger . LogInformation ( " [{Index}/{Arg1}] {Arg2} took {3:g}, source is {4:N2} mb" , Index , Binaries . Count , Path . GetFileName ( dSYM ) , Diff , Filesize / 1024.0 / 1024.0 ) ;
2022-04-18 14:37:50 -04:00
} ) ;
2023-03-08 12:43:35 -05:00
Logger . LogInformation ( "\n\n-------------------------------------------------------------------" ) ;
Logger . LogInformation ( "GeneratedSYM took {Arg0}, processed {1:N2} mb of binary data." , DateTime . Now - Start , ( double ) TotalAmountProcessed / 1024.0 / 1024.0 ) ;
2022-04-18 14:37:50 -04:00
if ( Binaries . Count > 5 )
{
2023-03-08 12:43:35 -05:00
Logger . LogInformation ( "Slowest dSYMS were:" ) ;
2022-04-18 14:37:50 -04:00
List < string > SlowDSYMs = Timers . Keys . ToList ( ) ;
SlowDSYMs . Sort ( ( A , B ) = > Timers [ B ] . CompareTo ( Timers [ A ] ) ) ;
2023-03-08 12:43:35 -05:00
Logger . LogInformation ( "{Text}" , string . Join ( "\n" , SlowDSYMs . Take ( 10 ) . Select ( x = > string . Format ( "{0} took {1}" , Path . GetFileName ( x ) , Timers [ x ] ) ) ) ) ;
2022-04-18 14:37:50 -04:00
}
}
else
{
var ProjectName = ParseParamValue ( "project" ) ;
var Config = ParseParamValue ( "config" ) ;
var IPPExe = CombinePaths ( CmdEnv . LocalRoot , "Engine/Binaries/DotNET/IOS/IPhonePackager.exe" ) ;
RunAndLog ( CmdEnv , IPPExe , "RPC " + ProjectName + " -config " + Config + " GenDSYM" ) ;
}
2014-08-18 13:29:39 -04:00
}
2023-04-13 17:01:24 -04:00
}