[mono] Add iOS app builder project (#34563)
authorEgor Bogatov <egorbo@gmail.com>
Tue, 14 Apr 2020 12:37:11 +0000 (15:37 +0300)
committerGitHub <noreply@github.com>
Tue, 14 Apr 2020 12:37:11 +0000 (14:37 +0200)
* Add iosAppBuilderTasks project

* Escape spaces in ProjectName

* Remove add_definitions(-DDEVICE)

* Fix typoe Buillder -> Builder, also build the task as part of mono runtime

* Rewrite HelloiOS sample (to use the task)

* Fix build

* Clean up

* Add license headers

* Clean up

* dont build app if provisionig is not set

* Add ExcludeFromAppDir input argument, remove stopwatch

* Drop DOTNET_SYSTEM_GLOBALIZATION_INVARIANT

* Address feedback

* Validate input

* fix build

* Disable GenerateXcodeProject by default

* move to mono/msbuild

* Add OutputDirectory property

* Fix sample

* Minor improvements

* fix build issues

18 files changed:
src/mono/mono.proj
src/mono/msbuild/AppleAppBuilder/AotCompiler.cs [new file with mode: 0644]
src/mono/msbuild/AppleAppBuilder/AppleAppBuilder.cs [new file with mode: 0644]
src/mono/msbuild/AppleAppBuilder/AppleAppBuilder.csproj [new file with mode: 0644]
src/mono/msbuild/AppleAppBuilder/Templates/CMakeLists.txt.template [new file with mode: 0644]
src/mono/msbuild/AppleAppBuilder/Templates/Info.plist.template [moved from src/mono/netcore/sample/iOS/Plist.in with 88% similarity]
src/mono/msbuild/AppleAppBuilder/Templates/main-console.m [new file with mode: 0644]
src/mono/msbuild/AppleAppBuilder/Templates/main-simple.m [new file with mode: 0644]
src/mono/msbuild/AppleAppBuilder/Templates/runtime.h [new file with mode: 0644]
src/mono/msbuild/AppleAppBuilder/Templates/runtime.m [moved from src/mono/netcore/sample/iOS/runtime.m with 74% similarity]
src/mono/msbuild/AppleAppBuilder/Utils.cs [new file with mode: 0644]
src/mono/msbuild/AppleAppBuilder/Xcode.cs [new file with mode: 0644]
src/mono/netcore/sample/iOS/.gitignore [deleted file]
src/mono/netcore/sample/iOS/CMakeLists.txt [deleted file]
src/mono/netcore/sample/iOS/Makefile
src/mono/netcore/sample/iOS/Program.cs
src/mono/netcore/sample/iOS/main.m
src/mono/netcore/sample/iOS/runtime.h [deleted file]

index 8f2ee64..dd5e11d 100644 (file)
 
   <Import Project="Directory.Build.targets" />
 
+  <Target Name="BuildAppleAppBuilder">
+    <MSBuild Projects="$(MonoProjectRoot)msbuild\AppleAppBuilder\AppleAppBuilder.csproj"
+             Properties="Configuration=$(Configuration)"
+             Targets="Restore;Build" />
+  </Target>
+
+  <UsingTask TaskName="AppleAppBuilderTask" 
+             AssemblyFile="$(ArtifactsObjDir)mono\AppleAppBuilder\$(TargetArchitecture)\$(Configuration)\AppleAppBuilder.dll" />
+
+  <Target Name="BuildAppleApp" DependsOnTargets="BuildAppleAppBuilder">
+    <AppleAppBuilderTask 
+        Arch="$(TargetArchitecture)"
+        ProjectName="$(ProjectName)"
+        Optimized="$(Optimized)"
+        MonoInclude="$(BinDir)include\mono-2.0"
+        CrossCompiler="$(BinDir)cross\mono-aot-cross"
+        MainLibraryFileName="$(MainLibraryFileName)"
+        NativeMainSource="$(NativeMainSource)"
+        GenerateXcodeProject="$(GenerateXcodeProject)"
+        BuildAppBundle="$(BuildAppBundle)"
+        DevTeamProvisioning="$(DevTeamProvisioning)"
+        OutputDirectory="$(BinDir)\$(ProjectName)"
+        AppDir="$(AppDir)">
+        <Output TaskParameter="AppBundlePath" PropertyName="AppBundlePath" />
+        <Output TaskParameter="XcodeProjectPath" PropertyName="XcodeProjectPath" />
+    </AppleAppBuilderTask>
+    <Message Importance="High" Text="Xcode: $(XcodeProjectPath)"/>
+    <Message Importance="High" Text="App: $(AppBundlePath)"/>
+  </Target>
+
   <!-- Ordering matters! Overwriting the Build target. -->
   <!-- General targets -->
   <Target Name="Build" DependsOnTargets="BuildMonoRuntimeUnix;BuildMonoRuntimeWindows">
diff --git a/src/mono/msbuild/AppleAppBuilder/AotCompiler.cs b/src/mono/msbuild/AppleAppBuilder/AotCompiler.cs
new file mode 100644 (file)
index 0000000..2d9896c
--- /dev/null
@@ -0,0 +1,140 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Threading.Tasks;
+
+internal class AotCompiler
+{
+    /// <summary>
+    /// Precompile all assemblies in parallel
+    /// </summary>
+    public static void PrecompileLibraries(
+        string crossCompiler,
+        string arch,
+        bool parallel,
+        string binDir,
+        string[] libsToPrecompile,
+        IDictionary<string, string> envVariables,
+        bool optimize)
+    {
+        Parallel.ForEach(libsToPrecompile,
+            new ParallelOptions { MaxDegreeOfParallelism = parallel ? Environment.ProcessorCount : 1 },
+            lib => PrecompileLibrary(crossCompiler, arch, binDir, lib, envVariables, optimize));
+    }
+
+    private static void PrecompileLibrary(
+        string crossCompiler,
+        string arch,
+        string binDir,
+        string libToPrecompile,
+        IDictionary<string, string> envVariables,
+        bool optimize)
+    {
+        Utils.LogInfo($"[AOT] {libToPrecompile}");
+
+        var crossArgs = new StringBuilder();
+        crossArgs
+            .Append(" -O=gsharedvt,float32")
+            .Append(" --nollvm")
+            .Append(" --debug");
+
+        string libName = Path.GetFileNameWithoutExtension(libToPrecompile);
+        var aotArgs = new StringBuilder();
+        aotArgs
+            .Append("mtriple=").Append(arch).Append("-ios,")
+            .Append("static,")
+            .Append("asmonly,")
+            .Append("direct-icalls,")
+            .Append("no-direct-calls,")
+            .Append("dwarfdebug,")
+            .Append("outfile=").Append(Path.Combine(binDir, libName + ".dll.s,"))
+            //  TODO: enable aotdata
+            //.Append("data-outfile=").Append(Path.Combine(binDir, libName + ".aotdata,"))
+            //  TODO: enable direct-pinvokes (to get rid of -force_loads)
+            //.Append("direct-pinvoke,")
+            .Append("full,");
+
+        // TODO: enable Interpreter
+        // TODO: enable LLVM
+        // TODO: enable System.Runtime.Intrinsics.Arm (LLVM-only for now)
+        // e.g. .Append("mattr=+crc,")
+
+        crossArgs
+            .Append(" --aot=").Append(aotArgs).Append(" ")
+            .Append(libToPrecompile);
+
+        Utils.RunProcess(crossCompiler, crossArgs.ToString(), envVariables, binDir);
+
+        var clangArgs = new StringBuilder();
+        if (optimize)
+        {
+            clangArgs.Append(" -Os");
+        }
+        clangArgs
+            .Append(" -isysroot ").Append(Xcode.Sysroot)
+            .Append(" -miphoneos-version-min=10.1")
+            .Append(" -arch ").Append(arch)
+            .Append(" -c ").Append(Path.Combine(binDir, libName)).Append(".dll.s")
+            .Append(" -o ").Append(Path.Combine(binDir, libName)).Append(".dll.o");
+
+        Utils.RunProcess("clang", clangArgs.ToString(), workingDir: binDir);
+    }
+
+    public static void GenerateLinkAllFile(string[] objFiles, string outputFile)
+    {
+        //  Generates 'modules.m' in order to register all managed libraries
+        //
+        //
+        // extern void *mono_aot_module_Lib1_info;
+        // extern void *mono_aot_module_Lib2_info;
+        // ...
+        //
+        // void mono_ios_register_modules (void)
+        // {
+        //     mono_aot_register_module (mono_aot_module_Lib1_info);
+        //     mono_aot_register_module (mono_aot_module_Lib2_info);
+        //     ...
+        // }
+
+        Utils.LogInfo("Generating 'modules.m'...");
+
+        var lsDecl = new StringBuilder();
+        lsDecl
+            .AppendLine("#include <mono/jit/jit.h>")
+            .AppendLine("#include <TargetConditionals.h>")
+            .AppendLine()
+            .AppendLine("#if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR")
+            .AppendLine();
+
+        var lsUsage = new StringBuilder();
+        lsUsage
+            .AppendLine("void mono_ios_register_modules (void)")
+            .AppendLine("{");
+        foreach (string objFile in objFiles)
+        {
+            string symbol = "mono_aot_module_" +
+                            Path.GetFileName(objFile)
+                                .Replace(".dll.o", "")
+                                .Replace(".", "_")
+                                .Replace("-", "_") + "_info";
+
+            lsDecl.Append("extern void *").Append(symbol).Append(';').AppendLine();
+            lsUsage.Append("\tmono_aot_register_module (").Append(symbol).Append(");").AppendLine();
+        }
+        lsDecl
+            .AppendLine()
+            .Append(lsUsage)
+            .AppendLine("}")
+            .AppendLine()
+            .AppendLine("#endif")
+            .AppendLine();
+
+        File.WriteAllText(outputFile, lsDecl.ToString());
+        Utils.LogInfo($"Saved to {outputFile}.");
+    }
+}
diff --git a/src/mono/msbuild/AppleAppBuilder/AppleAppBuilder.cs b/src/mono/msbuild/AppleAppBuilder/AppleAppBuilder.cs
new file mode 100644 (file)
index 0000000..f992b67
--- /dev/null
@@ -0,0 +1,187 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
+public class AppleAppBuilderTask : Task
+{
+    /// <summary>
+    /// Path to arm64 AOT cross-compiler (mono-aot-cross)
+    /// It's not used for x64 (Simulator)
+    /// </summary>
+    public string? CrossCompiler { get; set; }
+
+    /// <summary>
+    /// ProjectName is used as an app name, bundleId and xcode project name
+    /// </summary>
+    [Required]
+    public string ProjectName { get; set; } = ""!;
+
+    /// <summary>
+    /// Target directory with *dll and other content to be AOT'd and/or bundled
+    /// </summary>
+    [Required]
+    public string AppDir { get; set; } = ""!;
+
+    /// <summary>
+    /// Path to Mono public headers (*.h)
+    /// </summary>
+    [Required]
+    public string MonoInclude { get; set; } = ""!;
+
+    /// <summary>
+    /// This library will be used as an entry-point (e.g. TestRunner.dll)
+    /// </summary>
+    [Required]
+    public string MainLibraryFileName { get; set; } = ""!;
+
+    /// <summary>
+    /// Path to store build artifacts
+    /// </summary>
+    public string? OutputDirectory { get; set; }
+
+    /// <summary>
+    /// Produce optimized binaries (e.g. use -O2 in AOT)
+    /// and use 'Release' config in xcode
+    /// </summary>
+    public bool Optimized { get; set; }
+
+    /// <summary>
+    /// Disable parallel AOT compilation
+    /// </summary>
+    public bool DisableParallelAot { get; set; }
+
+    /// <summary>
+    /// Target arch, can be "arm64" (device) or "x64" (simulator) at the moment
+    /// </summary>
+    [Required]
+    public string Arch { get; set; } = ""!;
+
+    /// <summary>
+    /// DEVELOPER_TEAM provisioning, needed for arm64 builds.
+    /// </summary>
+    public string? DevTeamProvisioning { get; set; }
+
+    /// <summary>
+    /// Build *.app bundle (using XCode for now)
+    /// </summary>
+    public bool BuildAppBundle { get; set; }
+
+    /// <summary>
+    /// Generate xcode project
+    /// </summary>
+    public bool GenerateXcodeProject { get; set; }
+
+    /// <summary>
+    /// Files to be ignored in AppDir
+    /// </summary>
+    public ITaskItem[]? ExcludeFromAppDir { get; set; }
+
+    /// <summary>
+    /// Path to a custom main.m with custom UI
+    /// A default one is used if it's not set
+    /// </summary>
+    public string? NativeMainSource { get; set; }
+
+    /// <summary>
+    /// Use Console-style native UI template
+    /// (use NativeMainSource to override)
+    /// </summary>
+    public bool UseConsoleUITemplate { get; set; }
+
+    /// <summary>
+    /// Path to *.app bundle
+    /// </summary>
+    [Output]
+    public string AppBundlePath { get; set; } = ""!;
+
+    /// <summary>
+    /// Path to xcode project
+    /// </summary>
+    [Output]
+    public string XcodeProjectPath { get; set; } = ""!;
+
+    public override bool Execute()
+    {
+        Utils.Logger = Log;
+        bool isDevice = Arch.Equals("arm64", StringComparison.InvariantCultureIgnoreCase);
+        if (isDevice && string.IsNullOrEmpty(CrossCompiler))
+        {
+            throw new ArgumentException("arm64 arch requires CrossCompiler");
+        }
+
+        if (!File.Exists(Path.Combine(AppDir, MainLibraryFileName)))
+        {
+            throw new ArgumentException($"MainLibraryFileName='{MainLibraryFileName}' was not found in AppDir='{AppDir}'");
+        }
+
+        // escape spaces
+        ProjectName = ProjectName.Replace(" ", "-");
+
+        string[] excludes = new string[0];
+        if (ExcludeFromAppDir != null)
+        {
+            excludes = ExcludeFromAppDir
+                .Where(i => !string.IsNullOrEmpty(i.ItemSpec))
+                .Select(i => i.ItemSpec)
+                .ToArray();
+        }
+        string[] libsToAot = Directory.GetFiles(AppDir, "*.dll")
+            .Where(f => !excludes.Contains(Path.GetFileName(f)))
+            .ToArray();
+
+        string binDir = Path.Combine(AppDir, $"bin-{ProjectName}-{Arch}");
+        if (!string.IsNullOrEmpty(OutputDirectory))
+        {
+            binDir = OutputDirectory;
+        }
+        Directory.CreateDirectory(binDir);
+
+        // run AOT compilation only for devices
+        if (isDevice)
+        {
+            if (string.IsNullOrEmpty(CrossCompiler))
+                throw new InvalidOperationException("cross-compiler is not set");
+
+            AotCompiler.PrecompileLibraries(CrossCompiler, Arch, !DisableParallelAot, binDir, libsToAot,
+                new Dictionary<string, string> { {"MONO_PATH", AppDir} },
+                Optimized);
+        }
+
+        // generate modules.m
+        AotCompiler.GenerateLinkAllFile(
+            Directory.GetFiles(binDir, "*.dll.o"),
+            Path.Combine(binDir, "modules.m"));
+
+        if (GenerateXcodeProject)
+        {
+            XcodeProjectPath = Xcode.GenerateXCode(ProjectName, MainLibraryFileName, 
+                AppDir, binDir, MonoInclude, UseConsoleUITemplate, NativeMainSource);
+
+            if (BuildAppBundle)
+            {
+                if (isDevice && string.IsNullOrEmpty(DevTeamProvisioning))
+                {
+                    // DevTeamProvisioning shouldn't be empty for arm64 builds
+                    Utils.LogInfo("DevTeamProvisioning is not set, BuildAppBundle step is skipped.");
+                }
+                else
+                {
+                    AppBundlePath = Xcode.BuildAppBundle(
+                        Path.Combine(binDir, ProjectName, ProjectName + ".xcodeproj"),
+                        Arch, Optimized, DevTeamProvisioning);
+                }
+            }
+            Utils.LogInfo($"Xcode: {XcodeProjectPath}\n App: {AppBundlePath}");
+        }
+
+        return true;
+    }
+}
diff --git a/src/mono/msbuild/AppleAppBuilder/AppleAppBuilder.csproj b/src/mono/msbuild/AppleAppBuilder/AppleAppBuilder.csproj
new file mode 100644 (file)
index 0000000..dd703fd
--- /dev/null
@@ -0,0 +1,25 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>Library</OutputType>
+    <OutputPath>bin</OutputPath>
+    <TargetFramework>$(NetCoreAppCurrent)</TargetFramework>
+    <Nullable>enable</Nullable>
+    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
+    <EnableDefaultCompileItems>false</EnableDefaultCompileItems>
+  </PropertyGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="Templates\*.*" />
+  </ItemGroup>
+  <ItemGroup>
+    <PackageReference Include="Microsoft.Build" Version="$(RefOnlyMicrosoftBuildVersion)" />
+    <PackageReference Include="Microsoft.Build.Framework" Version="$(RefOnlyMicrosoftBuildFrameworkVersion)" />
+    <PackageReference Include="Microsoft.Build.Tasks.Core" Version="$(RefOnlyMicrosoftBuildTasksCoreVersion)" />
+    <PackageReference Include="Microsoft.Build.Utilities.Core" Version="$(RefOnlyMicrosoftBuildUtilitiesCoreVersion)" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="AotCompiler.cs" />
+    <Compile Include="AppleAppBuilder.cs" />
+    <Compile Include="Utils.cs" />
+    <Compile Include="Xcode.cs" />
+  </ItemGroup>
+</Project>
diff --git a/src/mono/msbuild/AppleAppBuilder/Templates/CMakeLists.txt.template b/src/mono/msbuild/AppleAppBuilder/Templates/CMakeLists.txt.template
new file mode 100644 (file)
index 0000000..47a7a18
--- /dev/null
@@ -0,0 +1,39 @@
+cmake_minimum_required(VERSION 3.14.5)
+
+project(%ProjectName%)
+
+set(APP_RESOURCES
+%AppResources%
+)
+
+add_executable(
+    %ProjectName%
+    %MainSource%
+    runtime.h
+    runtime.m
+    modules.m
+    ${APP_RESOURCES}
+)
+
+include_directories("%MonoInclude%")
+
+set_target_properties(%ProjectName% PROPERTIES
+    MACOSX_BUNDLE TRUE
+    MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in
+    XCODE_ATTRIBUTE_ENABLE_BITCODE "NO"
+    XCODE_ATTRIBUTE_DEAD_CODE_STRIPPING "NO"
+    RESOURCE "${APP_RESOURCES}"
+)
+
+# FIXME: `XCODE_ATTRIBUTE_DEAD_CODE_STRIPPING` should not be NO
+
+target_link_libraries(
+    %ProjectName%
+    "-framework Foundation"
+    "-framework Security"
+    "-framework UIKit"
+    "-framework GSS"
+    "-lz"
+    "-liconv"
+%NativeLibrariesToLink%
+)
@@ -5,13 +5,13 @@
        <key>CFBundleDevelopmentRegion</key>
        <string>en-US</string>
        <key>CFBundleExecutable</key>
-       <string>HelloiOS</string>
+       <string>%BundleIdentifier%</string>
        <key>CFBundleIdentifier</key>
-       <string>net.dot.HelloiOS</string>
+       <string>net.dot.%BundleIdentifier%</string>
+       <key>CFBundleName</key>
+       <string>%BundleIdentifier%</string>
        <key>CFBundleInfoDictionaryVersion</key>
        <string>6.0</string>
-       <key>CFBundleName</key>
-       <string>HelloiOS</string>
        <key>CFBundlePackageType</key>
        <string>APPL</string>
        <key>CFBundleShortVersionString</key>
diff --git a/src/mono/msbuild/AppleAppBuilder/Templates/main-console.m b/src/mono/msbuild/AppleAppBuilder/Templates/main-console.m
new file mode 100644 (file)
index 0000000..c908f16
--- /dev/null
@@ -0,0 +1,93 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#import <UIKit/UIKit.h>
+#import "runtime.h"
+#include <TargetConditionals.h>
+
+@interface ViewController : UIViewController
+@end
+
+@interface AppDelegate : UIResponder <UIApplicationDelegate>
+@property (strong, nonatomic) UIWindow *window;
+@property (strong, nonatomic) ViewController *controller;
+@end
+
+@implementation AppDelegate
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
+    self.controller = [[ViewController alloc] initWithNibName:nil bundle:nil];
+    self.window.rootViewController = self.controller;
+    [self.window makeKeyAndVisible];
+    return YES;
+}
+@end
+
+UILabel *summaryLabel;
+UITextView* logLabel;
+
+@implementation ViewController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+
+    CGRect applicationFrame = [[UIScreen mainScreen] applicationFrame];
+    logLabel = [[UITextView alloc] initWithFrame:
+        CGRectMake(2.0, 50.0, applicationFrame.size.width, applicationFrame.size.height)];
+    logLabel.font = [UIFont systemFontOfSize:9.0];
+    logLabel.backgroundColor = [UIColor blackColor];
+    logLabel.textColor = [UIColor greenColor];
+    logLabel.scrollEnabled = YES;
+    logLabel.alwaysBounceVertical = YES;
+    logLabel.editable = NO;
+    logLabel.clipsToBounds = YES;
+
+    summaryLabel = [[UILabel alloc] initWithFrame: CGRectMake(10.0, 0.0, applicationFrame.size.width, 50)];
+    summaryLabel.textColor = [UIColor whiteColor];
+    summaryLabel.font = [UIFont boldSystemFontOfSize: 14];
+    summaryLabel.numberOfLines = 2;
+    summaryLabel.textAlignment = NSTextAlignmentLeft;
+#ifdef TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
+    summaryLabel.text = @"Loading...";
+#else
+    summaryLabel.text = @"Jitting...";
+#endif
+    [self.view addSubview:logLabel];
+    [self.view addSubview:summaryLabel];
+
+    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+        mono_ios_runtime_init ();
+    });
+}
+
+@end
+
+// can be called from C# to update UI
+void
+mono_ios_set_summary (const char* value)
+{
+    NSString* nsstr = [NSString stringWithUTF8String:strdup(value)];
+    dispatch_async(dispatch_get_main_queue(), ^{
+        summaryLabel.text = nsstr;
+    });
+}
+
+// can be called from C# to update UI
+void
+mono_ios_append_output (const char* value)
+{
+    NSString* nsstr = [NSString stringWithUTF8String:strdup(value)];
+    dispatch_async(dispatch_get_main_queue(), ^{
+        logLabel.text = [logLabel.text stringByAppendingString:nsstr];
+        dispatch_async(dispatch_get_main_queue(), ^{
+            [logLabel scrollRangeToVisible: NSMakeRange(logLabel.text.length -1, 1)];
+        });
+    });
+}
+
+int main(int argc, char * argv[]) {
+    @autoreleasepool {
+        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
+    }
+}
diff --git a/src/mono/msbuild/AppleAppBuilder/Templates/main-simple.m b/src/mono/msbuild/AppleAppBuilder/Templates/main-simple.m
new file mode 100644 (file)
index 0000000..d68fa3b
--- /dev/null
@@ -0,0 +1,82 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#import <UIKit/UIKit.h>
+#import "runtime.h"
+
+@interface ViewController : UIViewController
+@end
+
+@interface AppDelegate : UIResponder <UIApplicationDelegate>
+@property (strong, nonatomic) UIWindow *window;
+@property (strong, nonatomic) ViewController *controller;
+@end
+
+@implementation AppDelegate
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
+    self.controller = [[ViewController alloc] initWithNibName:nil bundle:nil];
+    self.window.rootViewController = self.controller;
+    [self.window makeKeyAndVisible];
+    return YES;
+}
+@end
+
+UILabel *label;
+void (*clickHandlerPtr)(void);
+
+@implementation ViewController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    
+    label = [[UILabel alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
+    label.textColor = [UIColor greenColor];
+    label.font = [UIFont boldSystemFontOfSize: 30];
+    label.numberOfLines = 2;
+    label.textAlignment = NSTextAlignmentCenter;
+    label.text = @"Hello, wire me up!\n(dllimport ios_set_text)";
+    [self.view addSubview:label];
+    
+    UIButton *button = [UIButton buttonWithType:UIButtonTypeInfoDark];
+    [button addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
+    [button setFrame:CGRectMake(50, 300, 200, 50)];
+    [button setTitle:@"Click me (wire me up)" forState:UIControlStateNormal];
+    [button setExclusiveTouch:YES];
+    [self.view addSubview:button];
+
+    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+        mono_ios_runtime_init ();
+    });
+}
+-(void) buttonClicked:(UIButton*)sender
+{
+    if (clickHandlerPtr)
+        clickHandlerPtr();
+}
+
+@end
+
+// called from C# sample
+void
+ios_register_button_click (void* ptr)
+{
+    clickHandlerPtr = ptr;
+}
+
+// called from C# sample
+void
+ios_set_text (const char* value)
+{
+    NSString* nsstr = [NSString stringWithUTF8String:strdup(value)];
+    dispatch_async(dispatch_get_main_queue(), ^{
+        label.text = nsstr;
+    });
+}
+
+int main(int argc, char * argv[]) {
+    @autoreleasepool {
+        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
+    }
+}
diff --git a/src/mono/msbuild/AppleAppBuilder/Templates/runtime.h b/src/mono/msbuild/AppleAppBuilder/Templates/runtime.h
new file mode 100644 (file)
index 0000000..bbfca32
--- /dev/null
@@ -0,0 +1,10 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef runtime_h
+#define runtime_h
+
+void mono_ios_runtime_init (void);
+
+#endif /* runtime_h */
similarity index 74%
rename from src/mono/netcore/sample/iOS/runtime.m
rename to src/mono/msbuild/AppleAppBuilder/Templates/runtime.m
index 424b4d8..dfef913 100644 (file)
@@ -1,3 +1,7 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
 #import <Foundation/Foundation.h>
 #include <mono/utils/mono-publib.h>
 #include <mono/utils/mono-logger.h>
 #include <mono/metadata/exception.h>
 #include <mono/jit/jit.h>
 #include <mono/jit/mono-private-unstable.h>
