From c5491eea97d68b6c7633c65148a223330217749f Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 13 Apr 2023 08:34:49 +0200 Subject: [PATCH] Add Mono AOT for iOS to run C# --- .../Cooker/Platform/Mac/MacPlatformTools.cpp | 1 + .../Cooker/Platform/iOS/iOSPlatformTools.cpp | 26 ++++++++++----- .../Cooker/Platform/iOS/iOSPlatformTools.h | 1 + Source/Editor/Cooker/Steps/DeployDataStep.cpp | 13 ++++++-- Source/Engine/Platform/iOS/iOSDefines.h | 4 +++ .../Flax.Build/Build/DotNet/DotNetSdk.cs | 7 ++++ .../Flax.Build/Platforms/iOS/iOSToolchain.cs | 33 +++++++++++++++++++ 7 files changed, 74 insertions(+), 11 deletions(-) diff --git a/Source/Editor/Cooker/Platform/Mac/MacPlatformTools.cpp b/Source/Editor/Cooker/Platform/Mac/MacPlatformTools.cpp index f6df44ad9..8c29bbcdd 100644 --- a/Source/Editor/Cooker/Platform/Mac/MacPlatformTools.cpp +++ b/Source/Editor/Cooker/Platform/Mac/MacPlatformTools.cpp @@ -218,6 +218,7 @@ bool MacPlatformTools::OnPostProcess(CookingData& data) LSMinimumSystemVersionByArchitecture.append_child(PUGIXML_TEXT("string")).set_child_value(PUGIXML_TEXT("10.15")); #undef ADD_ENTRY +#undef ADD_ENTRY_STR if (!doc.save_file(*StringAnsi(plistPath))) { diff --git a/Source/Editor/Cooker/Platform/iOS/iOSPlatformTools.cpp b/Source/Editor/Cooker/Platform/iOS/iOSPlatformTools.cpp index c5759a5a1..910b08edd 100644 --- a/Source/Editor/Cooker/Platform/iOS/iOSPlatformTools.cpp +++ b/Source/Editor/Cooker/Platform/iOS/iOSPlatformTools.cpp @@ -54,6 +54,11 @@ ArchitectureType iOSPlatformTools::GetArchitecture() const return ArchitectureType::ARM64; } +DotNetAOTModes iOSPlatformTools::UseAOT() const +{ + return DotNetAOTModes::MonoAOTDynamic; +} + bool iOSPlatformTools::IsNativeCodeFile(CookingData& data, const String& file) { String extension = FileSystem::GetExtension(file); @@ -170,6 +175,9 @@ bool iOSPlatformTools::OnPostProcess(CookingData& data) plist.append_attribute(PUGIXML_TEXT("version")).set_value(PUGIXML_TEXT("1.0")); xml_node dict = plist.child_or_append(PUGIXML_TEXT("dict")); + dict.append_child(PUGIXML_TEXT("key")).set_child_value(PUGIXML_TEXT("LSRequiresIPhoneOS")); + dict.append_child(PUGIXML_TEXT("true")); + #define ADD_ENTRY(key, value) \ dict.append_child(PUGIXML_TEXT("key")).set_child_value(PUGIXML_TEXT(key)); \ dict.append_child(PUGIXML_TEXT("string")).set_child_value(PUGIXML_TEXT(value)) @@ -192,16 +200,18 @@ bool iOSPlatformTools::OnPostProcess(CookingData& data) ADD_ENTRY("UIRequiresFullScreen", "true"); ADD_ENTRY("UIStatusBarHidden", "true"); - dict.append_child(PUGIXML_TEXT("key")).set_child_value(PUGIXML_TEXT("CFBundleSupportedPlatforms")); - xml_node CFBundleSupportedPlatforms = dict.append_child(PUGIXML_TEXT("array")); - CFBundleSupportedPlatforms.append_child(PUGIXML_TEXT("string")).set_child_value(PUGIXML_TEXT("iPhoneOS")); + dict.append_child(PUGIXML_TEXT("key")).set_child_value(PUGIXML_TEXT("UIRequiredDeviceCapabilities")); + xml_node UIRequiredDeviceCapabilities = dict.append_child(PUGIXML_TEXT("array")); + UIRequiredDeviceCapabilities.append_child(PUGIXML_TEXT("string")).set_child_value(PUGIXML_TEXT("arm64")); + + dict.append_child(PUGIXML_TEXT("key")).set_child_value(PUGIXML_TEXT("UISupportedInterfaceOrientations")); + xml_node UISupportedInterfaceOrientations = dict.append_child(PUGIXML_TEXT("array")); + UISupportedInterfaceOrientations.append_child(PUGIXML_TEXT("string")).set_child_value(PUGIXML_TEXT("UIInterfaceOrientationPortrait")); + UISupportedInterfaceOrientations.append_child(PUGIXML_TEXT("string")).set_child_value(PUGIXML_TEXT("UIInterfaceOrientationLandscapeLeft")); + UISupportedInterfaceOrientations.append_child(PUGIXML_TEXT("string")).set_child_value(PUGIXML_TEXT("UIInterfaceOrientationLandscapeRight")); - dict.append_child(PUGIXML_TEXT("key")).set_child_value(PUGIXML_TEXT("LSMinimumSystemVersionByArchitecture")); - xml_node LSMinimumSystemVersionByArchitecture = dict.append_child(PUGIXML_TEXT("dict")); - LSMinimumSystemVersionByArchitecture.append_child(PUGIXML_TEXT("key")).set_child_value(PUGIXML_TEXT("arm64")); - LSMinimumSystemVersionByArchitecture.append_child(PUGIXML_TEXT("string")).set_child_value(PUGIXML_TEXT("10.15")); - #undef ADD_ENTRY +#undef ADD_ENTRY_STR if (!doc.save_file(*StringAnsi(plistPath))) { diff --git a/Source/Editor/Cooker/Platform/iOS/iOSPlatformTools.h b/Source/Editor/Cooker/Platform/iOS/iOSPlatformTools.h index acc650fd6..ff95ca3f0 100644 --- a/Source/Editor/Cooker/Platform/iOS/iOSPlatformTools.h +++ b/Source/Editor/Cooker/Platform/iOS/iOSPlatformTools.h @@ -17,6 +17,7 @@ public: const Char* GetName() const override; PlatformType GetPlatform() const override; ArchitectureType GetArchitecture() const override; + DotNetAOTModes UseAOT() const override; bool IsNativeCodeFile(CookingData& data, const String& file) override; void OnBuildStarted(CookingData& data) override; bool OnPostProcess(CookingData& data) override; diff --git a/Source/Editor/Cooker/Steps/DeployDataStep.cpp b/Source/Editor/Cooker/Steps/DeployDataStep.cpp index 8c8a45d7c..fd3b53d2d 100644 --- a/Source/Editor/Cooker/Steps/DeployDataStep.cpp +++ b/Source/Editor/Cooker/Steps/DeployDataStep.cpp @@ -174,7 +174,7 @@ bool DeployDataStep::Perform(CookingData& data) String packFolder = srcDotnet / TEXT("../../../"); String dstDotnetLibs = dstDotnet, srcDotnetLibs = srcDotnet; StringUtils::PathRemoveRelativeParts(packFolder); - if (usAOT) + if (usAOT && srcDotnetFromEngine) { // AOT runtime files inside Engine Platform folder packFolder /= TEXT("Dotnet"); @@ -202,8 +202,8 @@ bool DeployDataStep::Perform(CookingData& data) failed |= EditorUtilities::CopyFileIfNewer(dstDotnetLibs / corlibPrivateName, srcDotnet / corlibPrivateName); switch (data.Platform) { - case BuildPlatform::AndroidARM64: #define DEPLOY_NATIVE_FILE(filename) failed |= FileSystem::CopyFile(data.NativeCodeOutputPath / TEXT(filename), srcDotnet / TEXT(filename)); + case BuildPlatform::AndroidARM64: if (data.Configuration != BuildConfiguration::Release) { DEPLOY_NATIVE_FILE("libmono-component-debugger.so"); @@ -214,8 +214,15 @@ bool DeployDataStep::Perform(CookingData& data) DEPLOY_NATIVE_FILE("libSystem.IO.Compression.Native.so"); DEPLOY_NATIVE_FILE("libSystem.Native.so"); DEPLOY_NATIVE_FILE("libSystem.Security.Cryptography.Native.Android.so"); -#undef DEPLOY_NATIVE_FILE break; + case BuildPlatform::iOSARM64: + DEPLOY_NATIVE_FILE("libmonosgen-2.0.dylib"); + DEPLOY_NATIVE_FILE("libSystem.IO.Compression.Native.dylib"); + DEPLOY_NATIVE_FILE("libSystem.Native.dylib"); + DEPLOY_NATIVE_FILE("libSystem.Net.Security.Native.dylib"); + DEPLOY_NATIVE_FILE("libSystem.Security.Cryptography.Native.Apple.dylib"); + break; +#undef DEPLOY_NATIVE_FILE default: ; } if (failed) diff --git a/Source/Engine/Platform/iOS/iOSDefines.h b/Source/Engine/Platform/iOS/iOSDefines.h index 321607464..fbbcd0afd 100644 --- a/Source/Engine/Platform/iOS/iOSDefines.h +++ b/Source/Engine/Platform/iOS/iOSDefines.h @@ -14,4 +14,8 @@ #define PLATFORM_CACHE_LINE_SIZE 128 #define PLATFORM_DEBUG_BREAK __builtin_trap() +// Use AOT for Mono +#define USE_MONO_AOT 1 +#define USE_MONO_AOT_MODE MONO_AOT_MODE_FULL + #endif diff --git a/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs b/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs index 39ee0d374..e8739a9fc 100644 --- a/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs +++ b/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs @@ -407,6 +407,13 @@ namespace Flax.Build return exists; } + internal static string SelectVersionFolder(string root) + { + var versions = GetVersions(root); + var version = GetVersion(versions); + return Path.Combine(root, version); + } + private static Version ParseVersion(string version) { // Give precedence to final releases over release candidate / beta releases diff --git a/Source/Tools/Flax.Build/Platforms/iOS/iOSToolchain.cs b/Source/Tools/Flax.Build/Platforms/iOS/iOSToolchain.cs index bee83f947..c944fea48 100644 --- a/Source/Tools/Flax.Build/Platforms/iOS/iOSToolchain.cs +++ b/Source/Tools/Flax.Build/Platforms/iOS/iOSToolchain.cs @@ -1,5 +1,6 @@ // Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. +using System.IO; using System.Collections.Generic; using Flax.Build.NativeCpp; @@ -61,5 +62,37 @@ namespace Flax.Build.Platforms args.Add("-miphoneos-version-min=" + Configuration.iOSMinVer); } + + public override bool CompileCSharp(ref CSharpOptions options) + { + switch (options.Action) + { + case CSharpOptions.ActionTypes.GetPlatformTools: + options.PlatformToolsPath = Path.Combine(DotNetSdk.SelectVersionFolder(Path.Combine(DotNetSdk.Instance.RootPath, "packs/Microsoft.NETCore.App.Runtime.AOT.osx-x64.Cross.ios-arm64")), "tools"); + return false; + case CSharpOptions.ActionTypes.MonoCompile: + { + var aotCompilerPath = Path.Combine(options.PlatformToolsPath, "mono-aot-cross"); +return true; // TODO: impl this (output assembly from aot cross-compiler and manually compile into shared library for ios) + // Setup options + var monoAotMode = "full"; + var monoDebugMode = options.EnableDebugSymbols ? "soft-debug" : "nodebug"; + var aotCompilerArgs = $"--aot={monoAotMode},verbose,stats,print-skipped,{monoDebugMode} -O=all"; + if (options.EnableDebugSymbols || options.EnableToolDebug) + aotCompilerArgs = "--debug " + aotCompilerArgs; + var envVars = new Dictionary(); + envVars["MONO_PATH"] = options.AssembliesPath + ";" + options.ClassLibraryPath; + if (options.EnableToolDebug) + { + envVars["MONO_LOG_LEVEL"] = "debug"; + } + + // Run cross-compiler compiler + int result = Utilities.Run(aotCompilerPath, $"{aotCompilerArgs} \"{options.InputFiles[0]}\"", null, options.PlatformToolsPath, Utilities.RunOptions.AppMustExist | Utilities.RunOptions.ConsoleLogOutput, envVars); + return result != 0; + } + } + return base.CompileCSharp(ref options); + } } }