From 8642a210c178f1608e4b9a075987d3dc2b734ffa Mon Sep 17 00:00:00 2001
From: Ivan Povazan <55002338+ivanpovazan@users.noreply.github.com>
Date: Tue, 7 Feb 2023 19:14:50 +0100
Subject: [PATCH] Enable AppleAppBuilder to bundle iOS applications built for
NativeAOT runtime (#81711)
Fixes: https://github.com/dotnet/runtime/issues/80910
---
src/tasks/AppleAppBuilder/AppleAppBuilder.cs | 49 +++++++++++++++--
.../Templates/CMakeLists.txt.template | 16 ++++--
src/tasks/AppleAppBuilder/Templates/main-simple.m | 13 +++++
src/tasks/AppleAppBuilder/Xcode.cs | 64 ++++++++++++++--------
4 files changed, 110 insertions(+), 32 deletions(-)
diff --git a/src/tasks/AppleAppBuilder/AppleAppBuilder.cs b/src/tasks/AppleAppBuilder/AppleAppBuilder.cs
index 859db0b..6182f97 100644
--- a/src/tasks/AppleAppBuilder/AppleAppBuilder.cs
+++ b/src/tasks/AppleAppBuilder/AppleAppBuilder.cs
@@ -46,7 +46,6 @@ public class AppleAppBuilderTask : Task
///
/// Path to Mono public headers (*.h)
///
- [Required]
public string MonoRuntimeHeaders { get; set; } = ""!;
///
@@ -167,10 +166,52 @@ public class AppleAppBuilderTask : Task
///
public bool StripSymbolTable { get; set; }
+ ///
+ /// Bundles the application for NativeAOT runtime. Default runtime is Mono.
+ ///
+ public bool UseNativeAOTRuntime { get; set; }
+
+ public void ValidateRuntimeSelection()
+ {
+ if (UseNativeAOTRuntime)
+ {
+ if (!string.IsNullOrEmpty(MonoRuntimeHeaders))
+ throw new ArgumentException($"Property \"{nameof(MonoRuntimeHeaders)}\" is not supported with NativeAOT runtime and will be ignored.");
+
+ if (!string.IsNullOrEmpty(MainLibraryFileName))
+ throw new ArgumentException($"Property \"{nameof(MainLibraryFileName)}\" is not supported with NativeAOT runtime and will be ignored.");
+
+ if (UseConsoleUITemplate)
+ throw new ArgumentException($"Property \"{nameof(UseConsoleUITemplate)}\" is not supported with NativeAOT runtime and will be ignored.");
+
+ if (ForceInterpreter)
+ throw new ArgumentException($"Property \"{nameof(ForceInterpreter)}\" is not supported with NativeAOT runtime and will be ignored.");
+
+ if (ForceAOT)
+ throw new ArgumentException($"Property \"{nameof(ForceAOT)}\" is not supported with NativeAOT runtime and will be ignored.");
+
+ if (!string.IsNullOrEmpty(RuntimeComponents))
+ throw new ArgumentException($"Property \"{nameof(RuntimeComponents)}\" is not supported with NativeAOT runtime and will be ignored.");
+
+ if (!string.IsNullOrEmpty(DiagnosticPorts))
+ throw new ArgumentException($"Property \"{nameof(DiagnosticPorts)}\" is not supported with NativeAOT runtime and will be ignored.");
+
+ if (EnableRuntimeLogging)
+ throw new ArgumentException($"Property \"{nameof(EnableRuntimeLogging)}\" is not supported with NativeAOT runtime and will be ignored.");
+ }
+ else
+ {
+ if (string.IsNullOrEmpty(MonoRuntimeHeaders))
+ throw new ArgumentException($"The \"{nameof(AppleAppBuilderTask)}\" task was not given a value for the required parameter \"{nameof(MonoRuntimeHeaders)}\" when using Mono runtime.");
+ }
+ }
+
public override bool Execute()
{
bool isDevice = (TargetOS == TargetNames.iOS || TargetOS == TargetNames.tvOS);
+ ValidateRuntimeSelection();
+
if (!string.IsNullOrEmpty(MainLibraryFileName))
{
if (!File.Exists(Path.Combine(AppDir, MainLibraryFileName)))
@@ -226,7 +267,7 @@ public class AppleAppBuilderTask : Task
}
}
- if (!ForceInterpreter && (isDevice || ForceAOT) && assemblerFiles.Count == 0)
+ if (!ForceInterpreter && (isDevice || ForceAOT) && (assemblerFiles.Count == 0 && !UseNativeAOTRuntime))
{
throw new InvalidOperationException("Need list of AOT files for device builds.");
}
@@ -256,7 +297,7 @@ public class AppleAppBuilderTask : Task
if (GenerateXcodeProject)
{
XcodeProjectPath = generator.GenerateXCode(ProjectName, MainLibraryFileName, assemblerFiles, assemblerDataFiles, assemblerFilesToLink,
- AppDir, binDir, MonoRuntimeHeaders, !isDevice, UseConsoleUITemplate, ForceAOT, ForceInterpreter, InvariantGlobalization, Optimized, EnableRuntimeLogging, EnableAppSandbox, DiagnosticPorts, RuntimeComponents, NativeMainSource);
+ AppDir, binDir, MonoRuntimeHeaders, !isDevice, UseConsoleUITemplate, ForceAOT, ForceInterpreter, InvariantGlobalization, Optimized, EnableRuntimeLogging, EnableAppSandbox, DiagnosticPorts, RuntimeComponents, NativeMainSource, UseNativeAOTRuntime);
if (BuildAppBundle)
{
@@ -274,7 +315,7 @@ public class AppleAppBuilderTask : Task
else if (GenerateCMakeProject)
{
generator.GenerateCMake(ProjectName, MainLibraryFileName, assemblerFiles, assemblerDataFiles, assemblerFilesToLink,
- AppDir, binDir, MonoRuntimeHeaders, !isDevice, UseConsoleUITemplate, ForceAOT, ForceInterpreter, InvariantGlobalization, Optimized, EnableRuntimeLogging, EnableAppSandbox, DiagnosticPorts, RuntimeComponents, NativeMainSource);
+ AppDir, binDir, MonoRuntimeHeaders, !isDevice, UseConsoleUITemplate, ForceAOT, ForceInterpreter, InvariantGlobalization, Optimized, EnableRuntimeLogging, EnableAppSandbox, DiagnosticPorts, RuntimeComponents, NativeMainSource, UseNativeAOTRuntime);
}
return true;
diff --git a/src/tasks/AppleAppBuilder/Templates/CMakeLists.txt.template b/src/tasks/AppleAppBuilder/Templates/CMakeLists.txt.template
index 0697c3f..aba0797 100644
--- a/src/tasks/AppleAppBuilder/Templates/CMakeLists.txt.template
+++ b/src/tasks/AppleAppBuilder/Templates/CMakeLists.txt.template
@@ -10,17 +10,25 @@ set(APP_RESOURCES
add_executable(
%ProjectName%
%MainSource%
- runtime.h
- runtime.m
- %AotModulesSource%
${APP_RESOURCES}
)
+if(NOT %UseNativeAOTRuntime%)
+ target_sources(
+ %ProjectName%
+ PRIVATE
+ %AotModulesSource%
+ runtime.h
+ runtime.m)
+endif()
+
%AotSources%
%Defines%
-include_directories("%MonoInclude%")
+if(NOT %UseNativeAOTRuntime%)
+ include_directories("%MonoInclude%")
+endif()
set_target_properties(%ProjectName% %AotTargetsList% PROPERTIES
XCODE_ATTRIBUTE_SUPPORTS_MACCATALYST "YES"
diff --git a/src/tasks/AppleAppBuilder/Templates/main-simple.m b/src/tasks/AppleAppBuilder/Templates/main-simple.m
index e05868f..270bf23 100644
--- a/src/tasks/AppleAppBuilder/Templates/main-simple.m
+++ b/src/tasks/AppleAppBuilder/Templates/main-simple.m
@@ -2,7 +2,12 @@
// The .NET Foundation licenses this file to you under the MIT license.
#import
+#if !USE_NATIVE_AOT
#import "runtime.h"
+#else
+extern void* NativeAOT_StaticInitialization();
+extern int __managed__Main(int argc, char* argv[]);
+#endif
@interface ViewController : UIViewController
@end
@@ -46,7 +51,15 @@ void (*clickHandlerPtr)(void);
[self.view addSubview:button];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+#if !USE_NATIVE_AOT
mono_ios_runtime_init ();
+#else
+#if INVARIANT_GLOBALIZATION
+ setenv ("DOTNET_SYSTEM_GLOBALIZATION_INVARIANT", "1", TRUE);
+#endif
+ NativeAOT_StaticInitialization();
+ int ret_val = __managed__Main(0, NULL);
+#endif
});
}
-(void) buttonClicked:(UIButton*)sender
diff --git a/src/tasks/AppleAppBuilder/Xcode.cs b/src/tasks/AppleAppBuilder/Xcode.cs
index 87ee142..66d40e5 100644
--- a/src/tasks/AppleAppBuilder/Xcode.cs
+++ b/src/tasks/AppleAppBuilder/Xcode.cs
@@ -152,10 +152,11 @@ internal sealed class Xcode
bool enableRuntimeLogging,
bool enableAppSandbox,
string? diagnosticPorts,
- string? runtimeComponents=null,
- string? nativeMainSource = null)
+ string? runtimeComponents = null,
+ string? nativeMainSource = null,
+ bool useNativeAOTRuntime = false)
{
- var cmakeDirectoryPath = GenerateCMake(projectName, entryPointLib, asmFiles, asmDataFiles, asmLinkFiles, workspace, binDir, monoInclude, preferDylibs, useConsoleUiTemplate, forceAOT, forceInterpreter, invariantGlobalization, optimized, enableRuntimeLogging, enableAppSandbox, diagnosticPorts, runtimeComponents, nativeMainSource);
+ var cmakeDirectoryPath = GenerateCMake(projectName, entryPointLib, asmFiles, asmDataFiles, asmLinkFiles, workspace, binDir, monoInclude, preferDylibs, useConsoleUiTemplate, forceAOT, forceInterpreter, invariantGlobalization, optimized, enableRuntimeLogging, enableAppSandbox, diagnosticPorts, runtimeComponents, nativeMainSource, useNativeAOTRuntime);
CreateXcodeProject(projectName, cmakeDirectoryPath);
return Path.Combine(binDir, projectName, projectName + ".xcodeproj");
}
@@ -210,8 +211,9 @@ internal sealed class Xcode
bool enableRuntimeLogging,
bool enableAppSandbox,
string? diagnosticPorts,
- string? runtimeComponents=null,
- string? nativeMainSource = null)
+ string? runtimeComponents = null,
+ string? nativeMainSource = null,
+ bool useNativeAOTRuntime = false)
{
// bundle everything as resources excluding native files
var excludes = new List { ".dll.o", ".dll.s", ".dwarf", ".m", ".h", ".a", ".bc", "libmonosgen-2.0.dylib", "libcoreclr.dylib" };
@@ -270,6 +272,7 @@ internal sealed class Xcode
appResources += string.Join(Environment.NewLine, resources.Where(r => !r.EndsWith("-llvm.o")).Select(r => " " + Path.GetRelativePath(binDir, r)));
string cmakeLists = Utils.GetEmbeddedResource("CMakeLists.txt.template")
+ .Replace("%UseNativeAOTRuntime%", useNativeAOTRuntime ? "TRUE" : "FALSE")
.Replace("%ProjectName%", projectName)
.Replace("%AppResources%", appResources)
.Replace("%MainSource%", nativeMainSource)
@@ -332,7 +335,12 @@ internal sealed class Xcode
// libmono must always be statically linked, for other librarires we can use dylibs
bool dylibExists = libName != "libmonosgen-2.0" && dylibs.Any(dylib => Path.GetFileName(dylib) == libName + ".dylib");
- if (forceAOT || !(preferDylibs && dylibExists))
+ if (useNativeAOTRuntime)
+ {
+ // link NativeAOT framework libs without '-force_load'
+ toLink += $" {lib}{Environment.NewLine}";
+ }
+ else if (forceAOT || !(preferDylibs && dylibExists))
{
// these libraries are pinvoked
// -force_load will be removed once we enable direct-pinvokes for AOT
@@ -394,6 +402,11 @@ internal sealed class Xcode
defines.AppendLine($"\nadd_definitions(-DDIAGNOSTIC_PORTS=\"{diagnosticPorts}\")");
}
+ if (useNativeAOTRuntime)
+ {
+ defines.AppendLine("add_definitions(-DUSE_NATIVE_AOT=1)");
+ }
+
cmakeLists = cmakeLists.Replace("%Defines%", defines.ToString());
string plist = Utils.GetEmbeddedResource("Info.plist.template")
@@ -417,28 +430,31 @@ internal sealed class Xcode
File.WriteAllText(Path.Combine(binDir, "app.entitlements"), entitlementsTemplate.Replace("%Entitlements%", ent.ToString()));
}
- File.WriteAllText(Path.Combine(binDir, "runtime.h"),
- Utils.GetEmbeddedResource("runtime.h"));
-
- // forward pinvokes to "__Internal"
- var dllMap = new StringBuilder();
- foreach (string aFile in Directory.GetFiles(workspace, "*.a"))
+ if (!useNativeAOTRuntime)
{
- string aFileName = Path.GetFileNameWithoutExtension(aFile);
- dllMap.AppendLine($" mono_dllmap_insert (NULL, \"{aFileName}\", NULL, \"__Internal\", NULL);");
+ File.WriteAllText(Path.Combine(binDir, "runtime.h"),
+ Utils.GetEmbeddedResource("runtime.h"));
- // also register with or without "lib" prefix
- aFileName = aFileName.StartsWith("lib") ? aFileName.Remove(0, 3) : "lib" + aFileName;
- dllMap.AppendLine($" mono_dllmap_insert (NULL, \"{aFileName}\", NULL, \"__Internal\", NULL);");
- }
+ // forward pinvokes to "__Internal"
+ var dllMap = new StringBuilder();
+ foreach (string aFile in Directory.GetFiles(workspace, "*.a"))
+ {
+ string aFileName = Path.GetFileNameWithoutExtension(aFile);
+ dllMap.AppendLine($" mono_dllmap_insert (NULL, \"{aFileName}\", NULL, \"__Internal\", NULL);");
- dllMap.AppendLine($" mono_dllmap_insert (NULL, \"System.Globalization.Native\", NULL, \"__Internal\", NULL);");
+ // also register with or without "lib" prefix
+ aFileName = aFileName.StartsWith("lib") ? aFileName.Remove(0, 3) : "lib" + aFileName;
+ dllMap.AppendLine($" mono_dllmap_insert (NULL, \"{aFileName}\", NULL, \"__Internal\", NULL);");
+ }
- File.WriteAllText(Path.Combine(binDir, "runtime.m"),
- Utils.GetEmbeddedResource("runtime.m")
- .Replace("//%DllMap%", dllMap.ToString())
- .Replace("//%APPLE_RUNTIME_IDENTIFIER%", RuntimeIdentifier)
- .Replace("%EntryPointLibName%", Path.GetFileName(entryPointLib)));
+ dllMap.AppendLine($" mono_dllmap_insert (NULL, \"System.Globalization.Native\", NULL, \"__Internal\", NULL);");
+
+ File.WriteAllText(Path.Combine(binDir, "runtime.m"),
+ Utils.GetEmbeddedResource("runtime.m")
+ .Replace("//%DllMap%", dllMap.ToString())
+ .Replace("//%APPLE_RUNTIME_IDENTIFIER%", RuntimeIdentifier)
+ .Replace("%EntryPointLibName%", Path.GetFileName(entryPointLib)));
+ }
return binDir;
}
--
2.7.4