-
+#include <TargetConditionals.h>
 #import <os/log.h>
 #include <sys/stat.h>
 #include <sys/mman.h>
 
+static char *bundle_path;
+
 // no-op for iOS and tvOS.
 // watchOS is not supported yet.
 #define MONO_ENTER_GC_UNSAFE
 #define MONO_EXIT_GC_UNSAFE
 
-static os_log_t stdout_log;
-
-static char *bundle_path;
-
 const char *
 get_bundle_path (void)
 {
     if (bundle_path)
         return bundle_path;
-
     NSBundle* main_bundle = [NSBundle mainBundle];
     NSString* path = [main_bundle bundlePath];
     bundle_path = strdup ([path UTF8String]);
@@ -99,7 +100,7 @@ load_assembly (const char *name, const char *culture)
     else
         res = snprintf (path, sizeof (path) - 1, "%s/%s", bundle, filename);
     assert (res > 0);
-    
+
     struct stat buffer;
     if (stat (path, &buffer) == 0) {
         MonoAssembly *assembly = mono_assembly_open (path, NULL);
@@ -193,53 +194,12 @@ log_callback (const char *log_domain, const char *log_level, const char *message
 static void
 register_dllmap (void)
 {
-    mono_dllmap_insert (NULL, "libSystem.Native", NULL, "__Internal", NULL);
-    mono_dllmap_insert (NULL, "libSystem.IO.Compression.Native", NULL, "__Internal", NULL);
-    mono_dllmap_insert (NULL, "libSystem.Security.Cryptography.Native.Apple", NULL, "__Internal", NULL);
+//%DllMap%
 }
 
+#if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
 void mono_jit_set_aot_mode (MonoAotMode mode);
-
-#if DEVICE
-extern void *mono_aot_module_Program_info;
-extern void *mono_aot_module_System_Private_CoreLib_info;
-extern void *mono_aot_module_System_Runtime_info;
-extern void *mono_aot_module_System_Runtime_Extensions_info;
-extern void *mono_aot_module_System_Collections_info;
-extern void *mono_aot_module_System_Core_info;
-extern void *mono_aot_module_System_Threading_info;
-extern void *mono_aot_module_System_Threading_Tasks_info;
-extern void *mono_aot_module_System_Linq_info;
-extern void *mono_aot_module_System_Memory_info;
-extern void *mono_aot_module_System_Runtime_InteropServices_info;
-extern void *mono_aot_module_System_Text_Encoding_Extensions_info;
-extern void *mono_aot_module_Microsoft_Win32_Primitives_info;
-extern void *mono_aot_module_System_Console_info;
-extern void *mono_aot_module_Program_info;
-
-void mono_ios_register_modules (void)
-{
-    mono_aot_register_module (mono_aot_module_Program_info);
-    mono_aot_register_module (mono_aot_module_System_Private_CoreLib_info);
-    mono_aot_register_module (mono_aot_module_System_Runtime_info);
-    mono_aot_register_module (mono_aot_module_System_Runtime_Extensions_info);
-    mono_aot_register_module (mono_aot_module_System_Collections_info);
-    mono_aot_register_module (mono_aot_module_System_Core_info);
-    mono_aot_register_module (mono_aot_module_System_Threading_info);
-    mono_aot_register_module (mono_aot_module_System_Threading_Tasks_info);
-    mono_aot_register_module (mono_aot_module_System_Linq_info);
-    mono_aot_register_module (mono_aot_module_System_Memory_info);
-    mono_aot_register_module (mono_aot_module_System_Runtime_InteropServices_info);
-    mono_aot_register_module (mono_aot_module_System_Text_Encoding_Extensions_info);
-    mono_aot_register_module (mono_aot_module_Microsoft_Win32_Primitives_info);
-    mono_aot_register_module (mono_aot_module_System_Console_info);
-    mono_aot_register_module (mono_aot_module_Program_info);
-}
-
-void mono_ios_setup_execution_mode (void)
-{
-    mono_jit_set_aot_mode (MONO_AOT_MODE_FULL);
-}
+void mono_ios_register_modules (void);
 #endif
 
 void
@@ -252,22 +212,35 @@ mono_ios_runtime_init (void)
     // setenv ("MONO_LOG_LEVEL", "debug", TRUE);
     // setenv ("MONO_LOG_MASK", "all", TRUE);
 
-    stdout_log = os_log_create ("net.dot.mono", "stdout");
+    bool auto_exit = FALSE;
+    id args_array = [[NSProcessInfo processInfo] arguments];
+    assert ([args_array count] <= 128);
+    const char *managed_argv [128];
+    int argi;
+    for (argi = 0; argi < [args_array count]; argi++) {
+        NSString* arg = [args_array objectAtIndex: argi];
+        assert ([arg length] >= 3);
+        if ([arg hasPrefix:@"--setenv="]) {
+            // TODO: setenv
+        } else if ([arg isEqualToString:@"--auto-exit"]) {
+            auto_exit = TRUE;
+        }
+        managed_argv[argi] = [arg UTF8String];
+    }
 
     bool wait_for_debugger = FALSE;
-    char* executable = "Program.dll";
 
     const char* bundle = get_bundle_path ();
     chdir (bundle);
 
     register_dllmap ();
 
-#if DEVICE
+#if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
     // register modules
     mono_ios_register_modules ();
-    mono_ios_setup_execution_mode ();
+    mono_jit_set_aot_mode (MONO_AOT_MODE_FULL);
 #endif
-    
+
     mono_debug_init (MONO_DEBUG_FORMAT_MONO);
     mono_install_assembly_preload_hook (assembly_preload_hook, NULL);
     mono_install_load_aot_data_hook (load_aot_data, free_aot_data, NULL);
@@ -282,18 +255,22 @@ mono_ios_runtime_init (void)
     }
     mono_jit_init_version ("dotnet.ios", "mobile");
 
-#if DEVICE
+#if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
     // device runtimes are configured to use lazy gc thread creation
     MONO_ENTER_GC_UNSAFE;
     mono_gc_init_finalizer_thread ();
     MONO_EXIT_GC_UNSAFE;
 #endif
 
+    const char* executable = "%EntryPointLibName%";
     MonoAssembly *assembly = load_assembly (executable, NULL);
     assert (assembly);
     os_log_info (OS_LOG_DEFAULT, "Executable: %{public}s", executable);
 
-    int res = mono_jit_exec (mono_domain_get (), assembly, 1, &executable);
+    int res = mono_jit_exec (mono_domain_get (), assembly, argi, managed_argv);
     // Print this so apps parsing logs can detect when we exited
     os_log_info (OS_LOG_DEFAULT, "Exit code: %d.", res);
+
+    if (auto_exit)
+        exit (res);
 }
diff --git a/src/mono/msbuild/AppleAppBuilder/Utils.cs b/src/mono/msbuild/AppleAppBuilder/Utils.cs
new file mode 100644 (file)
index 0000000..41d16cb
--- /dev/null
@@ -0,0 +1,96 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Text;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
+internal class Utils
+{
+    public static string GetEmbeddedResource(string file)
+    {
+        using Stream stream = typeof(Utils).Assembly
+            .GetManifestResourceStream("AppleAppBuilder.Templates." + file)!;
+        using var reader = new StreamReader(stream);
+        return reader.ReadToEnd();
+    }
+
+    public static string RunProcess(
+        string path,
+        string args = "",
+        IDictionary<string, string>? envVars = null,
+        string? workingDir = null,
+        bool ignoreErrors = false)
+    {
+        LogInfo($"Running: {path} {args}");
+        var outputBuilder = new StringBuilder();
+        var errorBuilder = new StringBuilder();
+        var processStartInfo = new ProcessStartInfo
+        {
+            FileName = path,
+            UseShellExecute = false,
+            CreateNoWindow = true,
+            RedirectStandardError = true,
+            RedirectStandardOutput = true,
+            Arguments = args,
+        };
+
+        if (workingDir != null)
+        {
+            processStartInfo.WorkingDirectory = workingDir;
+        }
+
+        if (envVars != null)
+        {
+            foreach (KeyValuePair<string, string> envVar in envVars)
+            {
+                processStartInfo.EnvironmentVariables[envVar.Key] = envVar.Value;
+            }
+        }
+
+        Process process = Process.Start(processStartInfo)!;
+        process.ErrorDataReceived += (sender, e) =>
+        {
+            LogError(e.Data);
+            outputBuilder.AppendLine(e.Data);
+            errorBuilder.AppendLine(e.Data);
+        };
+        process.OutputDataReceived += (sender, e) =>
+        {
+            LogInfo(e.Data);
+            outputBuilder.AppendLine(e.Data);
+        };
+        process.BeginOutputReadLine();
+        process.BeginErrorReadLine();
+        process.WaitForExit();
+        if (process.ExitCode != 0)
+        {
+            throw new Exception("Error: " + errorBuilder);
+        }
+
+        return outputBuilder.ToString().Trim('\r','\n');
+    }
+
+    public static TaskLoggingHelper? Logger { get; set; }
+
+    public static void LogInfo(string? msg)
+    {
+        if (msg != null)
+        {
+            Logger?.LogMessage(MessageImportance.High, msg);
+        }
+    }
+
+    public static void LogError(string? msg)
+    {
+        if (msg != null)
+        {
+            Logger?.LogError(msg);
+        }
+    }
+}
diff --git a/src/mono/msbuild/AppleAppBuilder/Xcode.cs b/src/mono/msbuild/AppleAppBuilder/Xcode.cs
new file mode 100644 (file)
index 0000000..dc6f41a
--- /dev/null
@@ -0,0 +1,127 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+internal class Xcode
+{
+    public static string Sysroot { get; } = Utils.RunProcess("xcrun", "--sdk iphoneos --show-sdk-path");
+
+    public static string GenerateXCode(
+        string projectName,
+        string entryPointLib,
+        string workspace,
+        string binDir,
+        string monoInclude,
+        bool useConsoleUiTemplate = false,
+        string? nativeMainSource = null)
+    {
+        // bundle everything as resources excluding native files
+        string[] excludes = {".dylib", ".dll.o", ".dll.s", ".dwarf", ".m", ".h", ".a"};
+        string[] resources = Directory.GetFiles(workspace)
+            .Where(f => !excludes.Any(e => f.EndsWith(e, StringComparison.InvariantCultureIgnoreCase)))
+            .Concat(Directory.GetFiles(binDir, "*.aotdata"))
+            .ToArray();
+
+        if (string.IsNullOrEmpty(nativeMainSource))
+        {
+            // use built-in main.m (with default UI) if it's not set
+            nativeMainSource = Path.Combine(binDir, "main.m");
+            File.WriteAllText(nativeMainSource, Utils.GetEmbeddedResource(useConsoleUiTemplate ? "main-console.m" : "main-simple.m"));
+        }
+        else
+        {
+            string newMainPath = Path.Combine(binDir, "main.m");
+            if (nativeMainSource != newMainPath)
+            {
+                File.Copy(nativeMainSource, Path.Combine(binDir, "main.m"), true);
+                nativeMainSource = newMainPath;
+            }
+        }
+
+        string cmakeLists = Utils.GetEmbeddedResource("CMakeLists.txt.template")
+            .Replace("%ProjectName%", projectName)
+            .Replace("%AppResources%", string.Join(Environment.NewLine, resources.Select(r => "    " + r)))
+            .Replace("%MainSource%", nativeMainSource)
+            .Replace("%MonoInclude%", monoInclude);
+
+        string toLink = "";
+        foreach (string lib in Directory.GetFiles(workspace, "*.a"))
+        {
+            // these libraries are pinvoked
+            // -force_load will be removed once we enable direct-pinvokes for AOT
+            toLink += $"    \"-force_load {lib}\"{Environment.NewLine}";
+        }
+        foreach (string lib in Directory.GetFiles(binDir, "*.dll.o"))
+        {
+            // these libraries are linked via modules.m
+            toLink += $"    \"{lib}\"{Environment.NewLine}";
+        }
+        cmakeLists = cmakeLists.Replace("%NativeLibrariesToLink%", toLink);
+
+        string plist = Utils.GetEmbeddedResource("Info.plist.template")
+            .Replace("%BundleIdentifier%", projectName);
+
+        File.WriteAllText(Path.Combine(binDir, "Info.plist.in"), plist);
+        File.WriteAllText(Path.Combine(binDir, "CMakeLists.txt"), cmakeLists);
+
+        var cmakeArgs = new StringBuilder();
+        cmakeArgs
+            .Append("-S.")
+            .Append(" -B").Append(projectName)
+            .Append(" -GXcode")
+            .Append(" -DCMAKE_SYSTEM_NAME=iOS")
+            .Append(" \"-DCMAKE_OSX_ARCHITECTURES=arm64;x86_64\"")
+            .Append(" -DCMAKE_OSX_DEPLOYMENT_TARGET=10.1")
+            .Append(" -DCMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH=NO");
+
+        File.WriteAllText(Path.Combine(binDir, "runtime.h"),
+            Utils.GetEmbeddedResource("runtime.h"));
+
+        // forward pinvokes to "__Internal"
+        string dllMap = string.Join(Environment.NewLine, Directory.GetFiles(workspace, "*.a")
+            .Select(f => $"    mono_dllmap_insert (NULL, \"{Path.GetFileNameWithoutExtension(f)}\", NULL, \"__Internal\", NULL);"));
+
+        File.WriteAllText(Path.Combine(binDir, "runtime.m"),
+            Utils.GetEmbeddedResource("runtime.m")
+                .Replace("//%DllMap%", dllMap)
+                .Replace("%EntryPointLibName%", Path.GetFileName(entryPointLib)));
+
+        Utils.RunProcess("cmake", cmakeArgs.ToString(), workingDir: binDir);
+
+        return Path.Combine(binDir, projectName, projectName + ".xcodeproj");
+    }
+
+    public static string BuildAppBundle(
+        string xcodePrjPath, string architecture, bool optimized, string? devTeamProvisioning = null)
+    {
+        string sdk = "";
+        var args = new StringBuilder();
+        args.Append("ONLY_ACTIVE_ARCH=NO");
+        if (architecture == "arm64")
+        {
+            sdk = "iphoneos";
+            args.Append(" -arch arm64")
+                .Append(" -sdk iphoneos")
+                .Append(" -allowProvisioningUpdates")
+                .Append(" DEVELOPMENT_TEAM=").Append(devTeamProvisioning);
+        }
+        else
+        {
+            sdk = "iphonesimulator";
+            args.Append(" -arch x86_64")
+                .Append(" -sdk iphonesimulator");
+        }
+
+        string config = optimized ? "Release" : "Debug";
+        args.Append(" -configuration ").Append(config);
+
+        Utils.RunProcess("xcodebuild", args.ToString(), workingDir: Path.GetDirectoryName(xcodePrjPath));
+        return Path.Combine(Path.GetDirectoryName(xcodePrjPath)!, config + "-" + sdk,
+            Path.GetFileNameWithoutExtension(xcodePrjPath) + ".app");
+    }
+}
diff --git a/src/mono/netcore/sample/iOS/.gitignore b/src/mono/netcore/sample/iOS/.gitignore
deleted file mode 100644 (file)
index 8a7ad91..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-bin/
-xcode/
-*.o
-*.dll
\ No newline at end of file
diff --git a/src/mono/netcore/sample/iOS/CMakeLists.txt b/src/mono/netcore/sample/iOS/CMakeLists.txt
deleted file mode 100644 (file)
index 8821f84..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-cmake_minimum_required(VERSION 3.14.5)
-
-project(HelloiOS)
-
-file(GLOB DLLS *.dll)
-file(GLOB DLLS_AOT *.dll.o)
-file(GLOB DLLS_PDB *.pdb)
-
-set(APP_RESOURCES
-    ${DLLS}
-    ${DLLS_PDB}
-)
-
-add_executable(
-    HelloiOS
-    main.m
-    runtime.h
-    runtime.m
-    ${APP_RESOURCES}
-)
-
-if (MONO_ARCH STREQUAL arm64)
-    add_definitions(-DDEVICE)
-endif()
-
-include_directories("../../../../../artifacts/bin/mono/iOS.${MONO_ARCH}.${MONO_CONFIG}/include/mono-2.0")
-
-set_target_properties(HelloiOS PROPERTIES
-    MACOSX_BUNDLE TRUE
-    MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Plist.in
-    XCODE_ATTRIBUTE_ENABLE_BITCODE "NO"
-    XCODE_ATTRIBUTE_DEAD_CODE_STRIPPING "NO"
-    RESOURCE "${APP_RESOURCES}"
-)
-
-# FIXME: `XCODE_ATTRIBUTE_DEAD_CODE_STRIPPING` should not be NO
-# investigate why `PALEXPORT` doesn't preserve symbols
-
-target_link_libraries(
-    HelloiOS
-    "-framework Foundation"
-    "-framework Security"
-    "-framework UIKit"
-    "-framework GSS"
-    "-lz"
-    "-liconv"
-    "-force_load ../../../../../artifacts/bin/mono/iOS.${MONO_ARCH}.${MONO_CONFIG}/libmono.a"
-    "-force_load ../../../../../artifacts/bin/native/netcoreapp5.0-iOS-${MONO_CONFIG}-${MONO_ARCH}/libSystem.IO.Compression.Native.a"
-    "-force_load ../../../../../artifacts/bin/native/netcoreapp5.0-iOS-${MONO_CONFIG}-${MONO_ARCH}/libSystem.Native.a"
-    "-force_load ../../../../../artifacts/bin/native/netcoreapp5.0-iOS-${MONO_CONFIG}-${MONO_ARCH}/libSystem.Net.Security.Native.a"
-    "-force_load ../../../../../artifacts/bin/native/netcoreapp5.0-iOS-${MONO_CONFIG}-${MONO_ARCH}/libSystem.Security.Cryptography.Native.Apple.a"
-    ${DLLS_AOT}
-)
\ No newline at end of file
index 91c98bc..c00e946 100644 (file)
@@ -1,13 +1,11 @@
 MONO_CONFIG=Debug
-
-# change to x64 for simulator
 MONO_ARCH=arm64
+
 ARTIFACTS_BIN=../../../../../artifacts/bin/
 ARTIFACTS_BCL=$(ARTIFACTS_BIN)runtime/netcoreapp5.0-iOS-$(MONO_CONFIG)-$(MONO_ARCH)
 ARTIFACTS_MONO=$(ARTIFACTS_BIN)/mono/iOS.$(MONO_ARCH).$(MONO_CONFIG)
 
 DOTNET := $(shell cd ../../ && bash init-tools.sh | tail -1)
-SYSROOT := $(shell xcrun --sdk iphoneos --show-sdk-path)
 
 BCL_LIBS = \
        System.Runtime.dll \
@@ -23,53 +21,42 @@ BCL_LIBS = \
        Microsoft.Win32.Primitives.dll \
        System.Console.dll
 
-all: mono-libraries aot-all xcode 
-
-# rebuild mono and libraries for iOS and arm64 or x64
-mono-libraries:
-       ../../../../.././build.sh -os iOS -arch $(MONO_ARCH) --subsetCategory mono-libraries
-
-# once a new library is added here it should also be 
-# added in mono_ios_register_modules() (runtime.m)
-aot-all: prepare
-       make aot-lib-${MONO_ARCH} LIB=$(ARTIFACTS_MONO)/System.Private.CoreLib.dll
-       for lib in $(BCL_LIBS); do make aot-lib-${MONO_ARCH} LIB=$(ARTIFACTS_BCL)/$$lib; done
-       make aot-program
+all: mono build
 
-# recompile Program.cs AOT
-aot-program:
+program:
        $(DOTNET) build -c Debug Program.csproj
-       make aot-lib-${MONO_ARCH} LIB=bin/Program.dll
-
-# we need to copy some BCL libs to ARTIFACTS_MONO
-# to be able to aot other bcl libs
-prepare:
-       for lib in $(BCL_LIBS); do cp $(ARTIFACTS_BCL)/$$lib $(ARTIFACTS_MONO); done
-
-# we'll use regular jit for simulator
-aot-lib-x64:
-       cp $(LIB) $(notdir $(LIB))
-
-aot-lib-arm64:
-       DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 MONO_PATH=$(ARTIFACTS_MONO) \
-       $(ARTIFACTS_MONO)/cross/./mono-aot-cross -O=gsharedvt,float32 --nollvm --debug \
-       --aot=mtriple=arm64-ios,static,asmonly,direct-icalls,no-direct-calls,dwarfdebug,full $(LIB) && \
-       clang -isysroot $(SYSROOT) -miphoneos-version-min=10.1 -arch arm64 -c $(LIB).s
-       cp $(LIB) $(notdir $(LIB))
 
-# generate an xcode project
-xcode:
-       cmake -S. -BXcode -GXcode \
-       -DCMAKE_SYSTEM_NAME=iOS \
-       "-DCMAKE_OSX_ARCHITECTURES=arm64;x86_64" \
-       -DCMAKE_OSX_DEPLOYMENT_TARGET=10.1 \
-       -DCMAKE_INSTALL_PREFIX=`pwd`/_install \
-       -DCMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH=NO \
-       -DCMAKE_IOS_INSTALL_COMBINED=YES \
-       -DMONO_CONFIG=$(MONO_CONFIG) \
-       -DMONO_ARCH=$(MONO_ARCH)
+# copy everything to bin/ and run BuildIosApp task
+build: clean program
+       cp $(ARTIFACTS_MONO)/System.Private.CoreLib.{dll,pdb} bin
+       cp $(ARTIFACTS_MONO)/libmono.a bin
+       for lib in $(BCL_LIBS); do cp $(ARTIFACTS_BCL)/$$lib bin; done
+       cp $(ARTIFACTS_BCL)/*.a bin
+       $(DOTNET) msbuild /t:BuildAppleApp /p:Configuration=$(MONO_CONFIG) \
+       /p:TargetArchitecture=$(MONO_ARCH) \
+       /p:TargetOS=iOS \
+       /p:OutputDirectory=bin \
+       /p:ProjectName=HelloiOS \
+       /p:Optimized=false \
+       /p:AppDir=$(CURDIR)/bin \
+       /p:NativeMainSource=$(CURDIR)/main.m \
+       /p:BuildAppBundle=true \
+       /p:GenerateXcodeProject=true \
+       /p:DevTeamProvisioning= \
+       /p:MainLibraryFileName=Program.dll \
+       ../../../mono.proj
+
+deploy-sim:
+       make build MONO_ARCH=x64
+       xcrun simctl shutdown "iPhone 11" || true
+       xcrun simctl boot "iPhone 11"
+       open -a Simulator
+       xcrun simctl install "iPhone 11" $(realpath ../../../../../artifacts/bin/mono/iOS.x64.$(MONO_CONFIG)/HelloiOS/HelloiOS/Debug-iphonesimulator/HelloiOS.app)
+       xcrun simctl launch booted net.dot.HelloiOS
+
+# rebuild mono for iOS-arm64 or x64
+mono:
+       ../../../../.././build.sh -c $(MONO_CONFIG) -os iOS -arch $(MONO_ARCH) -subset Mono
 
 clean:
-       rm -rf *.dll
-       rm -rf *.dll.o
-       rm -rf Xcode
\ No newline at end of file
+       rm -rf bin
index c1f99af..0de2034 100644 (file)
@@ -1,4 +1,8 @@
-using System;
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Runtime.InteropServices;
index d3c6881..374a094 100644 (file)
@@ -1,3 +1,7 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
 #import <UIKit/UIKit.h>
 #import "runtime.h"
 
diff --git a/src/mono/netcore/sample/iOS/runtime.h b/src/mono/netcore/sample/iOS/runtime.h
deleted file mode 100644 (file)
index ddddd96..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef runtime_h
-#define runtime_h
-
-void mono_ios_runtime_init (void);
-
-#endif /* runtime_h */