1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239 |
- #if UNITY_EDITOR && ENABLE_BURST_AOT
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.IO;
- using System.Linq;
- using System.Text;
- using System.Text.RegularExpressions;
- using UnityEditor;
- using UnityEditor.Android;
- using UnityEditor.Build;
- using UnityEditor.Build.Reporting;
- using UnityEditor.Compilation;
- using UnityEditor.Scripting;
- using UnityEditor.Scripting.ScriptCompilation;
- using UnityEditor.Scripting.Compilers;
- using UnityEditor.UnityLinker;
- using UnityEditor.Utils;
- using UnityEngine;
- using CompilerMessageType = UnityEditor.Scripting.Compilers.CompilerMessageType;
- using Debug = UnityEngine.Debug;
- using System.Runtime.InteropServices;
-
- #if UNITY_EDITOR_OSX
- using System.ComponentModel;
- using Unity.Burst.LowLevel;
- using UnityEditor.Callbacks;
- #endif
-
- namespace Unity.Burst.Editor
- {
- using static BurstCompilerOptions;
-
- internal class TargetCpus
- {
- public List<BurstTargetCpu> Cpus;
-
- public TargetCpus()
- {
- Cpus = new List<BurstTargetCpu>();
- }
-
- public TargetCpus(BurstTargetCpu single)
- {
- Cpus = new List<BurstTargetCpu>(1)
- {
- single
- };
- }
-
- public bool IsX86()
- {
- foreach (var cpu in Cpus)
- {
- switch (cpu)
- {
- case BurstTargetCpu.X86_SSE2:
- case BurstTargetCpu.X86_SSE4:
- return true;
- }
- }
-
- return false;
- }
-
- public override string ToString()
- {
- var result = "";
-
- var first = true;
-
- foreach (var cpu in Cpus)
- {
- if (first)
- {
- result += $"{cpu}";
- first = false;
- }
- else
- {
- result += $", {cpu}";
- }
- }
-
- return result;
- }
-
- public TargetCpus Clone()
- {
- var copy = new TargetCpus
- {
- Cpus = new List<BurstTargetCpu>(Cpus.Count)
- };
-
- foreach (var cpu in Cpus)
- {
- copy.Cpus.Add(cpu);
- }
-
- return copy;
- }
- }
-
- #if !ENABLE_GENERATE_NATIVE_PLUGINS_FOR_ASSEMBLIES_API
- internal class LinkXMLGenerator : IUnityLinkerProcessor
- {
- public int callbackOrder => 1;
- public string GenerateAdditionalLinkXmlFile(BuildReport report, UnityLinkerBuildPipelineData data)
- {
- var linkXml = Path.GetFullPath(Path.Combine("Temp", BurstAotCompiler.BurstLinkXmlName));
-
- return linkXml;
- }
-
- public void OnBeforeRun(BuildReport report, UnityLinkerBuildPipelineData data)
- {
- }
-
- public void OnAfterRun(BuildReport report, UnityLinkerBuildPipelineData data)
- {
- }
- }
- #endif
-
- #if ENABLE_GENERATE_NATIVE_PLUGINS_FOR_ASSEMBLIES_API
- internal class BurstAOTCompilerPostprocessor : IGenerateNativePluginsForAssemblies
- #else
- internal class BurstAOTCompilerPostprocessor : IPostBuildPlayerScriptDLLs
- #endif
- {
- public int callbackOrder => 0;
- private Assembly[] playerBuildAssemblies = null;
-
- #if ENABLE_GENERATE_NATIVE_PLUGINS_FOR_ASSEMBLIES_API
-
- public IGenerateNativePluginsForAssemblies.PrepareResult PrepareOnMainThread(IGenerateNativePluginsForAssemblies.PrepareArgs args)
- {
- if (ForceDisableBurstCompilation)
- return new();
- DoSetup(args.report);
- var target = BurstPlatformAotSettings.ResolveTarget(settings.summary.platform);
- return new()
- {
- additionalInputFiles = new[]
- {
- // Any files in this list will be scanned for changes, and any changes in these files will trigger
- // a rerun of the Burst compiler on the player build (even if the script assemblies have not changed).
- //
- // We add the settings so that changing any Burst setting will trigger a rebuild.
- BurstPlatformAotSettings.GetPath(target),
-
- // Like above, but specifically for settings unique to player-builds (like SDK versions and like)
- // Those settings are extracted in `DoSetup`
- BurstAotCompiler.BurstAOTSettings.GetPath(target),
-
- // We don't want to scan every file in the Burst package (though every file could potentially change
- // behavior). When working on Burst code locally, you may need to select "Clean Build" in the Build
- // settings window to force a rebuild to pick up the changes.
- //
- // But we add the compiler executable to have at least on file in the package. This should be good
- // enough for users. Because any change in Burst will come with a change of the Burst package
- // version, which will change the pathname for this file (which will then trigger a rebuild, even
- // if the contents have not changed).
- BurstLoader.BclConfiguration.ExecutablePath,
- },
- displayName = "Running Burst Compiler"
- };
- }
-
- public IGenerateNativePluginsForAssemblies.GenerateResult GenerateNativePluginsForAssemblies(IGenerateNativePluginsForAssemblies.GenerateArgs args)
- {
- if (ForceDisableBurstCompilation)
- return new ();
- if (Directory.Exists(BurstAotCompiler.OutputBaseFolder))
- Directory.Delete(BurstAotCompiler.OutputBaseFolder, true);
- var assemblies = args.assemblyFiles.Select(path =>
- {
- var name = Path.GetFileNameWithoutExtension(path);
- return new Assembly(
- name,
- path,
- Array.Empty<string>(),
- // Try to look up any defines for this assembly from the player build report
- playerBuildAssemblies.FirstOrDefault(asm => asm.name == name)?.defines ?? Array.Empty<string>(),
- Array.Empty<Assembly>(),
- Array.Empty<string>(),
- UnityEditor.Compilation.AssemblyFlags.None);
- })
- // We don't run Burst on UnityEngine assemblies, so we skip them to save time
- .Where(a => !a.name.StartsWith("UnityEngine."))
- .ToArray();
- return new () { generatedPlugins = DoGenerate(assemblies).ToArray() };
- }
- #else
- public void OnPostBuildPlayerScriptDLLs(BuildReport report)
- {
- if (ForceDisableBurstCompilation)
- {
- return;
- }
-
- var step = report.BeginBuildStep("burst");
- try
- {
- DoSetup(report);
-
- DoGenerate(playerBuildAssemblies)
- .ToList(); // Force enumeration
- }
- finally
- {
- report.EndBuildStep(step);
- }
- }
- #endif
-
- private BurstAotCompiler.BurstAOTSettings settings;
-
- public void DoSetup(BuildReport report)
- {
- settings = new BurstAotCompiler.BurstAOTSettings()
- {
- summary = report.summary,
- productName = PlayerSettings.productName
- };
- settings.aotSettingsForTarget = BurstPlatformAotSettings.GetOrCreateSettings(settings.summary.platform);
- settings.isSupported = BurstAotCompiler.IsSupportedPlatform(settings.summary.platform, settings.aotSettingsForTarget);
- if (settings.isSupported)
- {
- settings.targetPlatform = BurstAotCompiler.GetTargetPlatformAndDefaultCpu(settings.summary.platform,
- out settings.targetCpus, settings.aotSettingsForTarget);
- settings.combinations =
- BurstAotCompiler.CollectCombinations(settings.targetPlatform, settings.targetCpus,
- settings.summary);
- settings.scriptingBackend =
- #if UNITY_2021_2_OR_NEWER
- PlayerSettings.GetScriptingBackend(NamedBuildTarget.FromBuildTargetGroup(BuildPipeline.GetBuildTargetGroup(settings.summary.platform)));
- #else
- PlayerSettings.GetScriptingBackend(BuildPipeline.GetBuildTargetGroup(settings.summary.platform));
- #endif
- #if UNITY_IOS
- if (settings.targetPlatform == TargetPlatform.iOS)
- {
- settings.extraOptions = new List<string>();
- settings.extraOptions.Add(GetOption(OptionLinkerOptions, $"min-ios-version={PlayerSettings.iOS.targetOSVersionString}"));
- settings.extraOptions.Add(GetOption(OptionPlatformConfiguration, PlayerSettings.iOS.targetOSVersionString));
- }
- #endif
- #if UNITY_TVOS
- if (settings.targetPlatform == TargetPlatform.tvOS)
- {
- settings.extraOptions = new List<string>();
- settings.extraOptions.Add(GetOption(OptionLinkerOptions, $"min-tvos-version={PlayerSettings.tvOS.targetOSVersionString}"));
- settings.extraOptions.Add(GetOption(OptionPlatformConfiguration, PlayerSettings.tvOS.targetOSVersionString));
- }
- #endif
- #if UNITY_VISIONOS
- if (settings.targetPlatform == TargetPlatform.visionOS || settings.targetPlatform == TargetPlatform.visionSimulator)
- {
- settings.extraOptions = new List<string>();
- #if UNITY_2023_3_OR_NEWER
- var targetOSVersionString = PlayerSettings.VisionOS.targetOSVersionString;
- #else
- var playerSettings = typeof(PlayerSettings);
- var visionOs = playerSettings.GetNestedType("VisionOS");
- if (visionOs == null) throw new Exception("Editor does not appear to support visionOS");
- var targetOSVersionStringProperty = visionOs.GetProperty("targetOSVersionString", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
- if (targetOSVersionStringProperty == null) throw new Exception("Property `targetOSVersionString` not found");
- var targetOSVersionString = targetOSVersionStringProperty.GetValue(null, null);
- #endif
- settings.extraOptions.Add(GetOption(OptionLinkerOptions, $"min-visionos-version={targetOSVersionString}"));
- settings.extraOptions.Add(GetOption(OptionPlatformConfiguration, targetOSVersionString));
- }
- #endif
- #if UNITY_2022_2_OR_NEWER && UNITY_ANDROID
- if (settings.targetPlatform == TargetPlatform.Android)
- {
- // Enable Armv9 security features (PAC/BTI) if needed
- settings.aotSettingsForTarget.EnableArmv9SecurityFeatures = PlayerSettings.Android.enableArmv9SecurityFeatures;
- if (PlayerSettings.Android.enableArmv9SecurityFeatures)
- {
- settings.extraOptions ??= new List<string>();
- settings.extraOptions.Add(GetOption(OptionPlatformConfiguration, "armv9-sec"));
- }
- }
- #endif
- if (settings.targetPlatform == TargetPlatform.UWP)
- {
- settings.extraOptions = new List<string>();
-
- if (!string.IsNullOrEmpty(EditorUserBuildSettings.wsaUWPVisualStudioVersion))
- {
- settings.extraOptions.Add(GetOption(OptionLinkerOptions, $"vs-version={EditorUserBuildSettings.wsaUWPVisualStudioVersion}"));
- }
-
- if (!string.IsNullOrEmpty(EditorUserBuildSettings.wsaUWPSDK))
- {
- settings.extraOptions.Add(GetOption(OptionLinkerOptions, $"target-sdk-version={EditorUserBuildSettings.wsaUWPSDK}"));
- }
-
- settings.extraOptions.Add(GetOption(OptionPlatformConfiguration, $"{EditorUserBuildSettings.wsaUWPVisualStudioVersion}:{EditorUserBuildSettings.wsaUWPSDK}:{EditorUserBuildSettings.wsaMinUWPSDK}"));
- }
-
- #if PLATFORM_QNX
- if (settings.targetPlatform == TargetPlatform.QNX)
- {
- settings.extraOptions = new List<string>();
- settings.extraOptions.Add(GetOption(OptionPlatformConfiguration, GetQNXTargetOsVersion()));
- }
- #endif
- playerBuildAssemblies = BurstAotCompiler.GetPlayerAssemblies(report);
-
- Hash128 definesHash = default;
- foreach (var assembly in playerBuildAssemblies.OrderBy(x => x.name))
- {
- definesHash.Append(assembly.name);
- definesHash.Append(assembly.defines.Length);
- foreach (var symbol in assembly.defines.OrderBy(x => x))
- {
- definesHash.Append(symbol);
- }
- }
-
- settings.symbolDefinesHash = definesHash;
-
- settings.Save();
- }
- }
-
- private static string GetQNXTargetOsVersion()
- {
- var flags = System.Reflection.BindingFlags.Public |
- System.Reflection.BindingFlags.Static |
- System.Reflection.BindingFlags.FlattenHierarchy;
- var property = typeof(EditorUserBuildSettings).GetProperty("selectedQnxOsVersion", flags);
- if (null == property)
- {
- return "NOT_FOUND";
- }
- var value = (int)property.GetValue(null, null);
- switch (value)
- {
- case /*UnityEditor.QNXOsVersion.Neutrino70*/ 0: return "Neutrino70";
- case /*UnityEditor.QNXOsVersion.Neutrino71*/ 1: return "Neutrino71";
- default: return $"UNKNOWN_{value}";
- }
- }
-
- public IEnumerable<string> DoGenerate(Assembly[] assemblies)
- {
- if (!settings.isSupported)
- return Array.Empty<string>();
- return BurstAotCompiler.OnPostBuildPlayerScriptDLLsImpl(settings, assemblies);
- }
- }
-
- #if !ENABLE_GENERATE_NATIVE_PLUGINS_FOR_ASSEMBLIES_API
- internal class BurstAndroidGradlePostprocessor : IPostGenerateGradleAndroidProject
- {
- int IOrderedCallback.callbackOrder => 1;
-
- void IPostGenerateGradleAndroidProject.OnPostGenerateGradleAndroidProject(string path)
- {
- var aotSettingsForTarget = BurstPlatformAotSettings.GetOrCreateSettings(BuildTarget.Android);
- // Early exit if burst is not activated
- if (BurstCompilerOptions.ForceDisableBurstCompilation || !aotSettingsForTarget.EnableBurstCompilation)
- {
- return;
- }
-
- // Copy bursted .so's from tempburstlibs to the actual location in the gradle project
- var sourceLocation = Path.GetFullPath(Path.Combine("Temp", "StagingArea", "tempburstlibs"));
- var targetLocation = Path.GetFullPath(Path.Combine(path, "src", "main", "jniLibs"));
- FileUtil.CopyDirectoryRecursive(sourceLocation, targetLocation, true);
- }
- }
-
- // For static builds, there are two different approaches:
- // Postprocessing adds the libraries after Unity is done building,
- // for platforms that need to build a project file, etc.
- // Preprocessing simply adds the libraries to the Unity build,
- // for platforms where Unity can directly build an app.
- internal class StaticPreProcessor : IPreprocessBuildWithReport
- {
- private const string TempSourceLibrary = @"Temp/StagingArea/SourcePlugins";
- public int callbackOrder { get { return 0; } }
- public void OnPreprocessBuild(BuildReport report)
- {
- var aotSettingsForTarget = BurstPlatformAotSettings.GetOrCreateSettings(report.summary.platform);
-
- // Early exit if burst is not activated
- if (BurstCompilerOptions.ForceDisableBurstCompilation || !aotSettingsForTarget.EnableBurstCompilation)
- {
- return;
- }
-
- if(report.summary.platform == BuildTarget.Switch)
- {
- if(!Directory.Exists(TempSourceLibrary))
- {
- Directory.CreateDirectory(TempSourceLibrary);
- Directory.CreateDirectory(TempSourceLibrary);
- }
-
- BurstAotCompiler.WriteStaticLinkCppFile(TempSourceLibrary);
- }
- }
- }
- #endif
-
- /// <summary>
- /// Integration of the burst AOT compiler into the Unity build player pipeline
- /// </summary>
- internal class BurstAotCompiler
- {
- #if ENABLE_GENERATE_NATIVE_PLUGINS_FOR_ASSEMBLIES_API
- // When using the new player build API, don't write to Temp/StagingArea.
- // We still need code in Unity to support old versions of Burst not using the new API.
- // for that case, we will just pick up files written to the Temp/StagingArea.
- // So in order to not pick up files twice, use a different output location for the new
- // API.
- internal const string OutputBaseFolder = @"Temp/BurstOutput/";
- #else
- private const string OutputBaseFolder = @"Temp/StagingArea/";
- #endif
- private const string TempStagingManaged = OutputBaseFolder + @"Data/Managed/";
- private const string LibraryPlayerScriptAssemblies = "Library/PlayerScriptAssemblies";
- private const string TempManagedSymbols = @"Temp/ManagedSymbols/";
- internal const string BurstLinkXmlName = "burst.link.xml";
-
- internal struct BurstAOTSettings
- {
- public BuildSummary summary;
- public BurstPlatformAotSettings aotSettingsForTarget;
- public TargetPlatform targetPlatform;
- public TargetCpus targetCpus;
- public List<BurstAotCompiler.BurstOutputCombination> combinations;
- public ScriptingImplementation scriptingBackend;
- public string productName;
- public bool isSupported;
- public List<string> extraOptions;
- public Hash128 symbolDefinesHash;
-
- // Hash any fields that might have an effect on whether Bursted code needs to be recompiled
- // Note that the BurstPlatformAotSettings are saved and used separately, so they don't need to
- // be included in this hash.
- public Hash128 Hash()
- {
- var hc = new Hash128();
- hc.Append((int)(summary.options & (BuildOptions.InstallInBuildFolder | BuildOptions.Development)));
- hc.Append((int)targetPlatform);
- hc.Append(isSupported ? 1 : 0);
-
- if (targetCpus?.Cpus != null)
- {
- hc.Append(targetCpus.Cpus.Count);
- foreach (var cpu in targetCpus.Cpus)
- {
- hc.Append((int)cpu);
- }
- }
-
- if (combinations != null)
- {
- hc.Append(combinations.Count);
- foreach (var comb in combinations)
- {
- comb.HashInto(ref hc);
- }
- }
-
- if (extraOptions != null)
- {
- hc.Append(extraOptions.Count);
- foreach (var opt in extraOptions)
- {
- hc.Append(opt);
- }
- }
-
- hc.Append(symbolDefinesHash.u64_0);
- hc.Append(symbolDefinesHash.u64_1);
-
- hc.Append((int)scriptingBackend);
- hc.Append(productName);
-
- return hc;
- }
-
- public void Save()
- {
- var path = GetPath(BurstPlatformAotSettings.ResolveTarget(summary.platform));
- var hash = Hash();
- try
- {
- if (File.Exists(path))
- {
- // If the hashes match, don't touch the file so Bee will consider it unchanged
- var bytes = File.ReadAllBytes(path);
- var storedHash = new Hash128(BitConverter.ToUInt64(bytes, 0), BitConverter.ToUInt64(bytes, 8));
- if (storedHash == hash)
- {
- return;
- }
- }
-
- using (var f = new BufferedStream(File.OpenWrite(path)))
- {
- f.Write(BitConverter.GetBytes(hash.u64_0), 0, 8);
- f.Write(BitConverter.GetBytes(hash.u64_1), 0, 8);
- }
- }
- catch (Exception)
- {
- // If we for some reason fail to save the settings, delete the existing ones (if any) to be sure
- // we invalidate the cache and cause a recompilation
- try
- {
- if (File.Exists(path))
- {
- File.Delete(path);
- }
- }
- catch (Exception)
- {
- // Welp
- }
- }
- }
-
- public static string GetPath(BuildTarget? target)
- {
- var root = "Library/BurstCache";
- if (target.HasValue)
- {
- return $"{root}/AotSettings_{target.Value}.hash";
- }
- else
- {
- return $"{root}/AotSettings.hash";
- }
- }
- }
-
- static void CopyDirectory(string sourceDir, string destinationDir, bool recursive)
- {
- // Get information about the source directory
- var dir = new DirectoryInfo(sourceDir);
-
- // Check if the source directory exists
- if (!dir.Exists)
- throw new DirectoryNotFoundException($"Source directory not found: {dir.FullName}");
-
- // Cache directories before we start copying
- DirectoryInfo[] dirs = dir.GetDirectories();
-
- // Create the destination directory
- Directory.CreateDirectory(destinationDir);
-
- // Get the files in the source directory and copy to the destination directory
- foreach (FileInfo file in dir.GetFiles())
- {
- string targetFilePath = Path.Combine(destinationDir, file.Name);
- file.CopyTo(targetFilePath);
- }
-
- // If recursive and copying subdirectories, recursively call this method
- if (recursive)
- {
- foreach (DirectoryInfo subDir in dirs)
- {
- string newDestinationDir = Path.Combine(destinationDir, subDir.Name);
- CopyDirectory(subDir.FullName, newDestinationDir, true);
- }
- }
- }
-
- internal static IEnumerable<string> OnPostBuildPlayerScriptDLLsImpl(BurstAOTSettings settings, Assembly[] playerAssemblies)
- {
- var buildTarget = settings.summary.platform;
-
- string burstMiscAlongsidePath = "";
- if ((settings.summary.options & BuildOptions.InstallInBuildFolder) == 0)
- {
- burstMiscAlongsidePath = BurstPlatformAotSettings.FetchOutputPath(settings.summary, settings.productName);
- }
-
- HashSet<string> assemblyDefines = new HashSet<string>();
-
- // Early exit if burst is not activated or the platform is not supported
- if (BurstCompilerOptions.ForceDisableBurstCompilation || !settings.aotSettingsForTarget.EnableBurstCompilation)
- {
- return Array.Empty<string>();
- }
-
- var isDevelopmentBuild = (settings.summary.options & BuildOptions.Development) != 0;
-
- var commonOptions = new List<string>();
- var stagingFolder = Path.GetFullPath(TempStagingManaged);
-
- // grab the location of the root of the player folder - for handling nda platforms that require keys
- var keyFolder = BuildPipeline.GetPlaybackEngineDirectory(buildTarget, BuildOptions.None);
- commonOptions.Add(GetOption(OptionAotKeyFolder, keyFolder));
- commonOptions.Add(GetOption(OptionAotDecodeFolder, Path.Combine(Environment.CurrentDirectory, "Library", "Burst")));
-
- // Extract the TargetPlatform and Cpus from the current build settings
- commonOptions.Add(GetOption(OptionPlatform, settings.targetPlatform));
-
- // --------------------------------------------------------------------------------------------------------
- // 1) Calculate AssemblyFolders
- // These are the folders to look for assembly resolution
- // --------------------------------------------------------------------------------------------------------
- var assemblyFolders = new List<string> { stagingFolder };
-
- foreach (var assembly in playerAssemblies)
- AddAssemblyFolder(assembly.outputPath, stagingFolder, buildTarget, assemblyFolders);
-
- if (buildTarget == BuildTarget.WSAPlayer || buildTarget == BuildTarget.GameCoreXboxOne || buildTarget == BuildTarget.GameCoreXboxSeries)
- {
- // On UWP, not all assemblies are copied to StagingArea, so we want to
- // find all directories that we can reference assemblies from
- // If we don't do this, we will crash with AssemblyResolutionException
- // when following type references.
- foreach (var assembly in playerAssemblies)
- {
- foreach (var assemblyRef in assembly.compiledAssemblyReferences)
- AddAssemblyFolder(assemblyRef, stagingFolder, buildTarget, assemblyFolders);
- }
- }
-
- if (settings.extraOptions != null)
- {
- commonOptions.AddRange(settings.extraOptions);
- }
-
- // Copy assembly used during staging to have a trace
- if (BurstLoader.IsDebugging)
- {
- try
- {
- var copyAssemblyFolder = Path.Combine(Environment.CurrentDirectory, "Logs", "StagingAssemblies");
- try
- {
- if (Directory.Exists(copyAssemblyFolder)) Directory.Delete(copyAssemblyFolder);
- }
- catch
- {
- }
-
- if (!Directory.Exists(copyAssemblyFolder)) Directory.CreateDirectory(copyAssemblyFolder);
- foreach (var file in Directory.EnumerateFiles(stagingFolder))
- {
- File.Copy(file, Path.Combine(copyAssemblyFolder, Path.GetFileName(file)));
- }
- }
- catch
- {
- }
- }
-
- // --------------------------------------------------------------------------------------------------------
- // 2) Calculate root assemblies
- // These are the assemblies that the compiler will look for methods to compile
- // This list doesn't typically include .NET runtime assemblies but only assemblies compiled as part
- // of the current Unity project
- // --------------------------------------------------------------------------------------------------------
- var rootAssemblies = new List<string>();
- foreach (var playerAssembly in playerAssemblies)
- {
- #if ENABLE_GENERATE_NATIVE_PLUGINS_FOR_ASSEMBLIES_API
- var playerAssemblyPath = Path.GetFullPath(playerAssembly.outputPath);
- #else
- // the file at path `playerAssembly.outputPath` is actually not on the disk
- // while it is in the staging folder because OnPostBuildPlayerScriptDLLs is being called once the files are already
- // transferred to the staging folder, so we are going to work from it but we are reusing the file names that we got earlier
- var playerAssemblyPath = Path.Combine(stagingFolder, Path.GetFileName(playerAssembly.outputPath));
- #endif
-
- if (!File.Exists(playerAssemblyPath))
- {
- Debug.LogWarning($"Unable to find player assembly: {playerAssembly.outputPath}");
- }
- else
- {
- rootAssemblies.Add(playerAssemblyPath);
- commonOptions.Add(GetOption(OptionAssemblyDefines, $"{playerAssembly.name};{string.Join(";", playerAssembly.defines)}"));
- }
- }
-
- commonOptions.AddRange(rootAssemblies.Select(root => GetOption(OptionRootAssembly, root)));
-
- // --------------------------------------------------------------------------------------------------------
- // 4) Compile each combination
- //
- // Here bcl.exe is called for each target CPU combination
- // --------------------------------------------------------------------------------------------------------
-
- string debugLogFile = null;
- if (BurstLoader.IsDebugging)
- {
- // Reset log files
- try
- {
- var logDir = Path.Combine(Environment.CurrentDirectory, "Logs");
- debugLogFile = Path.Combine(logDir, "burst_bcl_editor.log");
- if (!Directory.Exists(logDir)) Directory.CreateDirectory(logDir);
- File.WriteAllText(debugLogFile, string.Empty);
- }
- catch
- {
- debugLogFile = null;
- }
- }
-
- if ((settings.summary.options & BuildOptions.InstallInBuildFolder) == 0)
- {
- CreateFolderForMiscFiles(burstMiscAlongsidePath);
- }
-
- // Log the targets generated by BurstReflection.FindExecuteMethods
- foreach (var combination in settings.combinations)
- {
- // Gets the output folder
- var stagingOutputFolder = Path.GetFullPath(Path.Combine(OutputBaseFolder, combination.OutputPath));
- var outputFilePrefix = Path.Combine(stagingOutputFolder, combination.LibraryName);
-
- var options = new List<string>(commonOptions)
- {
- GetOption(OptionAotOutputPath, outputFilePrefix),
- GetOption(OptionTempDirectory, Path.Combine(Environment.CurrentDirectory, "Temp", "Burst"))
- };
-
- foreach (var cpu in combination.TargetCpus.Cpus)
- {
- options.Add(GetOption(OptionTarget, cpu));
- }
-
- if (settings.targetPlatform == TargetPlatform.iOS || settings.targetPlatform == TargetPlatform.tvOS || settings.targetPlatform == TargetPlatform.Switch || settings.targetPlatform == TargetPlatform.visionOS)
- {
- options.Add(GetOption(OptionStaticLinkage));
- #if ENABLE_GENERATE_NATIVE_PLUGINS_FOR_ASSEMBLIES_API
- WriteStaticLinkCppFile($"{OutputBaseFolder}/{combination.OutputPath}");
- #endif
- }
-
- if (settings.targetPlatform == TargetPlatform.Windows)
- {
- options.Add(GetOption(OptionLinkerOptions, $"PdbAltPath=\"{settings.productName}_{combination.OutputPath}/{Path.GetFileNameWithoutExtension(combination.LibraryName)}.pdb\""));
- }
-
- #if UNITY_2022_2_OR_NEWER && UNITY_ANDROID
- if (settings.targetPlatform == TargetPlatform.Android)
- {
- // Enable Armv9 security features (PAC/BTI) if needed
- if (settings.aotSettingsForTarget.EnableArmv9SecurityFeatures)
- options.Add(GetOption(OptionBranchProtection, "Standard"));
- }
- #endif
-
- options.AddRange(assemblyFolders.Select(assemblyFolder => GetOption(OptionAotAssemblyFolder, assemblyFolder)));
-
- // Set the flag to print a message on missing MonoPInvokeCallback attribute on IL2CPP only
- if (settings.scriptingBackend == ScriptingImplementation.IL2CPP)
- {
- options.Add(GetOption(OptionPrintLogOnMissingPInvokeCallbackAttribute));
- }
-
- // Log the targets generated by BurstReflection.FindExecuteMethods
- if (BurstLoader.IsDebugging && debugLogFile != null)
- {
- try
- {
- var writer = new StringWriter();
- writer.WriteLine("-----------------------------------------------------------");
- writer.WriteLine("Combination: " + combination);
- writer.WriteLine("-----------------------------------------------------------");
-
- foreach (var option in options)
- {
- writer.WriteLine(option);
- }
-
- writer.WriteLine("Assemblies in AssemblyFolders:");
- foreach (var assemblyFolder in assemblyFolders)
- {
- writer.WriteLine("|- Folder: " + assemblyFolder);
- foreach (var assemblyOrDll in Directory.EnumerateFiles(assemblyFolder, "*.dll"))
- {
- var fileInfo = new FileInfo(assemblyOrDll);
- writer.WriteLine(" |- " + assemblyOrDll + " Size: " + fileInfo.Length + " Date: " + fileInfo.LastWriteTime);
- }
- }
-
- File.AppendAllText(debugLogFile, writer.ToString());
- }
- catch
- {
- // ignored
- }
- }
-
- // Allow burst to find managed symbols in the backup location in case the symbols are stripped in the build location
- options.Add(GetOption(OptionAotPdbSearchPaths, TempManagedSymbols));
-
- if (isDevelopmentBuild && Environment.GetEnvironmentVariable("UNITY_BURST_ENABLE_SAFETY_CHECKS_IN_PLAYER_BUILD") != null)
- {
- options.Add("--global-safety-checks-setting=ForceOn");
- }
-
-
- options.Add(GetOption(OptionGenerateLinkXml, Path.Combine("Temp", BurstLinkXmlName)));
-
- if (!string.IsNullOrWhiteSpace(settings.aotSettingsForTarget.DisabledWarnings))
- {
- options.Add(GetOption(OptionDisableWarnings, settings.aotSettingsForTarget.DisabledWarnings));
- }
-
- if (isDevelopmentBuild || settings.aotSettingsForTarget.EnableDebugInAllBuilds)
- {
- if (!isDevelopmentBuild)
- {
- Debug.LogWarning(
- "Symbols are being generated for burst compiled code, please ensure you intended this - see Burst AOT settings.");
- }
-
- options.Add(GetOption(OptionDebug,
- (settings.aotSettingsForTarget.DebugDataKind == DebugDataKind.Full) && (!combination.WorkaroundFullDebugInfo) ? "Full" : "LineOnly"));
- }
-
- if (!settings.aotSettingsForTarget.EnableOptimisations)
- {
- options.Add(GetOption(OptionDisableOpt));
- }
- else
- {
- switch (settings.aotSettingsForTarget.OptimizeFor)
- {
- case OptimizeFor.Default:
- case OptimizeFor.Balanced:
- options.Add(GetOption(OptionOptLevel, 2));
- break;
- case OptimizeFor.Performance:
- options.Add(GetOption(OptionOptLevel, 3));
- break;
- case OptimizeFor.Size:
- options.Add(GetOption(OptionOptForSize));
- options.Add(GetOption(OptionOptLevel, 3));
- break;
- case OptimizeFor.FastCompilation:
- options.Add(GetOption(OptionOptLevel, 1));
- break;
- }
- }
-
- if (BurstLoader.IsDebugging)
- {
- options.Add(GetOption("debug-logging"));
- }
-
- // Add list of assemblies to ignore
- var disabledAssemblies = BurstAssemblyDisable.GetDisabledAssemblies(BurstAssemblyDisable.DisableType.Player, BurstPlatformAotSettings.ResolveTarget(buildTarget).ToString());
- foreach (var discard in disabledAssemblies)
- {
- options.Add(GetOption(OptionDiscardAssemblies, discard));
- }
-
- // Write current options to the response file
- var responseFile = Path.GetTempFileName();
- File.WriteAllLines(responseFile, options);
-
- if (BurstLoader.IsDebugging)
- {
- Debug.Log($"bcl.exe {OptionBurstcSwitch} @{responseFile}\n\nResponse File:\n" + string.Join("\n", options));
- }
-
- try
- {
- var burstcSwitch = OptionBurstcSwitch;
-
- if (!string.IsNullOrEmpty(
- Environment.GetEnvironmentVariable("UNITY_BURST_DISABLE_INCREMENTAL_PLAYER_BUILDS")))
- {
- burstcSwitch = "";
- }
-
- if (BurstLoader.BclConfiguration.IsExecutableNative)
- {
- BclRunner.RunNativeProgram(
- BurstLoader.BclConfiguration.ExecutablePath,
- $"{burstcSwitch} {BclRunner.EscapeForShell("@" + responseFile)}",
- new BclOutputErrorParser());
- }
- else
- {
- BclRunner.RunManagedProgram(
- BurstLoader.BclConfiguration.ExecutablePath,
- $"{burstcSwitch} {BclRunner.EscapeForShell("@" + responseFile)}",
- new BclOutputErrorParser(),
- combination.EnvironmentVariables);
- }
-
- // Additionally copy the pdb to the root of the player build so run in editor also locates the symbols
- var pdbPath = $"{Path.Combine(stagingOutputFolder, combination.LibraryName)}.pdb";
- if (File.Exists(pdbPath))
- {
- var dstPath = Path.Combine(OutputBaseFolder, $"{combination.LibraryName}.pdb");
- File.Copy(pdbPath, dstPath, overwrite: true);
- }
- }
- catch (BuildFailedException)
- {
- throw;
- }
- catch (Exception e)
- {
- throw new BuildFailedException(e);
- }
- }
-
- PostProcessCombinations(settings.targetPlatform, settings.combinations, settings.summary);
-
- var pdbsRemainInBuild = isDevelopmentBuild || settings.aotSettingsForTarget.EnableDebugInAllBuilds || settings.targetPlatform == TargetPlatform.UWP;
-
- // Finally move out any symbols/misc files from the final output
- if ((settings.summary.options & BuildOptions.InstallInBuildFolder) == 0)
- {
- return CollateMiscFiles(settings.combinations, burstMiscAlongsidePath, pdbsRemainInBuild);
- }
-
- return Array.Empty<string>();
- }
-
- private static void AddAssemblyFolder(string assemblyRef, string stagingFolder, BuildTarget buildTarget,
- List<string> assemblyFolders)
- {
- // Exclude folders with assemblies already compiled in the `folder`
- var assemblyName = Path.GetFileName(assemblyRef);
- if (assemblyName != null && File.Exists(Path.Combine(stagingFolder, assemblyName)))
- {
- return;
- }
-
- var directory = Path.GetDirectoryName(assemblyRef);
- if (directory != null)
- {
- var fullPath = Path.GetFullPath(directory);
- if (IsMonoReferenceAssemblyDirectory(fullPath) || IsDotNetStandardAssemblyDirectory(fullPath))
- {
- // Don't pass reference assemblies to burst because they contain methods without implementation
- // If burst accidentally resolves them, it will emit calls to burst_abort.
- fullPath = Path.Combine(EditorApplication.applicationContentsPath, "MonoBleedingEdge/lib/mono");
- #if UNITY_2021_2_OR_NEWER
- // In 2021.2 we got multiple mono distributions, per platform.
- fullPath = Path.Combine(fullPath, "unityaot-" + BuildTargetDiscovery.GetPlatformProfileSuffix(buildTarget));
- #else
- fullPath = Path.Combine(fullPath, "unityaot");
- #endif
- fullPath = Path.GetFullPath(fullPath); // GetFullPath will normalize path separators to OS native format
- if (!assemblyFolders.Contains(fullPath))
- assemblyFolders.Add(fullPath);
-
- fullPath = Path.Combine(fullPath, "Facades");
- if (!assemblyFolders.Contains(fullPath))
- assemblyFolders.Add(fullPath);
- }
- else if (!assemblyFolders.Contains(fullPath))
- {
- assemblyFolders.Add(fullPath);
- }
- }
- }
-
- private static void CreateFolderForMiscFiles(string finalFolder)
- {
- try
- {
- if (Directory.Exists(finalFolder)) Directory.Delete(finalFolder,true);
- }
- catch
- {
- }
- Directory.CreateDirectory(finalFolder);
- }
-
- private static IEnumerable<string> CollateMiscFiles(List<BurstOutputCombination> combinations, string finalFolder, bool retainPdbs)
- {
- foreach (var combination in combinations)
- {
- var inputPath = Path.GetFullPath(Path.Combine(OutputBaseFolder, combination.OutputPath));
- var outputPath = Path.Combine(finalFolder, combination.OutputPath);
- Directory.CreateDirectory(outputPath);
- if (!Directory.Exists(inputPath))
- continue;
- var files = Directory.GetFiles(inputPath);
- var directories = Directory.GetDirectories(inputPath);
- foreach (var fileName in files)
- {
- var lowerCase = fileName.ToLower();
- if ( (!retainPdbs && lowerCase.EndsWith(".pdb")) || lowerCase.EndsWith(".dsym") || lowerCase.EndsWith(".txt"))
- {
- // Move the file out of the staging area so its not included in the build
- File.Move(fileName, Path.Combine(outputPath, Path.GetFileName(fileName)));
- }
- else if (!combination.CollateDirectory)
- {
- yield return fileName;
- }
- }
- foreach (var fileName in directories)
- {
- var lowerCase = fileName.ToLower();
- if ( (!retainPdbs && lowerCase.EndsWith(".pdb")) || lowerCase.EndsWith(".dsym") || lowerCase.EndsWith(".txt"))
- {
- // Move the folder out of the staging area so its not included in the build
- Directory.Move(fileName, Path.Combine(outputPath, Path.GetFileName(fileName)));
- }
- else if (!combination.CollateDirectory)
- {
- yield return fileName;
- }
- }
-
- if (combination.CollateDirectory)
- yield return inputPath;
- }
- }
-
- private static bool AndroidHasX86(AndroidArchitecture architecture)
- {
- // Deal with rename that occured
- AndroidArchitecture val;
- if (AndroidArchitecture.TryParse("X86", out val))
- {
- return (architecture & val)!=0;
- }
- else if (AndroidArchitecture.TryParse("x86", out val))
- {
- return (architecture & val)!=0;
- }
- return false;
- }
- private static bool AndroidHasX86_64(AndroidArchitecture architecture)
- {
- // Deal with rename that occured
- AndroidArchitecture val;
- if (AndroidArchitecture.TryParse("X86_64", out val))
- {
- return (architecture & val)!=0;
- }
- else if (AndroidArchitecture.TryParse("x86_64", out val))
- {
- return (architecture & val)!=0;
- }
- return false;
- }
-
- private enum SimulatorPlatforms
- {
- iOS,
- tvOS
- }
- private static bool IsForSimulator(BuildTarget target)
- {
- switch (target)
- {
- case BuildTarget.iOS:
- return IsForSimulator(SimulatorPlatforms.iOS);
- case BuildTarget.tvOS:
- return IsForSimulator(SimulatorPlatforms.tvOS);
- default:
- return false;
- }
- }
- private static bool IsForSimulator(TargetPlatform targetPlatform)
- {
- switch (targetPlatform)
- {
- case TargetPlatform.iOS:
- return IsForSimulator(SimulatorPlatforms.iOS);
- case TargetPlatform.tvOS:
- return IsForSimulator(SimulatorPlatforms.tvOS);
- default:
- return false;
- }
- }
- private static bool IsForSimulator(SimulatorPlatforms simulatorPlatforms)
- {
- switch (simulatorPlatforms)
- {
- case SimulatorPlatforms.iOS:
- return UnityEditor.PlayerSettings.iOS.sdkVersion == iOSSdkVersion.SimulatorSDK;
- case SimulatorPlatforms.tvOS:
- return UnityEditor.PlayerSettings.tvOS.sdkVersion == tvOSSdkVersion.Simulator;
- }
-
- return false;
- }
-
- public static void WriteStaticLinkCppFile(string dir)
- {
- Directory.CreateDirectory(dir);
- string cppPath = Path.Combine(dir, "lib_burst_generated.cpp");
- // Additionally we need a small cpp file (weak symbols won't unfortunately override directly from the libs
- //presumably due to link order?
- File.WriteAllText(cppPath, @"
- extern ""C""
- {
- void Staticburst_initialize(void* );
- void* StaticBurstStaticMethodLookup(void* );
-
- int burst_enable_static_linkage = 1;
- void burst_initialize(void* i) { Staticburst_initialize(i); }
- void* BurstStaticMethodLookup(void* i) { return StaticBurstStaticMethodLookup(i); }
- }
- ");
- }
-
- /// <summary>
- /// Collect CPU combinations for the specified TargetPlatform and TargetCPU
- /// </summary>
- /// <param name="targetPlatform">The target platform (e.g Windows)</param>
- /// <param name="targetCpus">The target CPUs (e.g X64_SSE4)</param>
- /// <param name="report">Error reporting</param>
- /// <returns>The list of CPU combinations</returns>
- internal static List<BurstOutputCombination> CollectCombinations(TargetPlatform targetPlatform, TargetCpus targetCpus, BuildSummary summary)
- {
- var combinations = new List<BurstOutputCombination>();
-
- if (targetPlatform == TargetPlatform.macOS)
- {
- // NOTE: OSX has a special folder for the plugin
- // Declared in GetStagingAreaPluginsFolder
- // PlatformDependent\OSXPlayer\Extensions\Managed\OSXDesktopStandalonePostProcessor.cs
- var outputPath = Path.Combine(Path.GetFileName(summary.outputPath), "Contents", "Plugins");
-
- // Based on : PlatformDependent/OSXPlayer/Extension/OSXStandaloneBuildWindowExtension.cs
- var aotSettings = BurstPlatformAotSettings.GetOrCreateSettings(BuildTarget.StandaloneOSX);
- var buildTargetName = BuildPipeline.GetBuildTargetName(BuildTarget.StandaloneOSX);
- var architecture = EditorUserBuildSettings.GetPlatformSettings(buildTargetName, "Architecture").ToLowerInvariant();
- switch (architecture)
- {
- case "x64":
- combinations.Add(new BurstOutputCombination(outputPath, aotSettings.GetDesktopCpu64Bit()));
- break;
- case "arm64":
- // According to
- // https://web.archive.org/web/20220504192056/https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/Support/AArch64TargetParser.def#L240
- // M1 is equivalent to Armv8.5-A, so it supports everything from HALFFP target
- // (there's no direct confirmation on crypto because it's not mandatory)
- combinations.Add(new BurstOutputCombination(outputPath, new TargetCpus(BurstTargetCpu.ARMV8A_AARCH64_HALFFP)));
- break;
- default:
- combinations.Add(new BurstOutputCombination(Path.Combine(outputPath, "x64"), aotSettings.GetDesktopCpu64Bit()));
- combinations.Add(new BurstOutputCombination(Path.Combine(outputPath, "arm64"), new TargetCpus(BurstTargetCpu.ARMV8A_AARCH64_HALFFP)));
- break;
- }
- }
- else if (targetPlatform == TargetPlatform.iOS || targetPlatform == TargetPlatform.tvOS || targetPlatform == TargetPlatform.visionOS || targetPlatform == TargetPlatform.visionSimulator)
- {
- if (IsForSimulator(targetPlatform))
- {
- Debug.LogWarning("Burst Does not currently support the simulator, burst is disabled for this build.");
- }
- else if (Application.platform != RuntimePlatform.OSXEditor)
- {
- Debug.LogWarning("Burst Cross Compilation to iOS/tvOS for standalone player, is only supported on OSX Editor at this time, burst is disabled for this build.");
- }
- else
- {
- // Looks like a way to detect iOS CPU capabilities in runtime (like getauxval()) is sysctlbyname()
- // https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics
- // TODO: add support for it when needed, for now using the lowest common denominator
- // https://web.archive.org/web/20220504192056/https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/Support/AArch64TargetParser.def#L240
- // This LLVM code implies A11 is the first Armv8.2-A CPU
- // However, it doesn't support dotprod, so we can't consider it equivalent to our HALFFP variant
- // A13 (equivalent to Armv8.4-A) and M1 seem to be the first CPUs we can claim HALFFP compatible
- // Since we need to support older CPUs, have to use the "basic" Armv8A here
- combinations.Add(new BurstOutputCombination("StaticLibraries", new TargetCpus(BurstTargetCpu.ARMV8A_AARCH64)));
- }
- }
- else if (targetPlatform == TargetPlatform.Android)
- {
- // TODO: would be better to query AndroidNdkRoot (but thats not exposed from unity)
- string ndkRoot = null;
- var targetAPILevel = PlayerSettings.Android.GetMinTargetAPILevel();
- var environment = new Dictionary<string, string>();
- #if UNITY_ANDROID
- ndkRoot = UnityEditor.Android.AndroidExternalToolsSettings.ndkRootPath;
- #else
- // 2019.1 now has an embedded ndk
- if (EditorPrefs.HasKey("NdkUseEmbedded"))
- {
- if (EditorPrefs.GetBool("NdkUseEmbedded"))
- {
- ndkRoot = Path.Combine(BuildPipeline.GetPlaybackEngineDirectory(BuildTarget.Android, BuildOptions.None), "NDK");
- }
- else
- {
- ndkRoot = EditorPrefs.GetString("AndroidNdkRootR16b");
- }
- }
- #endif
-
- // If we still don't have a valid root, try the old key
- if (string.IsNullOrEmpty(ndkRoot))
- {
- ndkRoot = EditorPrefs.GetString("AndroidNdkRoot");
- }
-
- // Verify the directory at least exists, if not we fall back to ANDROID_NDK_ROOT current setting
- if (!string.IsNullOrEmpty(ndkRoot) && !Directory.Exists(ndkRoot))
- {
- ndkRoot = null;
- }
-
- // Always set the ANDROID_NDK_ROOT (if we got a valid result from above), so BCL knows where to find the Android toolchain and its the one the user expects
- if (!string.IsNullOrEmpty(ndkRoot))
- {
- environment["ANDROID_NDK_ROOT"] = ndkRoot;
- }
-
- environment["BURST_ANDROID_MIN_API_LEVEL"] = $"{targetAPILevel}";
-
- // Setting tempburstlibs/ as the interim target directory
- // Don't target libs/ directly because incremental build pipeline doesn't expect the so's at that path
- // Rather, so's are copied to the actual location in the gradle project in BurstAndroidGradlePostprocessor
- var androidTargetArch = PlayerSettings.Android.targetArchitectures;
- if ((androidTargetArch & AndroidArchitecture.ARMv7) != 0)
- {
- combinations.Add(new BurstOutputCombination("tempburstlibs/armeabi-v7a", new TargetCpus(BurstTargetCpu.ARMV7A_NEON32), collateDirectory: true, environment: environment));
- }
-
- if ((androidTargetArch & AndroidArchitecture.ARM64) != 0)
- {
- var aotSettingsForTarget = BurstPlatformAotSettings.GetOrCreateSettings(summary.platform);
- combinations.Add(new BurstOutputCombination("tempburstlibs/arm64-v8a", aotSettingsForTarget.GetAndroidCpuArm64(), collateDirectory: true, environment: environment));
- }
- #if UNITY_2019_4_OR_NEWER
- if (AndroidHasX86(androidTargetArch))
- {
- combinations.Add(new BurstOutputCombination("tempburstlibs/x86", new TargetCpus(BurstTargetCpu.X86_SSE4), collateDirectory: true, environment: environment));
- }
- if (AndroidHasX86_64(androidTargetArch))
- {
- combinations.Add(new BurstOutputCombination("tempburstlibs/x86_64", new TargetCpus(BurstTargetCpu.X64_SSE4), collateDirectory: true, environment: environment));
- }
- #endif
- }
- else if (targetPlatform == TargetPlatform.UWP)
- {
- var aotSettingsForTarget = BurstPlatformAotSettings.GetOrCreateSettings(summary.platform);
-
- if (EditorUserBuildSettings.wsaUWPBuildType == WSAUWPBuildType.ExecutableOnly)
- {
- combinations.Add(new BurstOutputCombination($"Plugins/{GetUWPTargetArchitecture()}", targetCpus, collateDirectory: true));
- }
- else
- {
- combinations.Add(new BurstOutputCombination("Plugins/x64", aotSettingsForTarget.GetDesktopCpu64Bit(), collateDirectory: true));
- combinations.Add(new BurstOutputCombination("Plugins/x86", aotSettingsForTarget.GetDesktopCpu32Bit(), collateDirectory: true));
- combinations.Add(new BurstOutputCombination("Plugins/ARM", new TargetCpus(BurstTargetCpu.THUMB2_NEON32), collateDirectory: true));
- combinations.Add(new BurstOutputCombination("Plugins/ARM64", new TargetCpus(BurstTargetCpu.ARMV8A_AARCH64), collateDirectory: true));
- }
- }
- #if !UNITY_2022_2_OR_NEWER
- else if (targetPlatform == TargetPlatform.Lumin)
- {
- // Set the LUMINSDK_UNITY so bcl.exe will be able to find the SDK
- if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("LUMINSDK_UNITY")))
- {
- var sdkRoot = EditorPrefs.GetString("LuminSDKRoot");
- if (!string.IsNullOrEmpty(sdkRoot))
- {
- Environment.SetEnvironmentVariable("LUMINSDK_UNITY", sdkRoot);
- }
- }
- combinations.Add(new BurstOutputCombination("Data/Plugins/", targetCpus));
- }
- #endif
- else if (targetPlatform == TargetPlatform.Switch)
- {
- combinations.Add(new BurstOutputCombination("NativePlugins/", targetCpus));
- }
- else
- {
- if (targetPlatform == TargetPlatform.Windows)
- {
- // This is what is expected by PlatformDependent\Win\Plugins.cpp
- if (targetCpus.IsX86())
- {
- combinations.Add(new BurstOutputCombination("Data/Plugins/x86", targetCpus, collateDirectory: true));
- }
- else
- {
- var windowsArchitecture = GetWindows64BitTargetArchitecture();
- if (string.Equals(windowsArchitecture, "ARM64", StringComparison.OrdinalIgnoreCase))
- {
- combinations.Add(new BurstOutputCombination("Data/Plugins/ARM64", targetCpus, collateDirectory: true, workaroundBrokenDebug: true));
- }
- else
- {
- combinations.Add(new BurstOutputCombination("Data/Plugins/x86_64", targetCpus, collateDirectory: true));
- }
- }
- }
- else
- {
- // Safeguard
- combinations.Add(new BurstOutputCombination("Data/Plugins/", targetCpus));
- }
- }
-
- return combinations;
- }
-
- private static void PostProcessCombinations(TargetPlatform targetPlatform, List<BurstOutputCombination> combinations, BuildSummary summary)
- {
- if (targetPlatform == TargetPlatform.macOS && combinations.Count > 1)
- {
- // Figure out which files we need to lipo
- string outputSymbolsDir = null;
- var outputDir = Path.Combine(OutputBaseFolder, Path.GetFileName(summary.outputPath), "Contents", "Plugins");
-
- var sliceCount = combinations.Count;
- var binarySlices = new string[sliceCount];
- var debugSymbolSlices = new string[sliceCount];
-
- for (int i = 0; i < sliceCount; i++)
- {
- var slice = combinations[i];
-
- var binaryFileName = slice.LibraryName + ".bundle";
- var binaryPath = Path.Combine(OutputBaseFolder, slice.OutputPath, binaryFileName);
- binarySlices[i] = binaryPath;
-
- // Only attempt to lipo symbols if they actually exist
- var dsymPath = binaryPath + ".dsym";
- var debugSymbolsPath = Path.Combine(dsymPath, "Contents", "Resources", "DWARF", binaryFileName);
- if (File.Exists(debugSymbolsPath))
- {
- if (string.IsNullOrWhiteSpace(outputSymbolsDir))
- {
- // Copy over the symbols from the first combination for metadata files which we aren't merging, like Info.plist
- var outputDsymPath = Path.Combine(outputDir, binaryFileName + ".dsym");
- CopyDirectory(dsymPath, outputDsymPath, true);
-
- outputSymbolsDir = Path.Combine(outputDsymPath, "Contents", "Resources", "DWARF");
- }
-
- debugSymbolSlices[i] = debugSymbolsPath;
- }
- }
-
- // lipo combinations together
- var outBinaryFileName = combinations[0].LibraryName + ".bundle";
- RunLipo(binarySlices, Path.Combine(outputDir, outBinaryFileName));
-
- if (!string.IsNullOrWhiteSpace(outputSymbolsDir))
- RunLipo(debugSymbolSlices, Path.Combine(outputSymbolsDir, outBinaryFileName));
-
- // Remove single-slice binary so they don't end up in the build
- for (int i = 0; i < sliceCount; i++)
- Directory.Delete(Path.GetDirectoryName(binarySlices[i]), true);
-
- // Since we have combined the files, we need to adjust combinations for the next step
- var outFolder = Path.GetDirectoryName(combinations[0].OutputPath); // remove platform folder
- combinations.Clear();
- combinations.Add(new BurstOutputCombination(outFolder, new TargetCpus()));
- }
- }
-
- private static void RunLipo(string[] inputFiles, string outputFile)
- {
- var outputDir = Path.GetDirectoryName(outputFile);
- Directory.CreateDirectory(outputDir);
-
- var cmdLine = new StringBuilder();
- foreach (var input in inputFiles)
- {
- if (string.IsNullOrEmpty(input))
- continue;
-
- cmdLine.Append(BclRunner.EscapeForShell(input));
- cmdLine.Append(' ');
- }
-
- cmdLine.Append("-create -output ");
- cmdLine.Append(BclRunner.EscapeForShell(outputFile));
-
- string lipoPath;
-
- var currentEditorPlatform = Application.platform;
- switch (currentEditorPlatform)
- {
- case RuntimePlatform.LinuxEditor:
- lipoPath = Path.Combine(BurstLoader.BclConfiguration.FolderPath, "hostlin", "llvm-lipo");
- break;
-
- case RuntimePlatform.OSXEditor:
- lipoPath = Path.Combine(BurstLoader.BclConfiguration.FolderPath, "hostmac", "llvm-lipo");
- break;
-
- case RuntimePlatform.WindowsEditor:
- lipoPath = Path.Combine(BurstLoader.BclConfiguration.FolderPath, "hostwin", "llvm-lipo.exe");
- break;
-
- default:
- throw new NotSupportedException("Unknown Unity editor platform: " + currentEditorPlatform);
- }
-
- BclRunner.RunNativeProgram(lipoPath, cmdLine.ToString(), null);
- }
-
- internal static Assembly[] GetPlayerAssemblies(BuildReport report)
- {
- // We need to build the list of root assemblies based from the "PlayerScriptAssemblies" folder.
- // This is so we compile the versions of the library built for the individual platforms, not the editor version.
- var oldOutputDir = EditorCompilationInterface.GetCompileScriptsOutputDirectory();
- try
- {
- EditorCompilationInterface.SetCompileScriptsOutputDirectory(LibraryPlayerScriptAssemblies);
-
- var shouldIncludeTestAssemblies = report.summary.options.HasFlag(BuildOptions.IncludeTestAssemblies);
-
- #if UNITY_2021_1_OR_NEWER
- // Workaround that with 'Server Build' ticked in the build options, since there is no 'AssembliesType.Server'
- // enum, we need to manually add the BuildingForHeadlessPlayer compilation option.
-
- #if UNITY_2022_1_OR_NEWER
- var isHeadless = report.summary.subtarget == (int)StandaloneBuildSubtarget.Server;
- #elif UNITY_2021_2_OR_NEWER
- // A really really really gross hack - thanks Cristian Mazo! Querying the BuildOptions.EnableHeadlessMode is
- // obselete, but accessing its integer value is not... Note: this is just the temporary workaround to unblock
- // us (as of 1st June 2021, I say this with **much hope** that it is indeed temporary!).
- var isHeadless = report.summary.options.HasFlag((BuildOptions)16384);
- #else
- var isHeadless = report.summary.options.HasFlag(BuildOptions.EnableHeadlessMode);
- #endif
- if (isHeadless)
- {
- var compilationOptions = EditorCompilationInterface.GetAdditionalEditorScriptCompilationOptions();
- compilationOptions |= EditorScriptCompilationOptions.BuildingForHeadlessPlayer;
-
- if (shouldIncludeTestAssemblies)
- {
- compilationOptions |= EditorScriptCompilationOptions.BuildingIncludingTestAssemblies;
- }
-
- return CompilationPipeline.ToAssemblies(CompilationPipeline.GetScriptAssemblies(EditorCompilationInterface.Instance, compilationOptions));
- }
- else
- {
- return CompilationPipeline.GetAssemblies(shouldIncludeTestAssemblies ? AssembliesType.Player : AssembliesType.PlayerWithoutTestAssemblies);
- }
- #else
- // Workaround that with 'Server Build' ticked in the build options, since there is no 'AssembliesType.Server'
- // enum, we need to manually add the 'UNITY_SERVER' define to the player assembly search list.
- if (report.summary.options.HasFlag(BuildOptions.EnableHeadlessMode))
- {
- var compilationOptions = EditorCompilationInterface.GetAdditionalEditorScriptCompilationOptions();
- if (shouldIncludeTestAssemblies)
- {
- compilationOptions |= EditorScriptCompilationOptions.BuildingIncludingTestAssemblies;
- }
-
- return CompilationPipeline.GetPlayerAssemblies(EditorCompilationInterface.Instance, compilationOptions, new string[] { "UNITY_SERVER" });
- }
- else
- {
- return CompilationPipeline.GetAssemblies(shouldIncludeTestAssemblies ? AssembliesType.Player : AssembliesType.PlayerWithoutTestAssemblies);
- }
- #endif
- }
- finally
- {
- EditorCompilationInterface.SetCompileScriptsOutputDirectory(oldOutputDir); // restore output directory back to original value
- }
- }
-
- private static bool IsMonoReferenceAssemblyDirectory(string path)
- {
- var editorDir = Path.GetFullPath(EditorApplication.applicationContentsPath);
- return path.IndexOf(editorDir, StringComparison.OrdinalIgnoreCase) != -1 && path.IndexOf("MonoBleedingEdge", StringComparison.OrdinalIgnoreCase) != -1 && path.IndexOf("-api", StringComparison.OrdinalIgnoreCase) != -1;
- }
-
- private static bool IsDotNetStandardAssemblyDirectory(string path)
- {
- var editorDir = Path.GetFullPath(EditorApplication.applicationContentsPath);
- return path.IndexOf(editorDir, StringComparison.OrdinalIgnoreCase) != -1 && path.IndexOf("netstandard", StringComparison.OrdinalIgnoreCase) != -1 && path.IndexOf("shims", StringComparison.OrdinalIgnoreCase) != -1;
- }
-
- internal static TargetPlatform GetTargetPlatformAndDefaultCpu(BuildTarget target, out TargetCpus targetCpu, BurstPlatformAotSettings aotSettingsForTarget)
- {
- var platform = TryGetTargetPlatform(target, out targetCpu, aotSettingsForTarget);
- if (!platform.HasValue)
- {
- throw new NotSupportedException("The target platform " + target + " is not supported by the burst compiler");
- }
- return platform.Value;
- }
-
- internal static bool IsSupportedPlatform(BuildTarget target, BurstPlatformAotSettings aotSettingsForTarget)
- {
- return TryGetTargetPlatform(target, out var _, aotSettingsForTarget).HasValue;
- }
-
- private static TargetPlatform? TryGetTargetPlatform(BuildTarget target, out TargetCpus targetCpus, BurstPlatformAotSettings aotSettingsForTarget)
- {
- switch (target)
- {
- case BuildTarget.StandaloneWindows:
- targetCpus = aotSettingsForTarget.GetDesktopCpu32Bit();
- return TargetPlatform.Windows;
- case BuildTarget.StandaloneWindows64:
- var windowsArchitecture = GetWindows64BitTargetArchitecture();
-
- if (string.Equals(windowsArchitecture, "x64", StringComparison.OrdinalIgnoreCase))
- {
- targetCpus = aotSettingsForTarget.GetDesktopCpu64Bit();
- }
- else if (string.Equals(windowsArchitecture, "ARM64", StringComparison.OrdinalIgnoreCase))
- {
- targetCpus = new TargetCpus(BurstTargetCpu.ARMV8A_AARCH64);
- }
- else
- {
- throw new InvalidOperationException("Unknown Windows 64 Bit CPU architecture: " + windowsArchitecture);
- }
- return TargetPlatform.Windows;
- case BuildTarget.StandaloneOSX:
- targetCpus = aotSettingsForTarget.GetDesktopCpu64Bit();
- return TargetPlatform.macOS;
- case BuildTarget.StandaloneLinux64:
- targetCpus = aotSettingsForTarget.GetDesktopCpu64Bit();
- return TargetPlatform.Linux;
- case BuildTarget.WSAPlayer:
- {
- var uwpArchitecture = GetUWPTargetArchitecture();
- if (string.Equals(uwpArchitecture, "x64", StringComparison.OrdinalIgnoreCase))
- {
- targetCpus = aotSettingsForTarget.GetDesktopCpu64Bit();
- }
- else if (string.Equals(uwpArchitecture, "x86", StringComparison.OrdinalIgnoreCase))
- {
- targetCpus = aotSettingsForTarget.GetDesktopCpu32Bit();
- }
- else if (string.Equals(uwpArchitecture, "ARM", StringComparison.OrdinalIgnoreCase))
- {
- targetCpus = new TargetCpus(BurstTargetCpu.THUMB2_NEON32);
- }
- else if (string.Equals(uwpArchitecture, "ARM64", StringComparison.OrdinalIgnoreCase))
- {
- targetCpus = new TargetCpus(BurstTargetCpu.ARMV8A_AARCH64);
- }
- else
- {
- throw new InvalidOperationException("Unknown UWP CPU architecture: " + uwpArchitecture);
- }
-
- return TargetPlatform.UWP;
- }
- case BuildTarget.GameCoreXboxOne:
- targetCpus = new TargetCpus(BurstTargetCpu.AVX);
- return TargetPlatform.GameCoreXboxOne;
- case BuildTarget.GameCoreXboxSeries:
- targetCpus = new TargetCpus(BurstTargetCpu.AVX2);
- return TargetPlatform.GameCoreXboxSeries;
- case BuildTarget.PS4:
- targetCpus = new TargetCpus(BurstTargetCpu.X64_SSE4);
- return TargetPlatform.PS4;
- case BuildTarget.Android:
- targetCpus = new TargetCpus(BurstTargetCpu.ARMV7A_NEON32);
- return TargetPlatform.Android;
- case BuildTarget.iOS:
- targetCpus = new TargetCpus(BurstTargetCpu.ARMV7A_NEON32);
- return TargetPlatform.iOS;
- case BuildTarget.tvOS:
- targetCpus = new TargetCpus(BurstTargetCpu.ARMV8A_AARCH64);
- return TargetPlatform.tvOS;
- #if !UNITY_2022_2_OR_NEWER
- case BuildTarget.Lumin:
- targetCpus = new TargetCpus(BurstTargetCpu.ARMV8A_AARCH64);
- return TargetPlatform.Lumin;
- #endif
- case BuildTarget.Switch:
- targetCpus = new TargetCpus(BurstTargetCpu.ARMV8A_AARCH64);
- return TargetPlatform.Switch;
- case BuildTarget.PS5:
- targetCpus = new TargetCpus(BurstTargetCpu.AVX2);
- return TargetPlatform.PS5;
- }
-
- #if UNITY_2023_3_OR_NEWER
- const int buildTargetVisionOS = (int)BuildTarget.VisionOS;
- #else
- const int buildTargetVisionOS = 47;
- #endif
- if ((int)target == buildTargetVisionOS)
- {
- targetCpus = new TargetCpus(BurstTargetCpu.ARMV8A_AARCH64);
- // An SDK Version of "0" indicates that the visionOS simulator SDK is not being
- // used, so assume this is the device SDK instead.
- return GetVisionSdkVersion() == 0 ? TargetPlatform.visionOS : TargetPlatform.visionSimulator;
- }
-
- #if UNITY_2022_1_OR_NEWER
- const int qnxTarget = (int)BuildTarget.QNX;
- #else
- const int qnxTarget = 46;
- #endif
- if (qnxTarget == (int)target)
- {
- // QNX is supported on 2019.4 (shadow branch), 2020.3 (shadow branch) and 2022.1+ (official).
- var qnxArchitecture = GetQNXTargetArchitecture();
- if ("Arm64" == qnxArchitecture)
- {
- targetCpus = new TargetCpus(BurstTargetCpu.ARMV8A_AARCH64);
- }
- else if ("X64" == qnxArchitecture)
- {
- targetCpus = new TargetCpus(BurstTargetCpu.X64_SSE4);
- }
- else if ("X86" == qnxArchitecture)
- {
- targetCpus = new TargetCpus(BurstTargetCpu.X86_SSE4);
- }
- else if ("Arm32" == qnxArchitecture)
- {
- targetCpus = new TargetCpus(BurstTargetCpu.ARMV7A_NEON32);
- }
- else
- {
- throw new InvalidOperationException("Unknown QNX CPU architecture: " + qnxArchitecture);
- }
- return TargetPlatform.QNX;
- }
-
- #if UNITY_2021_2_OR_NEWER
- const int embeddedLinuxTarget = (int)BuildTarget.EmbeddedLinux;
- #else
- const int embeddedLinuxTarget = 45;
- #endif
- if (embeddedLinuxTarget == (int)target)
- {
- //EmbeddedLinux is supported on 2019.4 (shadow branch), 2020.3 (shadow branch) and 2021.2+ (official).
- var embeddedLinuxArchitecture = GetEmbeddedLinuxTargetArchitecture();
- if ("Arm64" == embeddedLinuxArchitecture)
- {
- targetCpus = new TargetCpus(BurstTargetCpu.ARMV8A_AARCH64);
- }
- else if ("X64" == embeddedLinuxArchitecture)
- {
- targetCpus = new TargetCpus(BurstTargetCpu.X64_SSE2); //lowest supported for now
- }
- else if (("X86" == embeddedLinuxArchitecture) || ("Arm32" == embeddedLinuxArchitecture))
- {
- //32bit platforms cannot be support with the current SDK/Toolchain combination.
- //i686-embedded-linux-gnu/8.3.0\libgcc.a(_moddi3.o + _divdi3.o): contains a compressed section, but zlib is not available
- //_moddi3.o + _divdi3.o are required by LLVM for 64bit operations on 32bit platforms.
- throw new InvalidOperationException($"No EmbeddedLinux Burst Support on {embeddedLinuxArchitecture} architecture.");
- }
- else
- {
- throw new InvalidOperationException("Unknown EmbeddedLinux CPU architecture: " + embeddedLinuxArchitecture);
- }
- return TargetPlatform.EmbeddedLinux;
- }
-
- targetCpus = new TargetCpus(BurstTargetCpu.Auto);
- return null;
- }
-
- private static string GetWindows64BitTargetArchitecture()
- {
- var buildTargetName = BuildPipeline.GetBuildTargetName(BuildTarget.StandaloneWindows64);
- var architecture = EditorUserBuildSettings.GetPlatformSettings(buildTargetName, "Architecture").ToLowerInvariant();
-
- if (string.Equals(architecture, "x64", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(architecture, "ARM64", StringComparison.OrdinalIgnoreCase))
- {
- return architecture;
- }
-
- // Default to x64 if editor user build setting is garbage
- return "x64";
- }
-
- private static string GetUWPTargetArchitecture()
- {
- var architecture = EditorUserBuildSettings.wsaArchitecture;
-
- if (string.Equals(architecture, "x64", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(architecture, "x86", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(architecture, "ARM", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(architecture, "ARM64", StringComparison.OrdinalIgnoreCase))
- {
- return architecture;
- }
-
- // Default to x64 if editor user build setting is garbage
- return "x64";
- }
-
- private static string GetEmbeddedLinuxTargetArchitecture()
- {
- var flags = System.Reflection.BindingFlags.Public |
- System.Reflection.BindingFlags.Static |
- System.Reflection.BindingFlags.FlattenHierarchy;
- var property = typeof(EditorUserBuildSettings).GetProperty("selectedEmbeddedLinuxArchitecture", flags);
- if (null == property)
- {
- return "NOT_FOUND";
- }
- var value = (int)property.GetValue(null, null);
- switch (value)
- {
- case /*UnityEditor.EmbeddedLinuxArchitecture.Arm64*/ 0: return "Arm64";
- case /*UnityEditor.EmbeddedLinuxArchitecture.Arm32*/ 1: return "Arm32";
- case /*UnityEditor.EmbeddedLinuxArchitecture.X64*/ 2: return "X64";
- case /*UnityEditor.EmbeddedLinuxArchitecture.X86*/ 3: return "X86";
- default: return $"UNKNOWN_{value}";
- }
- }
-
- private static string GetQNXTargetArchitecture()
- {
- var flags = System.Reflection.BindingFlags.Public |
- System.Reflection.BindingFlags.Static |
- System.Reflection.BindingFlags.FlattenHierarchy;
- var property = typeof(EditorUserBuildSettings).GetProperty("selectedQnxArchitecture", flags);
- if (null == property)
- {
- return "NOT_FOUND";
- }
- var value = (int)property.GetValue(null, null);
- switch (value)
- {
- case /*UnityEditor.QNXArchitecture.Arm64*/ 0: return "Arm64";
- case /*UnityEditor.QNXArchitecture.Arm32*/ 1: return "Arm32";
- case /*UnityEditor.QNXArchitecture.X64*/ 2: return "X64";
- case /*UnityEditor.QNXArchitecture.X86*/ 3: return "X86";
- default: return $"UNKNOWN_{value}";
- }
- }
-
- private static int GetVisionSdkVersion()
- {
- var playerSettings = typeof(PlayerSettings);
- var visionOs = playerSettings.GetNestedType("VisionOS");
- if (visionOs == null) throw new Exception("Editor does not appear to support visionOS");
-
- var property = visionOs.GetProperty("sdkVersion", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
- if (property == null) throw new Exception("Property `sdkVersion` not found");
- var sdkVersion = property.GetValue(null, null);
- return (int)sdkVersion;
- }
-
- /// <summary>
- /// Defines an output path (for the generated code) and the target CPU
- /// </summary>
- internal struct BurstOutputCombination
- {
- public readonly TargetCpus TargetCpus;
- public readonly string OutputPath;
- public readonly string LibraryName;
- public readonly bool CollateDirectory;
- public readonly bool WorkaroundFullDebugInfo;
- public readonly Dictionary<string, string> EnvironmentVariables;
-
- public BurstOutputCombination(string outputPath, TargetCpus targetCpus, string libraryName = DefaultLibraryName, bool collateDirectory = false, bool workaroundBrokenDebug=false, Dictionary<string, string> environment = null)
- {
- TargetCpus = targetCpus.Clone();
- OutputPath = outputPath;
- LibraryName = libraryName;
- CollateDirectory = collateDirectory;
- WorkaroundFullDebugInfo = workaroundBrokenDebug;
- EnvironmentVariables = environment;
- }
-
- public void HashInto(ref Hash128 hc)
- {
- hc.Append(TargetCpus.Cpus.Count);
- foreach (var cpu in TargetCpus.Cpus)
- {
- hc.Append((int)cpu);
- }
-
- hc.Append(OutputPath);
- hc.Append(LibraryName);
- hc.Append(CollateDirectory ? 1 : 0);
- hc.Append(WorkaroundFullDebugInfo ? 1 : 0);
- }
-
- public override string ToString()
- {
- return $"{nameof(TargetCpus)}: {TargetCpus}, {nameof(OutputPath)}: {OutputPath}, {nameof(LibraryName)}: {LibraryName}";
- }
- }
-
- private class BclRunner
- {
- private static readonly Regex MatchVersion = new Regex(@"com.unity.burst@(\d+.*?)[\\/]");
-
- public static void RunManagedProgram(string exe, string args, CompilerOutputParserBase parser, IReadOnlyDictionary<string, string> environment = null)
- {
- RunManagedProgram(exe, args, Application.dataPath + "/..", parser, environment);
- }
-
- private static void RunManagedProgram(
- string exe,
- string args,
- string workingDirectory,
- CompilerOutputParserBase parser,
- IReadOnlyDictionary<string, string> environment = null)
- {
- Program p;
- bool unreliableExitCode = false;
- if (Application.platform == RuntimePlatform.WindowsEditor)
- {
- if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
- {
- // For Windows on Arm 64, we need to be explicit and specify the architecture we want our
- //managed process to run with - unfortunately, doing this means the exit code of the process
- //no longer reflects if compilation was successful, so unreliableExitCode works around this
- args = "/c start /machine arm64 /b /WAIT " + exe + " " + args;
- exe = "cmd";
- unreliableExitCode = true;
- }
- ProcessStartInfo si = new ProcessStartInfo()
- {
- Arguments = args,
- CreateNoWindow = true,
- FileName = exe,
- };
- SetEnvironmentVariables(si);
- p = new Program(si);
- }
- else
- {
- p = (Program) new ManagedProgram(MonoInstallationFinder.GetMonoInstallation("MonoBleedingEdge"), (string) null, exe, args, false, SetEnvironmentVariables);
- }
-
- RunProgram(p, exe, args, workingDirectory, parser, unreliableExitCode);
-
- return;
-
- void SetEnvironmentVariables(ProcessStartInfo psi)
- {
- if (environment == null) return;
- foreach (var kvp in environment)
- {
- psi.Environment[kvp.Key] = kvp.Value;
- }
- }
- }
-
- public static void RunNativeProgram(string exe, string args, CompilerOutputParserBase parser)
- {
- RunNativeProgram(exe, args, Application.dataPath + "/..", parser);
- }
-
- private static void RunNativeProgram(string exePath, string arguments, string workingDirectory, CompilerOutputParserBase parser)
- {
- // On non Windows platform, make sure that the command is executable
- // This is a workaround - occasionally the execute bits are lost from our package
- if (Application.platform != RuntimePlatform.WindowsEditor && Path.IsPathRooted(exePath))
- {
- var escapedExePath = EscapeForShell(exePath, singleQuoteWrapped: true);
- var shArgs = $"-c '[ ! -x {escapedExePath} ] && chmod 755 {escapedExePath}'";
-
- var p = new Program(new ProcessStartInfo("sh", shArgs) { CreateNoWindow = true});
- p.GetProcessStartInfo().WorkingDirectory = workingDirectory;
- p.Start();
- p.WaitForExit();
- }
-
- var startInfo = new ProcessStartInfo(exePath, arguments);
- startInfo.CreateNoWindow = true;
-
- RunProgram(new Program(startInfo), exePath, arguments, workingDirectory, parser, false);
- }
-
- public static string EscapeForShell(string s, bool singleQuoteWrapped = false)
- {
- // On Windows it's enough to enclose the path in double quotes (double quotes are not allowed in paths)
- if (Application.platform == RuntimePlatform.WindowsEditor) return $"\"{s}\"";
-
- // On non-windows platforms we enclose in single-quotes and escape any existing single quotes with: '\'':
- // John's Folder => 'John'\''s Folder'
- var sb = new StringBuilder();
- var escaped = s.Replace("'", "'\\''");
- sb.Append('\'');
- sb.Append(escaped);
- sb.Append('\'');
-
- // If the outer-context is already wrapped in single-quotes, we need to double escape things:
- // John's Folder => 'John'\''s Folder'
- // => '\''John'\''\'\'''\''s Folder'\''
- if (singleQuoteWrapped)
- {
- // Pain
- return sb.ToString().Replace("'", "'\\''");
- }
-
- return sb.ToString();
- }
-
-
-
- public static void RunProgram(
- Program p,
- string exe,
- string args,
- string workingDirectory,
- CompilerOutputParserBase parser,
- bool unreliableExitCode)
- {
- Stopwatch stopwatch = new Stopwatch();
- stopwatch.Start();
- using (p)
- {
- p.GetProcessStartInfo().WorkingDirectory = workingDirectory;
- p.Start();
- p.WaitForExit();
- stopwatch.Stop();
-
- Console.WriteLine("{0} exited after {1} ms.", (object)exe, (object)stopwatch.ElapsedMilliseconds);
- IEnumerable<UnityEditor.Scripting.Compilers.CompilerMessage> compilerMessages = null;
- string[] errorOutput = p.GetErrorOutput();
- string[] standardOutput = p.GetStandardOutput();
- if (parser != null)
- {
- compilerMessages = parser.Parse(errorOutput, standardOutput, true, "n/a (burst)");
- }
-
- var errorMessageBuilder = new StringBuilder();
-
- if (compilerMessages != null)
- {
- foreach (UnityEditor.Scripting.Compilers.CompilerMessage compilerMessage in compilerMessages)
- {
- switch (compilerMessage.type)
- {
- case CompilerMessageType.Warning:
- Debug.LogWarning(compilerMessage.message, compilerMessage.file, compilerMessage.line, compilerMessage.column);
- break;
- case CompilerMessageType.Error:
- Debug.LogPlayerBuildError(compilerMessage.message, compilerMessage.file, compilerMessage.line, compilerMessage.column);
- break;
- }
- }
- }
-
- var exitFailed = p.ExitCode != 0;
- if (unreliableExitCode)
- {
- // Bcl +burstc will emit a Done as the final stdout if everything was ok.
- exitFailed = (standardOutput.Length==0) || (standardOutput[standardOutput.Length - 1].Trim() != "Done");
- }
-
- if (exitFailed)
- {
- // We try to output the version in the heading error if we can
- var matchVersion = MatchVersion.Match(exe);
- errorMessageBuilder.Append(matchVersion.Success ?
- "Burst compiler (" + matchVersion.Groups[1].Value + ") failed running" :
- "Burst compiler failed running");
- errorMessageBuilder.AppendLine();
- errorMessageBuilder.AppendLine();
- // Don't output the path if we are not burst-debugging or the exe exist
- if (BurstLoader.IsDebugging || !File.Exists(exe))
- {
- errorMessageBuilder.Append(exe).Append(" ").Append(args);
- errorMessageBuilder.AppendLine();
- errorMessageBuilder.AppendLine();
- }
-
- errorMessageBuilder.AppendLine("stdout:");
- foreach (string str in standardOutput)
- errorMessageBuilder.AppendLine(str);
- errorMessageBuilder.AppendLine("stderr:");
- foreach (string str in errorOutput)
- errorMessageBuilder.AppendLine(str);
-
- throw new BuildFailedException(errorMessageBuilder.ToString());
- }
- Console.WriteLine(p.GetAllOutput());
- }
- }
- }
-
- /// <summary>
- /// Internal class used to parse bcl output errors
- /// </summary>
- private class BclOutputErrorParser : CompilerOutputParserBase
- {
- // Format of an error message:
- //
- //C:\work\burst\src\Burst.Compiler.IL.Tests\Program.cs(17,9): error: Loading a managed string literal is not supported by burst
- // at Buggy.NiceBug() (at C:\work\burst\src\Burst.Compiler.IL.Tests\Program.cs:17)
- //
- //
- // [1] [2] [3] [4] [5]
- // path line col type message
- private static readonly Regex MatchLocation = new Regex(@"^(.*?)\((\d+)\s*,\s*(\d+)\):\s*([\w\s]+)\s*:\s*(.*)");
-
- // Matches " at "
- private static readonly Regex MatchAt = new Regex(@"^\s+at\s+");
-
- public override IEnumerable<UnityEditor.Scripting.Compilers.CompilerMessage> Parse(
- string[] errorOutput,
- string[] standardOutput,
- bool compilationHadFailure,
- string assemblyName)
- {
- var messages = new List<UnityEditor.Scripting.Compilers.CompilerMessage>();
- var textBuilder = new StringBuilder();
- for (var i = 0; i < errorOutput.Length; i++)
- {
- string line = errorOutput[i];
-
- var message = new UnityEditor.Scripting.Compilers.CompilerMessage {assemblyName = assemblyName};
-
- // If we are able to match a location, we can decode it including the following attached " at " lines
- textBuilder.Clear();
-
- var match = MatchLocation.Match(line);
- if (match.Success)
- {
- var path = match.Groups[1].Value;
- int.TryParse(match.Groups[2].Value, out message.line);
- int.TryParse(match.Groups[3].Value, out message.column);
- if (match.Groups[4].Value.Contains("error"))
- {
- message.type = CompilerMessageType.Error;
- }
- else
- {
- message.type = CompilerMessageType.Warning;
- }
- message.file = !string.IsNullOrEmpty(path) ? path : "unknown";
- // Replace '\' with '/' to let the editor open the file
- message.file = message.file.Replace('\\', '/');
-
- // Make path relative to project path path
- var projectPath = Path.GetDirectoryName(Application.dataPath)?.Replace('\\', '/');
- if (projectPath != null && message.file.StartsWith(projectPath))
- {
- message.file = message.file.Substring(projectPath.EndsWith("/") ? projectPath.Length : projectPath.Length + 1);
- }
-
- // debug
- // textBuilder.AppendLine("line: " + message.line + " column: " + message.column + " error: " + message.type + " file: " + message.file);
- textBuilder.Append(match.Groups[5].Value);
- }
- else
- {
- // Don't output any blank line
- if (string.IsNullOrWhiteSpace(line))
- {
- continue;
- }
- // Otherwise we output an error, but without source location information
- // so that at least the user can see it directly in the log errors
- message.type = CompilerMessageType.Error;
- message.line = 0;
- message.column = 0;
- message.file = "unknown";
-
-
- textBuilder.Append(line);
- }
-
- // Collect attached location call context information ("at ...")
- // we do it for both case (as if we have an exception in bcl we want to print this in a single line)
- bool isFirstAt = true;
- for (int j = i + 1; j < errorOutput.Length; j++)
- {
- var nextLine = errorOutput[j];
-
- // Empty lines are ignored by the stack trace parser.
- if (string.IsNullOrWhiteSpace(nextLine))
- {
- i++;
- continue;
- }
-
- if (MatchAt.Match(nextLine).Success)
- {
- i++;
- if (isFirstAt)
- {
- textBuilder.AppendLine();
- isFirstAt = false;
- }
- textBuilder.AppendLine(nextLine);
- }
- else
- {
- break;
- }
- }
- message.message = textBuilder.ToString();
-
- messages.Add(message);
- }
- return messages;
- }
-
- protected override string GetErrorIdentifier()
- {
- throw new NotImplementedException(); // as we overriding the method Parse()
- }
-
- protected override Regex GetOutputRegex()
- {
- throw new NotImplementedException(); // as we overriding the method Parse()
- }
- }
-
- #if UNITY_EDITOR_OSX && !ENABLE_GENERATE_NATIVE_PLUGINS_FOR_ASSEMBLIES_API
- private class StaticLibraryPostProcessor
- {
- private const string TempSourceLibrary = @"Temp/StagingArea/StaticLibraries";
- [PostProcessBuildAttribute(1)]
- public static void OnPostProcessBuild(BuildTarget target, string path)
- {
- // Early out if we are building for the simulator, as we don't
- //currently generate burst libraries that will work for that.
- if (IsForSimulator(target))
- {
- return;
- }
- // We only support AOT compilation for ios from a macos host (we require xcrun and the apple tool chains)
- //for other hosts, we simply act as if burst is not being used (an error will be generated by the build aot step)
- //this keeps the behaviour consistent with how it was before static linkage was introduced
- if (target == BuildTarget.iOS)
- {
- var aotSettingsForTarget = BurstPlatformAotSettings.GetOrCreateSettings(BuildTarget.iOS);
-
- // Early exit if burst is not activated
- if (!aotSettingsForTarget.EnableBurstCompilation)
- {
- return;
- }
- PostAddStaticLibraries(path);
- }
- if (target == BuildTarget.tvOS)
- {
- var aotSettingsForTarget = BurstPlatformAotSettings.GetOrCreateSettings(BuildTarget.tvOS);
-
- // Early exit if burst is not activated
- if (!aotSettingsForTarget.EnableBurstCompilation)
- {
- return;
- }
- PostAddStaticLibraries(path);
- }
- #if UNITY_2023_3_OR_NEWER
- if (target == BuildTarget.visionOS)
- {
- var aotSettingsForTarget = BurstPlatformAotSettings.GetOrCreateSettings(BuildTarget.visionOS);
-
- // Early exit if burst is not activated
- if (!aotSettingsForTarget.EnableBurstCompilation)
- {
- return;
- }
- PostAddStaticLibraries(path);
- }
- #endif
- }
-
- private static void PostAddStaticLibraries(string path)
- {
- var assm = AppDomain.CurrentDomain.GetAssemblies().SingleOrDefault(assembly =>
- assembly.GetName().Name == "UnityEditor.iOS.Extensions.Xcode");
- Type PBXType = assm?.GetType("UnityEditor.iOS.Xcode.PBXProject");
- Type PBXSourceTree = assm?.GetType("UnityEditor.iOS.Xcode.PBXSourceTree");
- if (PBXType != null && PBXSourceTree != null)
- {
- var project = Activator.CreateInstance(PBXType, null);
-
- var _sGetPBXProjectPath = PBXType.GetMethod("GetPBXProjectPath");
- var _ReadFromFile = PBXType.GetMethod("ReadFromFile");
- var _sGetUnityTargetName = PBXType.GetMethod("GetUnityTargetName");
- var _AddFileToBuild = PBXType.GetMethod("AddFileToBuild");
- var _AddFile = PBXType.GetMethod("AddFile");
- var _WriteToString = PBXType.GetMethod("WriteToString");
-
- var sourcetree = new EnumConverter(PBXSourceTree).ConvertFromString("Source");
-
- string sPath = (string)_sGetPBXProjectPath?.Invoke(null, new object[] { path });
- _ReadFromFile?.Invoke(project, new object[] { sPath });
-
- var _TargetGuidByName = PBXType.GetMethod("GetUnityFrameworkTargetGuid");
- string g = (string) _TargetGuidByName?.Invoke(project, null);
-
- var srcPath = TempSourceLibrary;
- var dstPath = "Libraries";
- var dstCopyPath = Path.Combine(path, dstPath);
-
- var burstCppLinkFile = "lib_burst_generated.cpp";
-
- var libName = $"{DefaultLibraryName}.a";
- var libSrcPath = Path.Combine(srcPath, libName);
- var libExists = File.Exists(libSrcPath);
-
- if (!libExists)
- {
- return; // No libs, so don't write the cpp either
- }
-
- File.Copy(libSrcPath, Path.Combine(dstCopyPath, libName));
- AddLibToProject(project, _AddFileToBuild, _AddFile, sourcetree, g, dstPath, libName);
-
- // Additionally we need a small cpp file (weak symbols won't unfortunately override directly from the libs
- //presumably due to link order?
- WriteStaticLinkCppFile(dstCopyPath);
- string cppPath = Path.Combine(dstPath, burstCppLinkFile);
- string fileg = (string)_AddFile?.Invoke(project, new object[] { cppPath, cppPath, sourcetree });
- _AddFileToBuild?.Invoke(project, new object[] { g, fileg });
-
- string pstring = (string)_WriteToString?.Invoke(project, null);
- File.WriteAllText(sPath, pstring);
- }
- }
-
- private static void AddLibToProject(object project, System.Reflection.MethodInfo _AddFileToBuild, System.Reflection.MethodInfo _AddFile, object sourcetree, string g, string dstPath, string lib32Name)
- {
- string fg = (string)_AddFile?.Invoke(project,
- new object[] { Path.Combine(dstPath, lib32Name), Path.Combine(dstPath, lib32Name), sourcetree });
- _AddFileToBuild?.Invoke(project, new object[] { g, fg });
- }
- }
- #endif
- }
- }
- #endif
|