From 2945ca079be11fc646be2e75a48bb9eb330c1be9 Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Tue, 29 Sep 2020 13:10:32 -0400 Subject: [PATCH 01/41] Initial port of iOS sample --- core/mono-samples/iOS/Makefile | 21 ++ core/mono-samples/iOS/Program.cs | 53 ++++ core/mono-samples/iOS/Program.csproj | 88 ++++++ .../AotCompilerTask/MonoAOTCompiler.cs | 255 +++++++++++++++++ .../AotCompilerTask/MonoAOTCompiler.csproj | 25 ++ .../AotCompilerTask/MonoAOTCompiler.props | 17 ++ .../mobile.tasks/AotCompilerTask/Utils.cs | 87 ++++++ .../AppleAppBuilder/AppleAppBuilder.cs | 238 ++++++++++++++++ .../AppleAppBuilder/AppleAppBuilder.csproj | 24 ++ .../Templates/CMakeLists.txt.template | 44 +++ .../Templates/Info.plist.template | 37 +++ .../AppleAppBuilder/Templates/main-console.m | 93 ++++++ .../AppleAppBuilder/Templates/main-simple.m | 81 ++++++ .../AppleAppBuilder/Templates/runtime.h | 9 + .../AppleAppBuilder/Templates/runtime.m | 269 ++++++++++++++++++ .../mobile.tasks/AppleAppBuilder/Utils.cs | 95 +++++++ .../mobile.tasks/AppleAppBuilder/Xcode.cs | 169 +++++++++++ 17 files changed, 1605 insertions(+) create mode 100644 core/mono-samples/iOS/Makefile create mode 100644 core/mono-samples/iOS/Program.cs create mode 100644 core/mono-samples/iOS/Program.csproj create mode 100644 core/mono-samples/mobile.tasks/AotCompilerTask/MonoAOTCompiler.cs create mode 100644 core/mono-samples/mobile.tasks/AotCompilerTask/MonoAOTCompiler.csproj create mode 100644 core/mono-samples/mobile.tasks/AotCompilerTask/MonoAOTCompiler.props create mode 100644 core/mono-samples/mobile.tasks/AotCompilerTask/Utils.cs create mode 100644 core/mono-samples/mobile.tasks/AppleAppBuilder/AppleAppBuilder.cs create mode 100644 core/mono-samples/mobile.tasks/AppleAppBuilder/AppleAppBuilder.csproj create mode 100644 core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/CMakeLists.txt.template create mode 100644 core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/Info.plist.template create mode 100644 core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/main-console.m create mode 100644 core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/main-simple.m create mode 100644 core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/runtime.h create mode 100644 core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/runtime.m create mode 100644 core/mono-samples/mobile.tasks/AppleAppBuilder/Utils.cs create mode 100644 core/mono-samples/mobile.tasks/AppleAppBuilder/Xcode.cs diff --git a/core/mono-samples/iOS/Makefile b/core/mono-samples/iOS/Makefile new file mode 100644 index 00000000000..36dec2bc18d --- /dev/null +++ b/core/mono-samples/iOS/Makefile @@ -0,0 +1,21 @@ +MONO_CONFIG=Debug +MONO_ARCH=x64 +DOTNET := ../../../../.././dotnet.sh +USE_LLVM=True + +all: runtimepack run + +TOOLS_DIR=../../../../../tools-local/tasks/mobile.tasks +appbuilder: + $(DOTNET) build -c Release $(TOOLS_DIR)/AotCompilerTask/MonoAOTCompiler.csproj + $(DOTNET) build -c Release $(TOOLS_DIR)/AppleAppBuilder/AppleAppBuilder.csproj + +runtimepack: + ../../../../.././build.sh Mono+Libs -os iOS -arch $(MONO_ARCH) -c $(MONO_CONFIG) + +run: clean appbuilder + $(DOTNET) publish -c $(MONO_CONFIG) /p:TargetArchitecture=$(MONO_ARCH) \ + /p:UseLLVM=$(USE_LLVM) /p:UseAotForSimulator=true + +clean: + rm -rf bin diff --git a/core/mono-samples/iOS/Program.cs b/core/mono-samples/iOS/Program.cs new file mode 100644 index 00000000000..9769ded207e --- /dev/null +++ b/core/mono-samples/iOS/Program.cs @@ -0,0 +1,53 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Threading; +using System.Threading.Tasks; +using System.Runtime.InteropServices; + +// it's not part of the BCL but runtime needs it for native-to-managed callbacks in AOT +// To be replaced with NativeCallableAttribute +public class MonoPInvokeCallbackAttribute : Attribute +{ + public MonoPInvokeCallbackAttribute(Type delegateType) { } +} + +public static class Program +{ + // Defined in main.m + [DllImport("__Internal")] + private extern static void ios_set_text(string value); + + [DllImport("__Internal")] + private extern static void ios_register_button_click(Action action); + + private static Action buttonClickHandler = null; + + private static int counter = 0; + + // Called by native code, see main.m + [MonoPInvokeCallback(typeof(Action))] + private static void OnButtonClick() + { + ios_set_text("OnButtonClick! #" + counter++); + } + + public static async Task Main(string[] args) + { + // Register a managed callback (will be called by UIButton, see main.m) + // Also, keep the handler alive so GC won't collect it. + ios_register_button_click(buttonClickHandler = OnButtonClick); + + const string msg = "Hello World!\n.NET 5.0"; + for (int i = 0; i < msg.Length; i++) + { + // a kind of an animation + ios_set_text(msg.Substring(0, i + 1)); + await Task.Delay(100); + } + + Console.WriteLine("Done!"); + await Task.Delay(-1); + } +} diff --git a/core/mono-samples/iOS/Program.csproj b/core/mono-samples/iOS/Program.csproj new file mode 100644 index 00000000000..832b98b5502 --- /dev/null +++ b/core/mono-samples/iOS/Program.csproj @@ -0,0 +1,88 @@ + + + Exe + bin + Portable + $(NetCoreAppCurrent) + iOS + $(ArtifactsBinDir)microsoft.netcore.app.runtime.ios-$(TargetArchitecture)\$(Configuration)\runtimes\ios-$(TargetArchitecture)\ + false + ios-$(TargetArchitecture) + true + <_TrimmerDefaultAction>link + True + true + false + + + + + + + $(ArtifactsBinDir)microsoft.netcore.app.runtime.ios-$(TargetArchitecture)\$(Configuration) + + + + + + + + + + + + + $(MSBuildThisFileDirectory)$(PublishDir)\app + iPhone 11 + + + + + + + + @(MonoAOTCompilerDefaultAotArguments, ';') + @(MonoAOTCompilerDefaultProcessArguments, ';') + + + + + + + + + + + + + + + + + + + + + + diff --git a/core/mono-samples/mobile.tasks/AotCompilerTask/MonoAOTCompiler.cs b/core/mono-samples/mobile.tasks/AotCompilerTask/MonoAOTCompiler.cs new file mode 100644 index 00000000000..debd10c80f1 --- /dev/null +++ b/core/mono-samples/mobile.tasks/AotCompilerTask/MonoAOTCompiler.cs @@ -0,0 +1,255 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Collections.Concurrent; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +public class MonoAOTCompiler : Microsoft.Build.Utilities.Task +{ + /// + /// Path to AOT cross-compiler binary (mono-aot-cross) + /// + [Required] + public string CompilerBinaryPath { get; set; } = ""!; + + /// + /// Assemblies to be AOTd. They need to be in a self-contained directory. + /// + /// Metadata: + /// - AotArguments: semicolon-separated list of options that will be passed to --aot= + /// - ProcessArguments: semicolon-separated list of options that will be passed to the AOT compiler itself + /// + [Required] + public ITaskItem[] Assemblies { get; set; } = Array.Empty(); + + /// + /// Assemblies which were AOT compiled. + /// + /// Successful AOT compilation will set the following metadata on the items: + /// - AssemblerFile (when using OutputType=AsmOnly) + /// - ObjectFile (when using OutputType=Normal) + /// - AotDataFile + /// - LlvmObjectFile (if using LLVM) + /// - LlvmBitcodeFile (if using LLVM-only) + /// + [Output] + public ITaskItem[]? CompiledAssemblies { get; set; } + + /// + /// Disable parallel AOT compilation + /// + public bool DisableParallelAot { get; set; } + + /// + /// Use LLVM for AOT compilation. + /// The cross-compiler must be built with LLVM support + /// + public bool UseLLVM { get; set; } + + /// + /// Choose between 'Normal', 'Full', 'LLVMOnly'. + /// LLVMOnly means to use only LLVM for FullAOT, AOT result will be a LLVM Bitcode file (the cross-compiler must be built with LLVM support) + /// + public string Mode { get; set; } = nameof(MonoAotMode.Normal); + + /// + /// Choose between 'Normal', 'AsmOnly' + /// AsmOnly means the AOT compiler will produce .s assembly code instead of an .o object file. + /// + public string OutputType { get; set; } = nameof(MonoAotOutputType.Normal); + + /// + /// Path to the directory where LLVM binaries (opt and llc) are found. + /// It's required if UseLLVM is set + /// + public string? LLVMPath { get; set; } + + /// + /// Path to the directory where msym artifacts are stored. + /// + public string? MsymPath { get; set; } + + private ConcurrentBag compiledAssemblies = new ConcurrentBag(); + private MonoAotMode parsedAotMode; + private MonoAotOutputType parsedOutputType; + + public override bool Execute() + { + Utils.Logger = Log; + + if (string.IsNullOrEmpty(CompilerBinaryPath)) + { + throw new ArgumentException($"'{nameof(CompilerBinaryPath)}' is required.", nameof(CompilerBinaryPath)); + } + + if (!File.Exists(CompilerBinaryPath)) + { + throw new ArgumentException($"'{CompilerBinaryPath}' doesn't exist.", nameof(CompilerBinaryPath)); + } + + if (Assemblies.Length == 0) + { + throw new ArgumentException($"'{nameof(Assemblies)}' is required.", nameof(Assemblies)); + } + + if (UseLLVM && string.IsNullOrEmpty(LLVMPath)) + { + // prevent using some random llc/opt from PATH (installed with clang) + throw new ArgumentException($"'{nameof(LLVMPath)}' is required when '{nameof(UseLLVM)}' is true.", nameof(LLVMPath)); + } + + switch (Mode) + { + case "Normal": parsedAotMode = MonoAotMode.Normal; break; + case "Full": parsedAotMode = MonoAotMode.Full; break; + case "LLVMOnly": parsedAotMode = MonoAotMode.LLVMOnly; break; + default: + throw new ArgumentException($"'{nameof(Mode)}' must be one of: '{nameof(MonoAotMode.Normal)}', '{nameof(MonoAotMode.Full)}', '{nameof(MonoAotMode.LLVMOnly)}'. Received: '{Mode}'.", nameof(Mode)); + } + + switch (OutputType) + { + case "Normal": parsedOutputType = MonoAotOutputType.Normal; break; + case "AsmOnly": parsedOutputType = MonoAotOutputType.AsmOnly; break; + default: + throw new ArgumentException($"'{nameof(OutputType)}' must be one of: '{nameof(MonoAotOutputType.Normal)}', '{nameof(MonoAotOutputType.AsmOnly)}'. Received: '{OutputType}'.", nameof(OutputType)); + } + + if (parsedAotMode == MonoAotMode.LLVMOnly && !UseLLVM) + { + throw new ArgumentException($"'{nameof(UseLLVM)}' must be true when '{nameof(Mode)}' is {nameof(MonoAotMode.LLVMOnly)}.", nameof(UseLLVM)); + } + + Parallel.ForEach(Assemblies, + new ParallelOptions { MaxDegreeOfParallelism = DisableParallelAot ? 1 : Environment.ProcessorCount }, + assemblyItem => PrecompileLibrary (assemblyItem)); + + CompiledAssemblies = compiledAssemblies.ToArray(); + + return true; + } + + private void PrecompileLibrary(ITaskItem assemblyItem) + { + string assembly = assemblyItem.ItemSpec; + string directory = Path.GetDirectoryName(assembly)!; + var aotAssembly = new TaskItem(assembly); + var aotArgs = new List(); + var processArgs = new List(); + + var a = assemblyItem.GetMetadata("AotArguments"); + if (a != null) + { + aotArgs.AddRange(a.Split(";", StringSplitOptions.RemoveEmptyEntries)); + } + + var p = assemblyItem.GetMetadata("ProcessArguments"); + if (p != null) + { + processArgs.AddRange(p.Split(";", StringSplitOptions.RemoveEmptyEntries)); + } + + Utils.LogInfo($"[AOT] {assembly}"); + + processArgs.Add("--debug"); + + // add LLVM options + if (UseLLVM) + { + processArgs.Add("--llvm"); + + aotArgs.Add($"nodebug"); // can't use debug symbols with LLVM + aotArgs.Add($"llvm-path={LLVMPath}"); + } + else + { + processArgs.Add("--nollvm"); + } + + // compute output mode and file names + if (parsedAotMode == MonoAotMode.LLVMOnly) + { + aotArgs.Add("llvmonly"); + + string llvmBitcodeFile = Path.ChangeExtension(assembly, ".dll.bc"); + aotArgs.Add($"outfile={llvmBitcodeFile}"); + aotAssembly.SetMetadata("LlvmBitcodeFile", llvmBitcodeFile); + } + else + { + if (parsedAotMode == MonoAotMode.Full) + { + aotArgs.Add("full"); + } + + if (parsedOutputType == MonoAotOutputType.AsmOnly) + { + aotArgs.Add("asmonly"); + + string assemblerFile = Path.ChangeExtension(assembly, ".dll.s"); + aotArgs.Add($"outfile={assemblerFile}"); + aotAssembly.SetMetadata("AssemblerFile", assemblerFile); + } + else + { + string objectFile = Path.ChangeExtension(assembly, ".dll.o"); + aotArgs.Add($"outfile={objectFile}"); + aotAssembly.SetMetadata("ObjectFile", objectFile); + } + + if (UseLLVM) + { + string llvmObjectFile = Path.ChangeExtension(assembly, ".dll-llvm.o"); + aotArgs.Add($"llvm-outfile={llvmObjectFile}"); + aotAssembly.SetMetadata("LlvmObjectFile", llvmObjectFile); + } + } + + // pass msym-dir if specified + if (MsymPath != null) + { + aotArgs.Add($"msym-dir={MsymPath}"); + } + + string aotDataFile = Path.ChangeExtension(assembly, ".aotdata"); + aotArgs.Add($"data-outfile={aotDataFile}"); + aotAssembly.SetMetadata("AotDataFile", aotDataFile); + + // we need to quote the entire --aot arguments here to make sure it is parsed + // on Windows as one argument. Otherwise it will be split up into multiple + // values, which wont work. + processArgs.Add($"\"--aot={string.Join(",", aotArgs)}\""); + + processArgs.Add(assembly); + + var envVariables = new Dictionary + { + {"MONO_PATH", directory}, + {"MONO_ENV_OPTIONS", string.Empty} // we do not want options to be provided out of band to the cross compilers + }; + + // run the AOT compiler + Utils.RunProcess(CompilerBinaryPath, string.Join(" ", processArgs), envVariables, directory); + + compiledAssemblies.Add(aotAssembly); + } +} + +public enum MonoAotMode +{ + Normal, + Full, + LLVMOnly, +} + +public enum MonoAotOutputType +{ + Normal, + AsmOnly, +} diff --git a/core/mono-samples/mobile.tasks/AotCompilerTask/MonoAOTCompiler.csproj b/core/mono-samples/mobile.tasks/AotCompilerTask/MonoAOTCompiler.csproj new file mode 100644 index 00000000000..ab121a31019 --- /dev/null +++ b/core/mono-samples/mobile.tasks/AotCompilerTask/MonoAOTCompiler.csproj @@ -0,0 +1,25 @@ + + + $(NetCoreAppCurrent) + Library + true + false + enable + $(NoWarn),CA1050 + + + + + + + + + + + + + + PreserveNewest + + + diff --git a/core/mono-samples/mobile.tasks/AotCompilerTask/MonoAOTCompiler.props b/core/mono-samples/mobile.tasks/AotCompilerTask/MonoAOTCompiler.props new file mode 100644 index 00000000000..6824a7fc1c6 --- /dev/null +++ b/core/mono-samples/mobile.tasks/AotCompilerTask/MonoAOTCompiler.props @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/core/mono-samples/mobile.tasks/AotCompilerTask/Utils.cs b/core/mono-samples/mobile.tasks/AotCompilerTask/Utils.cs new file mode 100644 index 00000000000..a7c23d4132a --- /dev/null +++ b/core/mono-samples/mobile.tasks/AotCompilerTask/Utils.cs @@ -0,0 +1,87 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +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 RunProcess( + string path, + string args = "", + IDictionary? 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 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/core/mono-samples/mobile.tasks/AppleAppBuilder/AppleAppBuilder.cs b/core/mono-samples/mobile.tasks/AppleAppBuilder/AppleAppBuilder.cs new file mode 100644 index 00000000000..744b2960e9d --- /dev/null +++ b/core/mono-samples/mobile.tasks/AppleAppBuilder/AppleAppBuilder.cs @@ -0,0 +1,238 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Linq; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +public class AppleAppBuilderTask : Task +{ + /// + /// ProjectName is used as an app name, bundleId and xcode project name + /// + [Required] + public string ProjectName { get; set; } = ""!; + + /// + /// Target directory with *dll and other content to be AOT'd and/or bundled + /// + [Required] + public string AppDir { get; set; } = ""!; + + /// + /// Path to Mono public headers (*.h) + /// + [Required] + public string MonoRuntimeHeaders { get; set; } = ""!; + + /// + /// This library will be used as an entry-point (e.g. TestRunner.dll) + /// + [Required] + public string MainLibraryFileName { get; set; } = ""!; + + /// + /// List of paths to assemblies to be included in the app. For AOT builds the 'ObjectFile' metadata key needs to point to the object file. + /// + [Required] + public ITaskItem[] Assemblies { get; set; } = Array.Empty(); + + /// + /// Path to store build artifacts + /// + public string? OutputDirectory { get; set; } + + /// + /// Produce optimized binaries and use 'Release' config in xcode + /// + public bool Optimized { get; set; } + + /// + /// Target arch, can be "arm64" (device) or "x64" (simulator) at the moment + /// + [Required] + public string Arch { get; set; } = ""!; + + /// + /// DEVELOPER_TEAM provisioning, needed for arm64 builds. + /// + public string? DevTeamProvisioning { get; set; } + + /// + /// Build *.app bundle (using XCode for now) + /// + public bool BuildAppBundle { get; set; } + + /// + /// Generate xcode project + /// + public bool GenerateXcodeProject { get; set; } + + /// + /// Files to be ignored in AppDir + /// + public ITaskItem[]? ExcludeFromAppDir { get; set; } + + /// + /// Path to a custom main.m with custom UI + /// A default one is used if it's not set + /// + public string? NativeMainSource { get; set; } + + /// + /// Use Console-style native UI template + /// (use NativeMainSource to override) + /// + public bool UseConsoleUITemplate { get; set; } + + /// + /// Path to *.app bundle + /// + [Output] + public string AppBundlePath { get; set; } = ""!; + + /// + /// Prefer FullAOT mode for Simulator over JIT + /// + public bool UseAotForSimulator { get; set; } + + /// + /// Path to xcode project + /// + [Output] + public string XcodeProjectPath { get; set; } = ""!; + + public override bool Execute() + { + Utils.Logger = Log; + bool isDevice = Arch.Equals("arm64", StringComparison.InvariantCultureIgnoreCase); + + if (!File.Exists(Path.Combine(AppDir, MainLibraryFileName))) + { + throw new ArgumentException($"MainLibraryFileName='{MainLibraryFileName}' was not found in AppDir='{AppDir}'"); + } + + if (ProjectName.Contains(" ")) + { + throw new ArgumentException($"ProjectName='{ProjectName}' should not contain spaces"); + } + + string[] excludes = Array.Empty(); + if (ExcludeFromAppDir != null) + { + excludes = ExcludeFromAppDir + .Where(i => !string.IsNullOrEmpty(i.ItemSpec)) + .Select(i => i.ItemSpec) + .ToArray(); + } + + string binDir = Path.Combine(AppDir, $"bin-{ProjectName}-{Arch}"); + if (!string.IsNullOrEmpty(OutputDirectory)) + { + binDir = OutputDirectory; + } + Directory.CreateDirectory(binDir); + + var assemblerFiles = new List(); + foreach (ITaskItem file in Assemblies) + { + // use AOT files if available + var obj = file.GetMetadata("AssemblerFile"); + if (!string.IsNullOrEmpty(obj)) + { + assemblerFiles.Add(obj); + } + } + + if ((isDevice || UseAotForSimulator) && !assemblerFiles.Any()) + { + throw new InvalidOperationException("Need list of AOT files for device builds."); + } + + // generate modules.m + GenerateLinkAllFile( + assemblerFiles, + Path.Combine(binDir, "modules.m")); + + if (GenerateXcodeProject) + { + XcodeProjectPath = Xcode.GenerateXCode(ProjectName, MainLibraryFileName, assemblerFiles, + AppDir, binDir, MonoRuntimeHeaders, !isDevice, UseConsoleUITemplate, UseAotForSimulator, Optimized, 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); + } + } + } + + return true; + } + + private static void GenerateLinkAllFile(IEnumerable asmFiles, 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 ") + .AppendLine("#include ") + .AppendLine() + .AppendLine("#if TARGET_OS_IPHONE && (!TARGET_IPHONE_SIMULATOR || USE_AOT_FOR_SIMULATOR)") + .AppendLine(); + + var lsUsage = new StringBuilder(); + lsUsage + .AppendLine("void mono_ios_register_modules (void)") + .AppendLine("{"); + foreach (string asmFile in asmFiles) + { + string symbol = "mono_aot_module_" + + Path.GetFileName(asmFile) + .Replace(".dll.s", "") + .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/core/mono-samples/mobile.tasks/AppleAppBuilder/AppleAppBuilder.csproj b/core/mono-samples/mobile.tasks/AppleAppBuilder/AppleAppBuilder.csproj new file mode 100644 index 00000000000..61bf42d2995 --- /dev/null +++ b/core/mono-samples/mobile.tasks/AppleAppBuilder/AppleAppBuilder.csproj @@ -0,0 +1,24 @@ + + + net5.0 + Library + true + false + enable + $(NoWarn),CA1050 + + + + + + + + + + + + + + + + diff --git a/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/CMakeLists.txt.template b/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/CMakeLists.txt.template new file mode 100644 index 00000000000..ecd3d6c1e61 --- /dev/null +++ b/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/CMakeLists.txt.template @@ -0,0 +1,44 @@ +cmake_minimum_required(VERSION 3.16) + +project(%ProjectName%) +enable_language(OBJC ASM) + +set(APP_RESOURCES +%AppResources% +) + +add_executable( + %ProjectName% + %MainSource% + runtime.h + runtime.m + modules.m + ${APP_RESOURCES} +) + +%AotSources% + +%Defines% + +include_directories("%MonoInclude%") + +set_target_properties(%ProjectName% PROPERTIES + MACOSX_BUNDLE TRUE + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist + 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% +) diff --git a/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/Info.plist.template b/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/Info.plist.template new file mode 100644 index 00000000000..c8c0f53f160 --- /dev/null +++ b/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/Info.plist.template @@ -0,0 +1,37 @@ + + + + + CFBundleDevelopmentRegion + en-US + CFBundleExecutable + %BundleIdentifier% + CFBundleIdentifier + net.dot.%BundleIdentifier% + CFBundleName + %BundleIdentifier% + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + + + diff --git a/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/main-console.m b/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/main-console.m new file mode 100644 index 00000000000..20b9f8714d3 --- /dev/null +++ b/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/main-console.m @@ -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. + +#import +#import "runtime.h" +#include + +@interface ViewController : UIViewController +@end + +@interface AppDelegate : UIResponder +@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 - 2.0, applicationFrame.size.height - 50.0)]; + 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 - 10.0, 50)]; + summaryLabel.textColor = [UIColor whiteColor]; + summaryLabel.font = [UIFont boldSystemFontOfSize: 12]; + summaryLabel.numberOfLines = 2; + summaryLabel.textAlignment = NSTextAlignmentLeft; +#ifdef TARGET_OS_IPHONE && (!TARGET_IPHONE_SIMULATOR || USE_AOT_FOR_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: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:value]; + dispatch_async(dispatch_get_main_queue(), ^{ + logLabel.text = [logLabel.text stringByAppendingString:nsstr]; + CGRect caretRect = [logLabel caretRectForPosition:logLabel.endOfDocument]; + [logLabel scrollRectToVisible:caretRect animated:NO]; + [logLabel setScrollEnabled:NO]; + [logLabel setScrollEnabled:YES]; + }); +} + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/main-simple.m b/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/main-simple.m new file mode 100644 index 00000000000..e05868ffcd4 --- /dev/null +++ b/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/main-simple.m @@ -0,0 +1,81 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#import +#import "runtime.h" + +@interface ViewController : UIViewController +@end + +@interface AppDelegate : UIResponder +@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/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/runtime.h b/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/runtime.h new file mode 100644 index 00000000000..08fa626eba1 --- /dev/null +++ b/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/runtime.h @@ -0,0 +1,9 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#ifndef runtime_h +#define runtime_h + +void mono_ios_runtime_init (void); + +#endif /* runtime_h */ diff --git a/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/runtime.m b/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/runtime.m new file mode 100644 index 00000000000..02c0070fb6b --- /dev/null +++ b/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/runtime.m @@ -0,0 +1,269 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#import +#include +#include +#include +#include +#include +#include +#include +#include +#include +#import +#include +#include + +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 + +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]); + + return bundle_path; +} + +static unsigned char * +load_aot_data (MonoAssembly *assembly, int size, void *user_data, void **out_handle) +{ + *out_handle = NULL; + + char path [1024]; + int res; + + MonoAssemblyName *assembly_name = mono_assembly_get_name (assembly); + const char *aname = mono_assembly_name_get_name (assembly_name); + const char *bundle = get_bundle_path (); + + os_log_info (OS_LOG_DEFAULT, "Looking for aot data for assembly '%s'.", aname); + res = snprintf (path, sizeof (path) - 1, "%s/%s.aotdata", bundle, aname); + assert (res > 0); + + int fd = open (path, O_RDONLY); + if (fd < 0) { + os_log_info (OS_LOG_DEFAULT, "Could not load the aot data for %s from %s: %s\n", aname, path, strerror (errno)); + return NULL; + } + + void *ptr = mmap (NULL, size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0); + if (ptr == MAP_FAILED) { + os_log_info (OS_LOG_DEFAULT, "Could not map the aot file for %s: %s\n", aname, strerror (errno)); + close (fd); + return NULL; + } + + close (fd); + os_log_info (OS_LOG_DEFAULT, "Loaded aot data for %s.\n", aname); + *out_handle = ptr; + return (unsigned char *) ptr; +} + +static void +free_aot_data (MonoAssembly *assembly, int size, void *user_data, void *handle) +{ + munmap (handle, size); +} + +static MonoAssembly* +load_assembly (const char *name, const char *culture) +{ + const char *bundle = get_bundle_path (); + char filename [1024]; + char path [1024]; + int res; + + os_log_info (OS_LOG_DEFAULT, "assembly_preload_hook: %{public}s %{public}s %{public}s\n", name, culture, bundle); + + int len = strlen (name); + int has_extension = len > 3 && name [len - 4] == '.' && (!strcmp ("exe", name + (len - 3)) || !strcmp ("dll", name + (len - 3))); + + // add extensions if required. + strlcpy (filename, name, sizeof (filename)); + if (!has_extension) { + strlcat (filename, ".dll", sizeof (filename)); + } + + if (culture && strcmp (culture, "")) + res = snprintf (path, sizeof (path) - 1, "%s/%s/%s", bundle, culture, filename); + 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); + assert (assembly); + return assembly; + } + return NULL; +} + +static MonoAssembly* +assembly_preload_hook (MonoAssemblyName *aname, char **assemblies_path, void* user_data) +{ + const char *name = mono_assembly_name_get_name (aname); + const char *culture = mono_assembly_name_get_culture (aname); + return load_assembly (name, culture); +} + +char * +strdup_printf (const char *msg, ...) +{ + va_list args; + char *formatted = NULL; + va_start (args, msg); + vasprintf (&formatted, msg, args); + va_end (args); + return formatted; +} + +static MonoObject * +fetch_exception_property (MonoObject *obj, const char *name, bool is_virtual) +{ + MonoMethod *get = NULL; + MonoMethod *get_virt = NULL; + MonoObject *exc = NULL; + + get = mono_class_get_method_from_name (mono_get_exception_class (), name, 0); + if (get) { + if (is_virtual) { + get_virt = mono_object_get_virtual_method (obj, get); + if (get_virt) + get = get_virt; + } + + return (MonoObject *) mono_runtime_invoke (get, obj, NULL, &exc); + } else { + printf ("Could not find the property System.Exception.%s", name); + } + + return NULL; +} + +static char * +fetch_exception_property_string (MonoObject *obj, const char *name, bool is_virtual) +{ + MonoString *str = (MonoString *) fetch_exception_property (obj, name, is_virtual); + return str ? mono_string_to_utf8 (str) : NULL; +} + +void +unhandled_exception_handler (MonoObject *exc, void *user_data) +{ + NSMutableString *msg = [[NSMutableString alloc] init]; + + MonoClass *type = mono_object_get_class (exc); + char *type_name = strdup_printf ("%s.%s", mono_class_get_namespace (type), mono_class_get_name (type)); + char *trace = fetch_exception_property_string (exc, "get_StackTrace", true); + char *message = fetch_exception_property_string (exc, "get_Message", true); + + [msg appendString:@"Unhandled managed exceptions:\n"]; + [msg appendFormat: @"%s (%s)\n%s\n", message, type_name, trace ? trace : ""]; + + free (trace); + free (message); + free (type_name); + + os_log_info (OS_LOG_DEFAULT, "%@", msg); + os_log_info (OS_LOG_DEFAULT, "Exit code: %d.", 1); + exit (1); +} + +void +log_callback (const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data) +{ + os_log_info (OS_LOG_DEFAULT, "(%s %s) %s", log_domain, log_level, message); + if (fatal) { + os_log_info (OS_LOG_DEFAULT, "Exit code: %d.", 1); + exit (1); + } +} + +static void +register_dllmap (void) +{ +//%DllMap% +} + +#if TARGET_OS_IPHONE && (!TARGET_IPHONE_SIMULATOR || USE_AOT_FOR_SIMULATOR) +void mono_jit_set_aot_mode (MonoAotMode mode); +void mono_ios_register_modules (void); +#endif + +void +mono_ios_runtime_init (void) +{ + // for now, only Invariant Mode is supported (FIXME: integrate ICU) + setenv ("DOTNET_SYSTEM_GLOBALIZATION_INVARIANT", "1", TRUE); + // uncomment for debug output: + // + // setenv ("MONO_LOG_LEVEL", "debug", TRUE); + // setenv ("MONO_LOG_MASK", "all", TRUE); + + 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]; + managed_argv[argi] = [arg UTF8String]; + } + + bool wait_for_debugger = FALSE; + + const char* bundle = get_bundle_path (); + chdir (bundle); + + // TODO: set TRUSTED_PLATFORM_ASSEMBLIES, APP_PATHS and NATIVE_DLL_SEARCH_DIRECTORIES + monovm_initialize(0, NULL, NULL); + +#if TARGET_OS_IPHONE && (!TARGET_IPHONE_SIMULATOR || USE_AOT_FOR_SIMULATOR) + register_dllmap (); + // register modules + mono_ios_register_modules (); + 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); + mono_install_unhandled_exception_hook (unhandled_exception_handler, NULL); + mono_trace_set_log_handler (log_callback, NULL); + mono_set_signal_chaining (TRUE); + mono_set_crash_chaining (TRUE); + + if (wait_for_debugger) { + char* options[] = { "--debugger-agent=transport=dt_socket,server=y,address=0.0.0.0:55555" }; + mono_jit_parse_options (1, options); + } + mono_jit_init_version ("dotnet.ios", "mobile"); + +#if TARGET_OS_IPHONE && (!TARGET_IPHONE_SIMULATOR || USE_AOT_FOR_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, argi, managed_argv); + // Print this so apps parsing logs can detect when we exited + os_log_info (OS_LOG_DEFAULT, "Exit code: %d.", res); + + exit (res); +} diff --git a/core/mono-samples/mobile.tasks/AppleAppBuilder/Utils.cs b/core/mono-samples/mobile.tasks/AppleAppBuilder/Utils.cs new file mode 100644 index 00000000000..83304bd393c --- /dev/null +++ b/core/mono-samples/mobile.tasks/AppleAppBuilder/Utils.cs @@ -0,0 +1,95 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +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? 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 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/core/mono-samples/mobile.tasks/AppleAppBuilder/Xcode.cs b/core/mono-samples/mobile.tasks/AppleAppBuilder/Xcode.cs new file mode 100644 index 00000000000..1d67b35f349 --- /dev/null +++ b/core/mono-samples/mobile.tasks/AppleAppBuilder/Xcode.cs @@ -0,0 +1,169 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +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, + IEnumerable asmFiles, + string workspace, + string binDir, + string monoInclude, + bool preferDylibs, + bool useConsoleUiTemplate, + bool useAotForSimulator, + bool stripDebugSymbols, + string? nativeMainSource = null) + { + // bundle everything as resources excluding native files + var excludes = new List { ".dll.o", ".dll.s", ".dwarf", ".m", ".h", ".a", ".bc", "libmonosgen-2.0.dylib" }; + if (stripDebugSymbols) + { + excludes.Add(".pdb"); + } + + 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[] dylibs = Directory.GetFiles(workspace, "*.dylib"); + string toLink = ""; + foreach (string lib in Directory.GetFiles(workspace, "*.a")) + { + string libName = Path.GetFileNameWithoutExtension(lib); + // 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 (!preferDylibs || !dylibExists) + { + // these libraries are pinvoked + // -force_load will be removed once we enable direct-pinvokes for AOT + toLink += $" \"-force_load {lib}\"{Environment.NewLine}"; + } + } + + string aotSources = ""; + foreach (string asm in asmFiles) + { + // these libraries are linked via modules.m + var name = Path.GetFileNameWithoutExtension(asm); + aotSources += $"add_library({name} OBJECT {asm}){Environment.NewLine}"; + toLink += $" {name}{Environment.NewLine}"; + } + + cmakeLists = cmakeLists.Replace("%NativeLibrariesToLink%", toLink); + cmakeLists = cmakeLists.Replace("%AotSources%", aotSources); + cmakeLists = cmakeLists.Replace("%Defines%", + useAotForSimulator ? "add_definitions(-DUSE_AOT_FOR_SIMULATOR=1)" : ""); + + string plist = Utils.GetEmbeddedResource("Info.plist.template") + .Replace("%BundleIdentifier%", projectName); + + File.WriteAllText(Path.Combine(binDir, "Info.plist"), 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" + 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);"); + + // 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("%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)); + + string appPath = Path.Combine(Path.GetDirectoryName(xcodePrjPath)!, config + "-" + sdk, + Path.GetFileNameWithoutExtension(xcodePrjPath) + ".app"); + + long appSize = new DirectoryInfo(appPath) + .EnumerateFiles("*", SearchOption.AllDirectories) + .Sum(file => file.Length); + + Utils.LogInfo($"\nAPP size: {(appSize / 1000_000.0):0.#} Mb.\n"); + + return appPath; + } +} From a8a7887d71391e32e14c0e73dcac0ede4a95b60b Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Tue, 29 Sep 2020 13:13:37 -0400 Subject: [PATCH 02/41] Remove dependency on dotnet.sh and MonoAotCompiler --- core/mono-samples/iOS/Makefile | 8 +++----- core/mono-samples/iOS/Program.csproj | 11 ----------- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/core/mono-samples/iOS/Makefile b/core/mono-samples/iOS/Makefile index 36dec2bc18d..62e4c926fea 100644 --- a/core/mono-samples/iOS/Makefile +++ b/core/mono-samples/iOS/Makefile @@ -1,21 +1,19 @@ MONO_CONFIG=Debug MONO_ARCH=x64 -DOTNET := ../../../../.././dotnet.sh USE_LLVM=True all: runtimepack run TOOLS_DIR=../../../../../tools-local/tasks/mobile.tasks appbuilder: - $(DOTNET) build -c Release $(TOOLS_DIR)/AotCompilerTask/MonoAOTCompiler.csproj - $(DOTNET) build -c Release $(TOOLS_DIR)/AppleAppBuilder/AppleAppBuilder.csproj + dotnet build -c Release $(TOOLS_DIR)/AppleAppBuilder/AppleAppBuilder.csproj runtimepack: ../../../../.././build.sh Mono+Libs -os iOS -arch $(MONO_ARCH) -c $(MONO_CONFIG) run: clean appbuilder - $(DOTNET) publish -c $(MONO_CONFIG) /p:TargetArchitecture=$(MONO_ARCH) \ - /p:UseLLVM=$(USE_LLVM) /p:UseAotForSimulator=true + dotnet publish -c $(MONO_CONFIG) /p:TargetArchitecture=$(MONO_ARCH) \ + /p:UseLLVM=$(USE_LLVM) /p:UseAotForSimulator=false clean: rm -rf bin diff --git a/core/mono-samples/iOS/Program.csproj b/core/mono-samples/iOS/Program.csproj index 832b98b5502..d94d76463e3 100644 --- a/core/mono-samples/iOS/Program.csproj +++ b/core/mono-samples/iOS/Program.csproj @@ -48,17 +48,6 @@ - - - - Date: Tue, 29 Sep 2020 13:47:33 -0400 Subject: [PATCH 03/41] Remove reference to in-tree runtime pack --- core/mono-samples/iOS/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/mono-samples/iOS/Makefile b/core/mono-samples/iOS/Makefile index 62e4c926fea..b6959bd48df 100644 --- a/core/mono-samples/iOS/Makefile +++ b/core/mono-samples/iOS/Makefile @@ -2,7 +2,7 @@ MONO_CONFIG=Debug MONO_ARCH=x64 USE_LLVM=True -all: runtimepack run +all: run TOOLS_DIR=../../../../../tools-local/tasks/mobile.tasks appbuilder: From 7d20c40f2ea4fb8c9e3e6b7f750ff1dbd54db128 Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Tue, 29 Sep 2020 13:47:57 -0400 Subject: [PATCH 04/41] Modify path to mobile.tasks --- core/mono-samples/iOS/Makefile | 2 +- core/mono-samples/iOS/Program.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/mono-samples/iOS/Makefile b/core/mono-samples/iOS/Makefile index b6959bd48df..0aaeca6f5c6 100644 --- a/core/mono-samples/iOS/Makefile +++ b/core/mono-samples/iOS/Makefile @@ -4,7 +4,7 @@ USE_LLVM=True all: run -TOOLS_DIR=../../../../../tools-local/tasks/mobile.tasks +TOOLS_DIR=../mobile.tasks appbuilder: dotnet build -c Release $(TOOLS_DIR)/AppleAppBuilder/AppleAppBuilder.csproj diff --git a/core/mono-samples/iOS/Program.csproj b/core/mono-samples/iOS/Program.csproj index d94d76463e3..d939278540c 100644 --- a/core/mono-samples/iOS/Program.csproj +++ b/core/mono-samples/iOS/Program.csproj @@ -25,7 +25,7 @@ - + From 4b5e9cbdf884ef680ff52822ad43b2cbf9f09aea Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Tue, 29 Sep 2020 13:48:33 -0400 Subject: [PATCH 05/41] Directly reference TargetFramework --- core/mono-samples/iOS/Program.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/mono-samples/iOS/Program.csproj b/core/mono-samples/iOS/Program.csproj index d939278540c..ad1867dbc1a 100644 --- a/core/mono-samples/iOS/Program.csproj +++ b/core/mono-samples/iOS/Program.csproj @@ -3,7 +3,7 @@ Exe bin Portable - $(NetCoreAppCurrent) + net5.0 iOS $(ArtifactsBinDir)microsoft.netcore.app.runtime.ios-$(TargetArchitecture)\$(Configuration)\runtimes\ios-$(TargetArchitecture)\ false From c5d22c74302c627b6cb7be935f00f7eb0e64c17e Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Tue, 29 Sep 2020 14:38:22 -0400 Subject: [PATCH 06/41] Modify AppleAppBuilder config --- core/mono-samples/iOS/Makefile | 2 +- core/mono-samples/iOS/Program.csproj | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/core/mono-samples/iOS/Makefile b/core/mono-samples/iOS/Makefile index 0aaeca6f5c6..a4049d921ce 100644 --- a/core/mono-samples/iOS/Makefile +++ b/core/mono-samples/iOS/Makefile @@ -6,7 +6,7 @@ all: run TOOLS_DIR=../mobile.tasks appbuilder: - dotnet build -c Release $(TOOLS_DIR)/AppleAppBuilder/AppleAppBuilder.csproj + dotnet build -c Debug $(TOOLS_DIR)/AppleAppBuilder/AppleAppBuilder.csproj runtimepack: ../../../../.././build.sh Mono+Libs -os iOS -arch $(MONO_ARCH) -c $(MONO_CONFIG) diff --git a/core/mono-samples/iOS/Program.csproj b/core/mono-samples/iOS/Program.csproj index ad1867dbc1a..1d217a45737 100644 --- a/core/mono-samples/iOS/Program.csproj +++ b/core/mono-samples/iOS/Program.csproj @@ -27,10 +27,7 @@ - - + AssemblyFile="..\mobile.tasks\AppleAppBuilder\bin\$(Configuration)\$(TargetFramework)\AppleAppBuilder.dll" /> From e87abe0d21f97374892f3aba3f172a3434ae61b4 Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Tue, 29 Sep 2020 14:39:25 -0400 Subject: [PATCH 07/41] Use forward slash in paths --- core/mono-samples/iOS/Program.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/mono-samples/iOS/Program.csproj b/core/mono-samples/iOS/Program.csproj index 1d217a45737..80597d28e90 100644 --- a/core/mono-samples/iOS/Program.csproj +++ b/core/mono-samples/iOS/Program.csproj @@ -5,7 +5,7 @@ Portable net5.0 iOS - $(ArtifactsBinDir)microsoft.netcore.app.runtime.ios-$(TargetArchitecture)\$(Configuration)\runtimes\ios-$(TargetArchitecture)\ + $(ArtifactsBinDir)microsoft.netcore.app.runtime.ios-$(TargetArchitecture)/$(Configuration)/runtimes/ios-$(TargetArchitecture)/ false ios-$(TargetArchitecture) true @@ -48,7 +48,7 @@ Date: Tue, 29 Sep 2020 14:39:37 -0400 Subject: [PATCH 08/41] Remove in-tree runtime pack reference --- core/mono-samples/iOS/Program.csproj | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/core/mono-samples/iOS/Program.csproj b/core/mono-samples/iOS/Program.csproj index 80597d28e90..06c7b27616b 100644 --- a/core/mono-samples/iOS/Program.csproj +++ b/core/mono-samples/iOS/Program.csproj @@ -15,16 +15,6 @@ false - - - - - $(ArtifactsBinDir)microsoft.netcore.app.runtime.ios-$(TargetArchitecture)\$(Configuration) - - - - - From 06d67cd41005095621b1250c5f8e5e26e35219e2 Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Tue, 29 Sep 2020 15:47:42 -0400 Subject: [PATCH 09/41] Add TargetArch remove MNCARPD --- core/mono-samples/iOS/Program.csproj | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/mono-samples/iOS/Program.csproj b/core/mono-samples/iOS/Program.csproj index 06c7b27616b..77623f8d2e0 100644 --- a/core/mono-samples/iOS/Program.csproj +++ b/core/mono-samples/iOS/Program.csproj @@ -5,9 +5,8 @@ Portable net5.0 iOS - $(ArtifactsBinDir)microsoft.netcore.app.runtime.ios-$(TargetArchitecture)/$(Configuration)/runtimes/ios-$(TargetArchitecture)/ false - ios-$(TargetArchitecture) + ios-x64 true <_TrimmerDefaultAction>link True From 33b7058f13a06ad67972c4a09c0adb55d8e290db Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Tue, 29 Sep 2020 16:00:56 -0400 Subject: [PATCH 10/41] Add NuGet and BuildAppBundle after publish --- core/mono-samples/iOS/NuGet.config | 6 ++++++ core/mono-samples/iOS/Program.csproj | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 core/mono-samples/iOS/NuGet.config diff --git a/core/mono-samples/iOS/NuGet.config b/core/mono-samples/iOS/NuGet.config new file mode 100644 index 00000000000..176406763c7 --- /dev/null +++ b/core/mono-samples/iOS/NuGet.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/core/mono-samples/iOS/Program.csproj b/core/mono-samples/iOS/Program.csproj index 77623f8d2e0..cfcf989379d 100644 --- a/core/mono-samples/iOS/Program.csproj +++ b/core/mono-samples/iOS/Program.csproj @@ -18,7 +18,7 @@ - + $(MSBuildThisFileDirectory)$(PublishDir)\app iPhone 11 @@ -37,7 +37,7 @@ Date: Wed, 30 Sep 2020 16:12:59 -0400 Subject: [PATCH 11/41] Minimal working sample --- core/mono-samples/iOS/Program.csproj | 63 +++++++++++++--------------- 1 file changed, 29 insertions(+), 34 deletions(-) diff --git a/core/mono-samples/iOS/Program.csproj b/core/mono-samples/iOS/Program.csproj index cfcf989379d..9ed961d8d8d 100644 --- a/core/mono-samples/iOS/Program.csproj +++ b/core/mono-samples/iOS/Program.csproj @@ -1,54 +1,49 @@ - Exe - bin - Portable net5.0 - iOS - false ios-x64 - true - <_TrimmerDefaultAction>link - True - true - false + Exe - + + + + + + + - $(MSBuildThisFileDirectory)$(PublishDir)\app + $(MSBuildThisFileDirectory)$(PublishDir) iPhone 11 + True - - - - - @(MonoAOTCompilerDefaultAotArguments, ';') - @(MonoAOTCompilerDefaultProcessArguments, ';') - + - - + ProjectName="HelloiOS" + AppDir="$(MSBuildThisFileDirectory)$(PublishDir)" + MonoRuntimeHeaders="%(ResolvedRuntimePack.PackageDirectory)\runtimes\ios-x64\native\include\mono-2.0" + MainLibraryFileName="$(MSBuildThisFileName).dll" + Assemblies="@(BundleAssemblies)" + OutputDirectory="$(AppDir)\app" + Optimized="$(Optimized)" + Arch="x64" + DevTeamProvisioning="$(DevTeamProvisioning)" + BuildAppBundle="True" + GenerateXcodeProject="True" + ExcludeFromAppDir="@(ExcludeFromAppDir)" + NativeMainSource="$(NativeMainSource)" + UseConsoleUITemplate="$(UseConsoleUITemplate)" + UseAotForSimulator="$(UseAotForSimulator)"> + + @@ -60,4 +55,4 @@ - + \ No newline at end of file From 894f033c9be34b9eab0536659c2941ba93fbcf9f Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Thu, 1 Oct 2020 11:56:47 -0400 Subject: [PATCH 12/41] Modify sample to rely on nuget package instead --- core/mono-samples/iOS/Makefile | 19 -- core/mono-samples/iOS/NuGet.config | 6 - core/mono-samples/iOS/Program.csproj | 17 +- .../AotCompilerTask/MonoAOTCompiler.cs | 255 ----------------- .../AotCompilerTask/MonoAOTCompiler.csproj | 25 -- .../AotCompilerTask/MonoAOTCompiler.props | 17 -- .../mobile.tasks/AotCompilerTask/Utils.cs | 87 ------ .../AppleAppBuilder/AppleAppBuilder.cs | 238 ---------------- .../AppleAppBuilder/AppleAppBuilder.csproj | 24 -- .../Templates/CMakeLists.txt.template | 44 --- .../Templates/Info.plist.template | 37 --- .../AppleAppBuilder/Templates/main-console.m | 93 ------ .../AppleAppBuilder/Templates/main-simple.m | 81 ------ .../AppleAppBuilder/Templates/runtime.h | 9 - .../AppleAppBuilder/Templates/runtime.m | 269 ------------------ .../mobile.tasks/AppleAppBuilder/Utils.cs | 95 ------- .../mobile.tasks/AppleAppBuilder/Xcode.cs | 169 ----------- 17 files changed, 9 insertions(+), 1476 deletions(-) delete mode 100644 core/mono-samples/iOS/Makefile delete mode 100644 core/mono-samples/iOS/NuGet.config delete mode 100644 core/mono-samples/mobile.tasks/AotCompilerTask/MonoAOTCompiler.cs delete mode 100644 core/mono-samples/mobile.tasks/AotCompilerTask/MonoAOTCompiler.csproj delete mode 100644 core/mono-samples/mobile.tasks/AotCompilerTask/MonoAOTCompiler.props delete mode 100644 core/mono-samples/mobile.tasks/AotCompilerTask/Utils.cs delete mode 100644 core/mono-samples/mobile.tasks/AppleAppBuilder/AppleAppBuilder.cs delete mode 100644 core/mono-samples/mobile.tasks/AppleAppBuilder/AppleAppBuilder.csproj delete mode 100644 core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/CMakeLists.txt.template delete mode 100644 core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/Info.plist.template delete mode 100644 core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/main-console.m delete mode 100644 core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/main-simple.m delete mode 100644 core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/runtime.h delete mode 100644 core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/runtime.m delete mode 100644 core/mono-samples/mobile.tasks/AppleAppBuilder/Utils.cs delete mode 100644 core/mono-samples/mobile.tasks/AppleAppBuilder/Xcode.cs diff --git a/core/mono-samples/iOS/Makefile b/core/mono-samples/iOS/Makefile deleted file mode 100644 index a4049d921ce..00000000000 --- a/core/mono-samples/iOS/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -MONO_CONFIG=Debug -MONO_ARCH=x64 -USE_LLVM=True - -all: run - -TOOLS_DIR=../mobile.tasks -appbuilder: - dotnet build -c Debug $(TOOLS_DIR)/AppleAppBuilder/AppleAppBuilder.csproj - -runtimepack: - ../../../../.././build.sh Mono+Libs -os iOS -arch $(MONO_ARCH) -c $(MONO_CONFIG) - -run: clean appbuilder - dotnet publish -c $(MONO_CONFIG) /p:TargetArchitecture=$(MONO_ARCH) \ - /p:UseLLVM=$(USE_LLVM) /p:UseAotForSimulator=false - -clean: - rm -rf bin diff --git a/core/mono-samples/iOS/NuGet.config b/core/mono-samples/iOS/NuGet.config deleted file mode 100644 index 176406763c7..00000000000 --- a/core/mono-samples/iOS/NuGet.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/core/mono-samples/iOS/Program.csproj b/core/mono-samples/iOS/Program.csproj index 9ed961d8d8d..f46ed0d2c41 100644 --- a/core/mono-samples/iOS/Program.csproj +++ b/core/mono-samples/iOS/Program.csproj @@ -5,19 +5,20 @@ Exe - + + + - - - - - + + - + + $(MSBuildThisFileDirectory)$(PublishDir) + x64 iPhone 11 True diff --git a/core/mono-samples/mobile.tasks/AotCompilerTask/MonoAOTCompiler.cs b/core/mono-samples/mobile.tasks/AotCompilerTask/MonoAOTCompiler.cs deleted file mode 100644 index debd10c80f1..00000000000 --- a/core/mono-samples/mobile.tasks/AotCompilerTask/MonoAOTCompiler.cs +++ /dev/null @@ -1,255 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections.Generic; -using System.Collections.Concurrent; -using System.IO; -using System.Text; -using System.Threading.Tasks; -using Microsoft.Build.Framework; -using Microsoft.Build.Utilities; - -public class MonoAOTCompiler : Microsoft.Build.Utilities.Task -{ - /// - /// Path to AOT cross-compiler binary (mono-aot-cross) - /// - [Required] - public string CompilerBinaryPath { get; set; } = ""!; - - /// - /// Assemblies to be AOTd. They need to be in a self-contained directory. - /// - /// Metadata: - /// - AotArguments: semicolon-separated list of options that will be passed to --aot= - /// - ProcessArguments: semicolon-separated list of options that will be passed to the AOT compiler itself - /// - [Required] - public ITaskItem[] Assemblies { get; set; } = Array.Empty(); - - /// - /// Assemblies which were AOT compiled. - /// - /// Successful AOT compilation will set the following metadata on the items: - /// - AssemblerFile (when using OutputType=AsmOnly) - /// - ObjectFile (when using OutputType=Normal) - /// - AotDataFile - /// - LlvmObjectFile (if using LLVM) - /// - LlvmBitcodeFile (if using LLVM-only) - /// - [Output] - public ITaskItem[]? CompiledAssemblies { get; set; } - - /// - /// Disable parallel AOT compilation - /// - public bool DisableParallelAot { get; set; } - - /// - /// Use LLVM for AOT compilation. - /// The cross-compiler must be built with LLVM support - /// - public bool UseLLVM { get; set; } - - /// - /// Choose between 'Normal', 'Full', 'LLVMOnly'. - /// LLVMOnly means to use only LLVM for FullAOT, AOT result will be a LLVM Bitcode file (the cross-compiler must be built with LLVM support) - /// - public string Mode { get; set; } = nameof(MonoAotMode.Normal); - - /// - /// Choose between 'Normal', 'AsmOnly' - /// AsmOnly means the AOT compiler will produce .s assembly code instead of an .o object file. - /// - public string OutputType { get; set; } = nameof(MonoAotOutputType.Normal); - - /// - /// Path to the directory where LLVM binaries (opt and llc) are found. - /// It's required if UseLLVM is set - /// - public string? LLVMPath { get; set; } - - /// - /// Path to the directory where msym artifacts are stored. - /// - public string? MsymPath { get; set; } - - private ConcurrentBag compiledAssemblies = new ConcurrentBag(); - private MonoAotMode parsedAotMode; - private MonoAotOutputType parsedOutputType; - - public override bool Execute() - { - Utils.Logger = Log; - - if (string.IsNullOrEmpty(CompilerBinaryPath)) - { - throw new ArgumentException($"'{nameof(CompilerBinaryPath)}' is required.", nameof(CompilerBinaryPath)); - } - - if (!File.Exists(CompilerBinaryPath)) - { - throw new ArgumentException($"'{CompilerBinaryPath}' doesn't exist.", nameof(CompilerBinaryPath)); - } - - if (Assemblies.Length == 0) - { - throw new ArgumentException($"'{nameof(Assemblies)}' is required.", nameof(Assemblies)); - } - - if (UseLLVM && string.IsNullOrEmpty(LLVMPath)) - { - // prevent using some random llc/opt from PATH (installed with clang) - throw new ArgumentException($"'{nameof(LLVMPath)}' is required when '{nameof(UseLLVM)}' is true.", nameof(LLVMPath)); - } - - switch (Mode) - { - case "Normal": parsedAotMode = MonoAotMode.Normal; break; - case "Full": parsedAotMode = MonoAotMode.Full; break; - case "LLVMOnly": parsedAotMode = MonoAotMode.LLVMOnly; break; - default: - throw new ArgumentException($"'{nameof(Mode)}' must be one of: '{nameof(MonoAotMode.Normal)}', '{nameof(MonoAotMode.Full)}', '{nameof(MonoAotMode.LLVMOnly)}'. Received: '{Mode}'.", nameof(Mode)); - } - - switch (OutputType) - { - case "Normal": parsedOutputType = MonoAotOutputType.Normal; break; - case "AsmOnly": parsedOutputType = MonoAotOutputType.AsmOnly; break; - default: - throw new ArgumentException($"'{nameof(OutputType)}' must be one of: '{nameof(MonoAotOutputType.Normal)}', '{nameof(MonoAotOutputType.AsmOnly)}'. Received: '{OutputType}'.", nameof(OutputType)); - } - - if (parsedAotMode == MonoAotMode.LLVMOnly && !UseLLVM) - { - throw new ArgumentException($"'{nameof(UseLLVM)}' must be true when '{nameof(Mode)}' is {nameof(MonoAotMode.LLVMOnly)}.", nameof(UseLLVM)); - } - - Parallel.ForEach(Assemblies, - new ParallelOptions { MaxDegreeOfParallelism = DisableParallelAot ? 1 : Environment.ProcessorCount }, - assemblyItem => PrecompileLibrary (assemblyItem)); - - CompiledAssemblies = compiledAssemblies.ToArray(); - - return true; - } - - private void PrecompileLibrary(ITaskItem assemblyItem) - { - string assembly = assemblyItem.ItemSpec; - string directory = Path.GetDirectoryName(assembly)!; - var aotAssembly = new TaskItem(assembly); - var aotArgs = new List(); - var processArgs = new List(); - - var a = assemblyItem.GetMetadata("AotArguments"); - if (a != null) - { - aotArgs.AddRange(a.Split(";", StringSplitOptions.RemoveEmptyEntries)); - } - - var p = assemblyItem.GetMetadata("ProcessArguments"); - if (p != null) - { - processArgs.AddRange(p.Split(";", StringSplitOptions.RemoveEmptyEntries)); - } - - Utils.LogInfo($"[AOT] {assembly}"); - - processArgs.Add("--debug"); - - // add LLVM options - if (UseLLVM) - { - processArgs.Add("--llvm"); - - aotArgs.Add($"nodebug"); // can't use debug symbols with LLVM - aotArgs.Add($"llvm-path={LLVMPath}"); - } - else - { - processArgs.Add("--nollvm"); - } - - // compute output mode and file names - if (parsedAotMode == MonoAotMode.LLVMOnly) - { - aotArgs.Add("llvmonly"); - - string llvmBitcodeFile = Path.ChangeExtension(assembly, ".dll.bc"); - aotArgs.Add($"outfile={llvmBitcodeFile}"); - aotAssembly.SetMetadata("LlvmBitcodeFile", llvmBitcodeFile); - } - else - { - if (parsedAotMode == MonoAotMode.Full) - { - aotArgs.Add("full"); - } - - if (parsedOutputType == MonoAotOutputType.AsmOnly) - { - aotArgs.Add("asmonly"); - - string assemblerFile = Path.ChangeExtension(assembly, ".dll.s"); - aotArgs.Add($"outfile={assemblerFile}"); - aotAssembly.SetMetadata("AssemblerFile", assemblerFile); - } - else - { - string objectFile = Path.ChangeExtension(assembly, ".dll.o"); - aotArgs.Add($"outfile={objectFile}"); - aotAssembly.SetMetadata("ObjectFile", objectFile); - } - - if (UseLLVM) - { - string llvmObjectFile = Path.ChangeExtension(assembly, ".dll-llvm.o"); - aotArgs.Add($"llvm-outfile={llvmObjectFile}"); - aotAssembly.SetMetadata("LlvmObjectFile", llvmObjectFile); - } - } - - // pass msym-dir if specified - if (MsymPath != null) - { - aotArgs.Add($"msym-dir={MsymPath}"); - } - - string aotDataFile = Path.ChangeExtension(assembly, ".aotdata"); - aotArgs.Add($"data-outfile={aotDataFile}"); - aotAssembly.SetMetadata("AotDataFile", aotDataFile); - - // we need to quote the entire --aot arguments here to make sure it is parsed - // on Windows as one argument. Otherwise it will be split up into multiple - // values, which wont work. - processArgs.Add($"\"--aot={string.Join(",", aotArgs)}\""); - - processArgs.Add(assembly); - - var envVariables = new Dictionary - { - {"MONO_PATH", directory}, - {"MONO_ENV_OPTIONS", string.Empty} // we do not want options to be provided out of band to the cross compilers - }; - - // run the AOT compiler - Utils.RunProcess(CompilerBinaryPath, string.Join(" ", processArgs), envVariables, directory); - - compiledAssemblies.Add(aotAssembly); - } -} - -public enum MonoAotMode -{ - Normal, - Full, - LLVMOnly, -} - -public enum MonoAotOutputType -{ - Normal, - AsmOnly, -} diff --git a/core/mono-samples/mobile.tasks/AotCompilerTask/MonoAOTCompiler.csproj b/core/mono-samples/mobile.tasks/AotCompilerTask/MonoAOTCompiler.csproj deleted file mode 100644 index ab121a31019..00000000000 --- a/core/mono-samples/mobile.tasks/AotCompilerTask/MonoAOTCompiler.csproj +++ /dev/null @@ -1,25 +0,0 @@ - - - $(NetCoreAppCurrent) - Library - true - false - enable - $(NoWarn),CA1050 - - - - - - - - - - - - - - PreserveNewest - - - diff --git a/core/mono-samples/mobile.tasks/AotCompilerTask/MonoAOTCompiler.props b/core/mono-samples/mobile.tasks/AotCompilerTask/MonoAOTCompiler.props deleted file mode 100644 index 6824a7fc1c6..00000000000 --- a/core/mono-samples/mobile.tasks/AotCompilerTask/MonoAOTCompiler.props +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/core/mono-samples/mobile.tasks/AotCompilerTask/Utils.cs b/core/mono-samples/mobile.tasks/AotCompilerTask/Utils.cs deleted file mode 100644 index a7c23d4132a..00000000000 --- a/core/mono-samples/mobile.tasks/AotCompilerTask/Utils.cs +++ /dev/null @@ -1,87 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -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 RunProcess( - string path, - string args = "", - IDictionary? 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 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/core/mono-samples/mobile.tasks/AppleAppBuilder/AppleAppBuilder.cs b/core/mono-samples/mobile.tasks/AppleAppBuilder/AppleAppBuilder.cs deleted file mode 100644 index 744b2960e9d..00000000000 --- a/core/mono-samples/mobile.tasks/AppleAppBuilder/AppleAppBuilder.cs +++ /dev/null @@ -1,238 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Text; -using System.Linq; -using Microsoft.Build.Framework; -using Microsoft.Build.Utilities; - -public class AppleAppBuilderTask : Task -{ - /// - /// ProjectName is used as an app name, bundleId and xcode project name - /// - [Required] - public string ProjectName { get; set; } = ""!; - - /// - /// Target directory with *dll and other content to be AOT'd and/or bundled - /// - [Required] - public string AppDir { get; set; } = ""!; - - /// - /// Path to Mono public headers (*.h) - /// - [Required] - public string MonoRuntimeHeaders { get; set; } = ""!; - - /// - /// This library will be used as an entry-point (e.g. TestRunner.dll) - /// - [Required] - public string MainLibraryFileName { get; set; } = ""!; - - /// - /// List of paths to assemblies to be included in the app. For AOT builds the 'ObjectFile' metadata key needs to point to the object file. - /// - [Required] - public ITaskItem[] Assemblies { get; set; } = Array.Empty(); - - /// - /// Path to store build artifacts - /// - public string? OutputDirectory { get; set; } - - /// - /// Produce optimized binaries and use 'Release' config in xcode - /// - public bool Optimized { get; set; } - - /// - /// Target arch, can be "arm64" (device) or "x64" (simulator) at the moment - /// - [Required] - public string Arch { get; set; } = ""!; - - /// - /// DEVELOPER_TEAM provisioning, needed for arm64 builds. - /// - public string? DevTeamProvisioning { get; set; } - - /// - /// Build *.app bundle (using XCode for now) - /// - public bool BuildAppBundle { get; set; } - - /// - /// Generate xcode project - /// - public bool GenerateXcodeProject { get; set; } - - /// - /// Files to be ignored in AppDir - /// - public ITaskItem[]? ExcludeFromAppDir { get; set; } - - /// - /// Path to a custom main.m with custom UI - /// A default one is used if it's not set - /// - public string? NativeMainSource { get; set; } - - /// - /// Use Console-style native UI template - /// (use NativeMainSource to override) - /// - public bool UseConsoleUITemplate { get; set; } - - /// - /// Path to *.app bundle - /// - [Output] - public string AppBundlePath { get; set; } = ""!; - - /// - /// Prefer FullAOT mode for Simulator over JIT - /// - public bool UseAotForSimulator { get; set; } - - /// - /// Path to xcode project - /// - [Output] - public string XcodeProjectPath { get; set; } = ""!; - - public override bool Execute() - { - Utils.Logger = Log; - bool isDevice = Arch.Equals("arm64", StringComparison.InvariantCultureIgnoreCase); - - if (!File.Exists(Path.Combine(AppDir, MainLibraryFileName))) - { - throw new ArgumentException($"MainLibraryFileName='{MainLibraryFileName}' was not found in AppDir='{AppDir}'"); - } - - if (ProjectName.Contains(" ")) - { - throw new ArgumentException($"ProjectName='{ProjectName}' should not contain spaces"); - } - - string[] excludes = Array.Empty(); - if (ExcludeFromAppDir != null) - { - excludes = ExcludeFromAppDir - .Where(i => !string.IsNullOrEmpty(i.ItemSpec)) - .Select(i => i.ItemSpec) - .ToArray(); - } - - string binDir = Path.Combine(AppDir, $"bin-{ProjectName}-{Arch}"); - if (!string.IsNullOrEmpty(OutputDirectory)) - { - binDir = OutputDirectory; - } - Directory.CreateDirectory(binDir); - - var assemblerFiles = new List(); - foreach (ITaskItem file in Assemblies) - { - // use AOT files if available - var obj = file.GetMetadata("AssemblerFile"); - if (!string.IsNullOrEmpty(obj)) - { - assemblerFiles.Add(obj); - } - } - - if ((isDevice || UseAotForSimulator) && !assemblerFiles.Any()) - { - throw new InvalidOperationException("Need list of AOT files for device builds."); - } - - // generate modules.m - GenerateLinkAllFile( - assemblerFiles, - Path.Combine(binDir, "modules.m")); - - if (GenerateXcodeProject) - { - XcodeProjectPath = Xcode.GenerateXCode(ProjectName, MainLibraryFileName, assemblerFiles, - AppDir, binDir, MonoRuntimeHeaders, !isDevice, UseConsoleUITemplate, UseAotForSimulator, Optimized, 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); - } - } - } - - return true; - } - - private static void GenerateLinkAllFile(IEnumerable asmFiles, 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 ") - .AppendLine("#include ") - .AppendLine() - .AppendLine("#if TARGET_OS_IPHONE && (!TARGET_IPHONE_SIMULATOR || USE_AOT_FOR_SIMULATOR)") - .AppendLine(); - - var lsUsage = new StringBuilder(); - lsUsage - .AppendLine("void mono_ios_register_modules (void)") - .AppendLine("{"); - foreach (string asmFile in asmFiles) - { - string symbol = "mono_aot_module_" + - Path.GetFileName(asmFile) - .Replace(".dll.s", "") - .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/core/mono-samples/mobile.tasks/AppleAppBuilder/AppleAppBuilder.csproj b/core/mono-samples/mobile.tasks/AppleAppBuilder/AppleAppBuilder.csproj deleted file mode 100644 index 61bf42d2995..00000000000 --- a/core/mono-samples/mobile.tasks/AppleAppBuilder/AppleAppBuilder.csproj +++ /dev/null @@ -1,24 +0,0 @@ - - - net5.0 - Library - true - false - enable - $(NoWarn),CA1050 - - - - - - - - - - - - - - - - diff --git a/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/CMakeLists.txt.template b/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/CMakeLists.txt.template deleted file mode 100644 index ecd3d6c1e61..00000000000 --- a/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/CMakeLists.txt.template +++ /dev/null @@ -1,44 +0,0 @@ -cmake_minimum_required(VERSION 3.16) - -project(%ProjectName%) -enable_language(OBJC ASM) - -set(APP_RESOURCES -%AppResources% -) - -add_executable( - %ProjectName% - %MainSource% - runtime.h - runtime.m - modules.m - ${APP_RESOURCES} -) - -%AotSources% - -%Defines% - -include_directories("%MonoInclude%") - -set_target_properties(%ProjectName% PROPERTIES - MACOSX_BUNDLE TRUE - MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist - 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% -) diff --git a/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/Info.plist.template b/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/Info.plist.template deleted file mode 100644 index c8c0f53f160..00000000000 --- a/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/Info.plist.template +++ /dev/null @@ -1,37 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en-US - CFBundleExecutable - %BundleIdentifier% - CFBundleIdentifier - net.dot.%BundleIdentifier% - CFBundleName - %BundleIdentifier% - CFBundleInfoDictionaryVersion - 6.0 - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - LSRequiresIPhoneOS - - UIApplicationSceneManifest - - UIApplicationSupportsMultipleScenes - - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - - - diff --git a/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/main-console.m b/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/main-console.m deleted file mode 100644 index 20b9f8714d3..00000000000 --- a/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/main-console.m +++ /dev/null @@ -1,93 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#import -#import "runtime.h" -#include - -@interface ViewController : UIViewController -@end - -@interface AppDelegate : UIResponder -@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 - 2.0, applicationFrame.size.height - 50.0)]; - 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 - 10.0, 50)]; - summaryLabel.textColor = [UIColor whiteColor]; - summaryLabel.font = [UIFont boldSystemFontOfSize: 12]; - summaryLabel.numberOfLines = 2; - summaryLabel.textAlignment = NSTextAlignmentLeft; -#ifdef TARGET_OS_IPHONE && (!TARGET_IPHONE_SIMULATOR || USE_AOT_FOR_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: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:value]; - dispatch_async(dispatch_get_main_queue(), ^{ - logLabel.text = [logLabel.text stringByAppendingString:nsstr]; - CGRect caretRect = [logLabel caretRectForPosition:logLabel.endOfDocument]; - [logLabel scrollRectToVisible:caretRect animated:NO]; - [logLabel setScrollEnabled:NO]; - [logLabel setScrollEnabled:YES]; - }); -} - -int main(int argc, char * argv[]) { - @autoreleasepool { - return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); - } -} diff --git a/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/main-simple.m b/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/main-simple.m deleted file mode 100644 index e05868ffcd4..00000000000 --- a/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/main-simple.m +++ /dev/null @@ -1,81 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#import -#import "runtime.h" - -@interface ViewController : UIViewController -@end - -@interface AppDelegate : UIResponder -@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/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/runtime.h b/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/runtime.h deleted file mode 100644 index 08fa626eba1..00000000000 --- a/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/runtime.h +++ /dev/null @@ -1,9 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#ifndef runtime_h -#define runtime_h - -void mono_ios_runtime_init (void); - -#endif /* runtime_h */ diff --git a/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/runtime.m b/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/runtime.m deleted file mode 100644 index 02c0070fb6b..00000000000 --- a/core/mono-samples/mobile.tasks/AppleAppBuilder/Templates/runtime.m +++ /dev/null @@ -1,269 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#import -#include -#include -#include -#include -#include -#include -#include -#include -#include -#import -#include -#include - -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 - -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]); - - return bundle_path; -} - -static unsigned char * -load_aot_data (MonoAssembly *assembly, int size, void *user_data, void **out_handle) -{ - *out_handle = NULL; - - char path [1024]; - int res; - - MonoAssemblyName *assembly_name = mono_assembly_get_name (assembly); - const char *aname = mono_assembly_name_get_name (assembly_name); - const char *bundle = get_bundle_path (); - - os_log_info (OS_LOG_DEFAULT, "Looking for aot data for assembly '%s'.", aname); - res = snprintf (path, sizeof (path) - 1, "%s/%s.aotdata", bundle, aname); - assert (res > 0); - - int fd = open (path, O_RDONLY); - if (fd < 0) { - os_log_info (OS_LOG_DEFAULT, "Could not load the aot data for %s from %s: %s\n", aname, path, strerror (errno)); - return NULL; - } - - void *ptr = mmap (NULL, size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0); - if (ptr == MAP_FAILED) { - os_log_info (OS_LOG_DEFAULT, "Could not map the aot file for %s: %s\n", aname, strerror (errno)); - close (fd); - return NULL; - } - - close (fd); - os_log_info (OS_LOG_DEFAULT, "Loaded aot data for %s.\n", aname); - *out_handle = ptr; - return (unsigned char *) ptr; -} - -static void -free_aot_data (MonoAssembly *assembly, int size, void *user_data, void *handle) -{ - munmap (handle, size); -} - -static MonoAssembly* -load_assembly (const char *name, const char *culture) -{ - const char *bundle = get_bundle_path (); - char filename [1024]; - char path [1024]; - int res; - - os_log_info (OS_LOG_DEFAULT, "assembly_preload_hook: %{public}s %{public}s %{public}s\n", name, culture, bundle); - - int len = strlen (name); - int has_extension = len > 3 && name [len - 4] == '.' && (!strcmp ("exe", name + (len - 3)) || !strcmp ("dll", name + (len - 3))); - - // add extensions if required. - strlcpy (filename, name, sizeof (filename)); - if (!has_extension) { - strlcat (filename, ".dll", sizeof (filename)); - } - - if (culture && strcmp (culture, "")) - res = snprintf (path, sizeof (path) - 1, "%s/%s/%s", bundle, culture, filename); - 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); - assert (assembly); - return assembly; - } - return NULL; -} - -static MonoAssembly* -assembly_preload_hook (MonoAssemblyName *aname, char **assemblies_path, void* user_data) -{ - const char *name = mono_assembly_name_get_name (aname); - const char *culture = mono_assembly_name_get_culture (aname); - return load_assembly (name, culture); -} - -char * -strdup_printf (const char *msg, ...) -{ - va_list args; - char *formatted = NULL; - va_start (args, msg); - vasprintf (&formatted, msg, args); - va_end (args); - return formatted; -} - -static MonoObject * -fetch_exception_property (MonoObject *obj, const char *name, bool is_virtual) -{ - MonoMethod *get = NULL; - MonoMethod *get_virt = NULL; - MonoObject *exc = NULL; - - get = mono_class_get_method_from_name (mono_get_exception_class (), name, 0); - if (get) { - if (is_virtual) { - get_virt = mono_object_get_virtual_method (obj, get); - if (get_virt) - get = get_virt; - } - - return (MonoObject *) mono_runtime_invoke (get, obj, NULL, &exc); - } else { - printf ("Could not find the property System.Exception.%s", name); - } - - return NULL; -} - -static char * -fetch_exception_property_string (MonoObject *obj, const char *name, bool is_virtual) -{ - MonoString *str = (MonoString *) fetch_exception_property (obj, name, is_virtual); - return str ? mono_string_to_utf8 (str) : NULL; -} - -void -unhandled_exception_handler (MonoObject *exc, void *user_data) -{ - NSMutableString *msg = [[NSMutableString alloc] init]; - - MonoClass *type = mono_object_get_class (exc); - char *type_name = strdup_printf ("%s.%s", mono_class_get_namespace (type), mono_class_get_name (type)); - char *trace = fetch_exception_property_string (exc, "get_StackTrace", true); - char *message = fetch_exception_property_string (exc, "get_Message", true); - - [msg appendString:@"Unhandled managed exceptions:\n"]; - [msg appendFormat: @"%s (%s)\n%s\n", message, type_name, trace ? trace : ""]; - - free (trace); - free (message); - free (type_name); - - os_log_info (OS_LOG_DEFAULT, "%@", msg); - os_log_info (OS_LOG_DEFAULT, "Exit code: %d.", 1); - exit (1); -} - -void -log_callback (const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data) -{ - os_log_info (OS_LOG_DEFAULT, "(%s %s) %s", log_domain, log_level, message); - if (fatal) { - os_log_info (OS_LOG_DEFAULT, "Exit code: %d.", 1); - exit (1); - } -} - -static void -register_dllmap (void) -{ -//%DllMap% -} - -#if TARGET_OS_IPHONE && (!TARGET_IPHONE_SIMULATOR || USE_AOT_FOR_SIMULATOR) -void mono_jit_set_aot_mode (MonoAotMode mode); -void mono_ios_register_modules (void); -#endif - -void -mono_ios_runtime_init (void) -{ - // for now, only Invariant Mode is supported (FIXME: integrate ICU) - setenv ("DOTNET_SYSTEM_GLOBALIZATION_INVARIANT", "1", TRUE); - // uncomment for debug output: - // - // setenv ("MONO_LOG_LEVEL", "debug", TRUE); - // setenv ("MONO_LOG_MASK", "all", TRUE); - - 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]; - managed_argv[argi] = [arg UTF8String]; - } - - bool wait_for_debugger = FALSE; - - const char* bundle = get_bundle_path (); - chdir (bundle); - - // TODO: set TRUSTED_PLATFORM_ASSEMBLIES, APP_PATHS and NATIVE_DLL_SEARCH_DIRECTORIES - monovm_initialize(0, NULL, NULL); - -#if TARGET_OS_IPHONE && (!TARGET_IPHONE_SIMULATOR || USE_AOT_FOR_SIMULATOR) - register_dllmap (); - // register modules - mono_ios_register_modules (); - 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); - mono_install_unhandled_exception_hook (unhandled_exception_handler, NULL); - mono_trace_set_log_handler (log_callback, NULL); - mono_set_signal_chaining (TRUE); - mono_set_crash_chaining (TRUE); - - if (wait_for_debugger) { - char* options[] = { "--debugger-agent=transport=dt_socket,server=y,address=0.0.0.0:55555" }; - mono_jit_parse_options (1, options); - } - mono_jit_init_version ("dotnet.ios", "mobile"); - -#if TARGET_OS_IPHONE && (!TARGET_IPHONE_SIMULATOR || USE_AOT_FOR_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, argi, managed_argv); - // Print this so apps parsing logs can detect when we exited - os_log_info (OS_LOG_DEFAULT, "Exit code: %d.", res); - - exit (res); -} diff --git a/core/mono-samples/mobile.tasks/AppleAppBuilder/Utils.cs b/core/mono-samples/mobile.tasks/AppleAppBuilder/Utils.cs deleted file mode 100644 index 83304bd393c..00000000000 --- a/core/mono-samples/mobile.tasks/AppleAppBuilder/Utils.cs +++ /dev/null @@ -1,95 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -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? 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 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/core/mono-samples/mobile.tasks/AppleAppBuilder/Xcode.cs b/core/mono-samples/mobile.tasks/AppleAppBuilder/Xcode.cs deleted file mode 100644 index 1d67b35f349..00000000000 --- a/core/mono-samples/mobile.tasks/AppleAppBuilder/Xcode.cs +++ /dev/null @@ -1,169 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections.Generic; -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, - IEnumerable asmFiles, - string workspace, - string binDir, - string monoInclude, - bool preferDylibs, - bool useConsoleUiTemplate, - bool useAotForSimulator, - bool stripDebugSymbols, - string? nativeMainSource = null) - { - // bundle everything as resources excluding native files - var excludes = new List { ".dll.o", ".dll.s", ".dwarf", ".m", ".h", ".a", ".bc", "libmonosgen-2.0.dylib" }; - if (stripDebugSymbols) - { - excludes.Add(".pdb"); - } - - 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[] dylibs = Directory.GetFiles(workspace, "*.dylib"); - string toLink = ""; - foreach (string lib in Directory.GetFiles(workspace, "*.a")) - { - string libName = Path.GetFileNameWithoutExtension(lib); - // 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 (!preferDylibs || !dylibExists) - { - // these libraries are pinvoked - // -force_load will be removed once we enable direct-pinvokes for AOT - toLink += $" \"-force_load {lib}\"{Environment.NewLine}"; - } - } - - string aotSources = ""; - foreach (string asm in asmFiles) - { - // these libraries are linked via modules.m - var name = Path.GetFileNameWithoutExtension(asm); - aotSources += $"add_library({name} OBJECT {asm}){Environment.NewLine}"; - toLink += $" {name}{Environment.NewLine}"; - } - - cmakeLists = cmakeLists.Replace("%NativeLibrariesToLink%", toLink); - cmakeLists = cmakeLists.Replace("%AotSources%", aotSources); - cmakeLists = cmakeLists.Replace("%Defines%", - useAotForSimulator ? "add_definitions(-DUSE_AOT_FOR_SIMULATOR=1)" : ""); - - string plist = Utils.GetEmbeddedResource("Info.plist.template") - .Replace("%BundleIdentifier%", projectName); - - File.WriteAllText(Path.Combine(binDir, "Info.plist"), 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" - 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);"); - - // 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("%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)); - - string appPath = Path.Combine(Path.GetDirectoryName(xcodePrjPath)!, config + "-" + sdk, - Path.GetFileNameWithoutExtension(xcodePrjPath) + ".app"); - - long appSize = new DirectoryInfo(appPath) - .EnumerateFiles("*", SearchOption.AllDirectories) - .Sum(file => file.Length); - - Utils.LogInfo($"\nAPP size: {(appSize / 1000_000.0):0.#} Mb.\n"); - - return appPath; - } -} From a59c56dfd8e197096714ec9d8197387370799d01 Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Thu, 1 Oct 2020 12:01:24 -0400 Subject: [PATCH 13/41] Remove Debugging target --- core/mono-samples/iOS/Program.csproj | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/core/mono-samples/iOS/Program.csproj b/core/mono-samples/iOS/Program.csproj index f46ed0d2c41..114a423a4da 100644 --- a/core/mono-samples/iOS/Program.csproj +++ b/core/mono-samples/iOS/Program.csproj @@ -9,12 +9,9 @@ - - - - + $(MSBuildThisFileDirectory)$(PublishDir) From 93017d7177386462101153dd7fce767fb1b0ab4a Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Mon, 5 Oct 2020 10:39:24 -0400 Subject: [PATCH 14/41] Add iOS sample nuget package --- core/mono-samples/iOS/NuGet.config | 10 ++++++++++ core/mono-samples/iOS/Program.csproj | 4 ++-- 2 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 core/mono-samples/iOS/NuGet.config diff --git a/core/mono-samples/iOS/NuGet.config b/core/mono-samples/iOS/NuGet.config new file mode 100644 index 00000000000..58d680be9d4 --- /dev/null +++ b/core/mono-samples/iOS/NuGet.config @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/core/mono-samples/iOS/Program.csproj b/core/mono-samples/iOS/Program.csproj index 114a423a4da..099475cfa0e 100644 --- a/core/mono-samples/iOS/Program.csproj +++ b/core/mono-samples/iOS/Program.csproj @@ -6,11 +6,11 @@ - + + AssemblyFile="$(NuGetPackageRoot)microsoft.net.runtime.ios.sample.mono/6.0.0-dev/tools/net5.0/AppleAppBuilder.dll" /> From 2bf168f9b921b903abbe1428b8d4540d963f590a Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Tue, 13 Oct 2020 12:46:16 -0400 Subject: [PATCH 15/41] Add custom UI file --- core/mono-samples/iOS/main.m | 81 ++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 core/mono-samples/iOS/main.m diff --git a/core/mono-samples/iOS/main.m b/core/mono-samples/iOS/main.m new file mode 100644 index 00000000000..e05868ffcd4 --- /dev/null +++ b/core/mono-samples/iOS/main.m @@ -0,0 +1,81 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#import +#import "runtime.h" + +@interface ViewController : UIViewController +@end + +@interface AppDelegate : UIResponder +@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])); + } +} From dbfda592b289ae9e3ec031672c537ad4f5314954 Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Tue, 13 Oct 2020 12:46:50 -0400 Subject: [PATCH 16/41] Clean up project file --- core/mono-samples/iOS/Program.csproj | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/core/mono-samples/iOS/Program.csproj b/core/mono-samples/iOS/Program.csproj index 099475cfa0e..9e984604e9c 100644 --- a/core/mono-samples/iOS/Program.csproj +++ b/core/mono-samples/iOS/Program.csproj @@ -26,19 +26,16 @@ @@ -46,11 +43,13 @@ - + + + \ No newline at end of file From b1805b3b486ed1f013616516f9392c38f873513b Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Wed, 14 Oct 2020 13:23:21 -0400 Subject: [PATCH 17/41] Update iOS sample Auto Layout --- core/mono-samples/iOS/Program.cs | 28 +++-- core/mono-samples/iOS/main.m | 172 ++++++++++++++++++++++++++++--- 2 files changed, 179 insertions(+), 21 deletions(-) diff --git a/core/mono-samples/iOS/Program.cs b/core/mono-samples/iOS/Program.cs index 9769ded207e..443bd345fb1 100644 --- a/core/mono-samples/iOS/Program.cs +++ b/core/mono-samples/iOS/Program.cs @@ -19,27 +19,41 @@ public static class Program [DllImport("__Internal")] private extern static void ios_set_text(string value); + // [DllImport("__Internal")] + // private extern static void ios_greet_name(string value); + [DllImport("__Internal")] - private extern static void ios_register_button_click(Action action); + private extern static void ios_register_counter_increment(Action action); + + // [DllImport("__Internal")] + // private extern static void ios_register_name_greet(Action action); - private static Action buttonClickHandler = null; + private static Action incrementHandler = null; + // private static Action nameHandler = null; - private static int counter = 0; + private static int counter = 1; // Called by native code, see main.m [MonoPInvokeCallback(typeof(Action))] - private static void OnButtonClick() + private static void IncrementCounter() { - ios_set_text("OnButtonClick! #" + counter++); + ios_set_text("Clicked " + counter++ + " times!"); } + // [MonoPInvokeCallback(typeof(Action))] + // private static void GreetName() + // { + // ios_greet_name("Mitch"); + // } + public static async Task Main(string[] args) { // Register a managed callback (will be called by UIButton, see main.m) // Also, keep the handler alive so GC won't collect it. - ios_register_button_click(buttonClickHandler = OnButtonClick); + ios_register_counter_increment(incrementHandler = IncrementCounter); + // ios_register_name_greet(nameHandler = GreetName); - const string msg = "Hello World!\n.NET 5.0"; + const string msg = "Hello World!"; for (int i = 0; i < msg.Length; i++) { // a kind of an animation diff --git a/core/mono-samples/iOS/main.m b/core/mono-samples/iOS/main.m index e05868ffcd4..f23d84cc606 100644 --- a/core/mono-samples/iOS/main.m +++ b/core/mono-samples/iOS/main.m @@ -23,45 +23,179 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( @end UILabel *label; -void (*clickHandlerPtr)(void); +UILabel *counter; +UITextField *textField; +NSString *name = @"iOS"; +void (*incrementHandlerPtr)(void); @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; - label = [[UILabel alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + label = [[UILabel alloc] init]; + [label setTranslatesAutoresizingMaskIntoConstraints:NO]; label.textColor = [UIColor greenColor]; - label.font = [UIFont boldSystemFontOfSize: 30]; - label.numberOfLines = 2; + label.font = [UIFont boldSystemFontOfSize: 20]; + label.numberOfLines = 3; label.textAlignment = NSTextAlignmentCenter; - label.text = @"Hello, wire me up!\n(dllimport ios_set_text)"; + label.text = [NSString stringWithFormat:@"%@%@%@", @"Hello ", name, @"!\nRunning on mono runtime\nUsing C#"]; [self.view addSubview:label]; + [label addConstraint:[NSLayoutConstraint constraintWithItem:label + attribute:NSLayoutAttributeWidth + relatedBy:NSLayoutRelationEqual + toItem:nil + attribute:NSLayoutAttributeNotAnAttribute + multiplier:1 + constant:300]]; + [self.view addConstraint:[NSLayoutConstraint constraintWithItem:label + attribute:NSLayoutAttributeCenterX + relatedBy:NSLayoutRelationEqual + toItem:self.view + attribute:NSLayoutAttributeCenterX + multiplier:1 + constant:0]]; + + counter = [[UILabel alloc] init]; + [counter setTranslatesAutoresizingMaskIntoConstraints:NO]; + counter.textColor = [UIColor greenColor]; + counter.font = [UIFont boldSystemFontOfSize: 20]; + counter.numberOfLines = 2; + counter.textAlignment = NSTextAlignmentCenter; + counter.text = @"counter"; + [self.view addSubview:counter]; + [counter addConstraint:[NSLayoutConstraint constraintWithItem:counter + attribute:NSLayoutAttributeWidth + relatedBy:NSLayoutRelationEqual + toItem:nil + attribute:NSLayoutAttributeNotAnAttribute + multiplier:1 + constant:300]]; + [self.view addConstraint:[NSLayoutConstraint constraintWithItem:counter + attribute:NSLayoutAttributeTop + relatedBy:NSLayoutRelationEqual + toItem:label + attribute:NSLayoutAttributeBottom + multiplier:1 + constant:50]]; + [self.view addConstraint:[NSLayoutConstraint constraintWithItem:counter + attribute:NSLayoutAttributeCenterX + relatedBy:NSLayoutRelationEqual + toItem:self.view + attribute:NSLayoutAttributeCenterX + multiplier:1 + constant:0]]; 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 setTranslatesAutoresizingMaskIntoConstraints:NO]; + [button addTarget:self action:@selector(incrementCounter:) forControlEvents:UIControlEventTouchUpInside]; + [button setTitle:@"Click me" forState:UIControlStateNormal]; [button setExclusiveTouch:YES]; [self.view addSubview:button]; + [button addConstraint:[NSLayoutConstraint constraintWithItem:button + attribute:NSLayoutAttributeWidth + relatedBy:NSLayoutRelationEqual + toItem:nil + attribute:NSLayoutAttributeNotAnAttribute + multiplier:1 + constant:200]]; + [self.view addConstraint:[NSLayoutConstraint constraintWithItem:button + attribute:NSLayoutAttributeTop + relatedBy:NSLayoutRelationEqual + toItem:counter + attribute:NSLayoutAttributeBottom + multiplier:1 + constant:10]]; + [self.view addConstraint:[NSLayoutConstraint constraintWithItem:button + attribute:NSLayoutAttributeCenterX + relatedBy:NSLayoutRelationEqual + toItem:counter + attribute:NSLayoutAttributeCenterX + multiplier:1 + constant:0]]; + [self.view addConstraint:[NSLayoutConstraint constraintWithItem:button + attribute:NSLayoutAttributeCenterX + relatedBy:NSLayoutRelationEqual + toItem:self.view + attribute:NSLayoutAttributeCenterX + multiplier:1 + constant:0]]; + + textField = [[UITextField alloc] init]; + [textField setTranslatesAutoresizingMaskIntoConstraints:NO]; + textField.textColor = [UIColor greenColor]; + textField.BackgroundColor = [UIColor darkGrayColor]; + textField.font = [UIFont boldSystemFontOfSize: 15]; + textField.textAlignment = NSTextAlignmentCenter; + textField.placeholder = @"Your name"; + [self.view addSubview:textField]; + [textField addConstraint:[NSLayoutConstraint constraintWithItem:textField + attribute:NSLayoutAttributeWidth + relatedBy:NSLayoutRelationEqual + toItem:nil + attribute:NSLayoutAttributeNotAnAttribute + multiplier:1 + constant:125]]; + [self.view addConstraint:[NSLayoutConstraint constraintWithItem:textField + attribute:NSLayoutAttributeTop + relatedBy:NSLayoutRelationEqual + toItem:button + attribute:NSLayoutAttributeBottom + multiplier:1 + constant:50]]; + [self.view addConstraint:[NSLayoutConstraint constraintWithItem:textField + attribute:NSLayoutAttributeCenterX + relatedBy:NSLayoutRelationEqual + toItem:self.view + attribute:NSLayoutAttributeCenterX + multiplier:1 + constant:0]]; + + UIButton *enterName = [UIButton buttonWithType:UIButtonTypeInfoDark]; + [enterName setTranslatesAutoresizingMaskIntoConstraints:NO]; + // [enterName addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside]; + [enterName setTitle:@"Enter" forState:UIControlStateNormal]; + [enterName setExclusiveTouch:YES]; + [self.view addSubview:enterName]; + [enterName addConstraint:[NSLayoutConstraint constraintWithItem:enterName + attribute:NSLayoutAttributeWidth + relatedBy:NSLayoutRelationEqual + toItem:nil + attribute:NSLayoutAttributeNotAnAttribute + multiplier:1 + constant:200]]; + [self.view addConstraint:[NSLayoutConstraint constraintWithItem:enterName + attribute:NSLayoutAttributeTop + relatedBy:NSLayoutRelationEqual + toItem:textField + attribute:NSLayoutAttributeBottom + multiplier:1 + constant:10]]; + [self.view addConstraint:[NSLayoutConstraint constraintWithItem:enterName + attribute:NSLayoutAttributeCenterX + relatedBy:NSLayoutRelationEqual + toItem:textField + attribute:NSLayoutAttributeCenterX + multiplier:1 + constant:0]]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ mono_ios_runtime_init (); }); } --(void) buttonClicked:(UIButton*)sender +-(void) incrementCounter:(UIButton*)sender { - if (clickHandlerPtr) - clickHandlerPtr(); + if (incrementHandlerPtr) + incrementHandlerPtr(); } @end // called from C# sample void -ios_register_button_click (void* ptr) +ios_register_counter_increment (void* ptr) { - clickHandlerPtr = ptr; + incrementHandlerPtr = ptr; } // called from C# sample @@ -70,10 +204,20 @@ -(void) buttonClicked:(UIButton*)sender { NSString* nsstr = [NSString stringWithUTF8String:strdup(value)]; dispatch_async(dispatch_get_main_queue(), ^{ - label.text = nsstr; + counter.text = nsstr; }); } +// called from C# sample +// void +// ios_greet_name (const char* value) +// { +// NSString* nsstr = [NSString stringWithUTF8String:strdup(value)]; +// dispatch_async(dispatch_get_main_queue(), ^{ +// name = nsstr; +// }); +// } + int main(int argc, char * argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); From 2ad509f5cf77091c343ea1d5e7e79d9367abd313 Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Wed, 14 Oct 2020 13:44:04 -0400 Subject: [PATCH 18/41] Add action replace iOS with name --- core/mono-samples/iOS/Program.cs | 22 ++++++++++---------- core/mono-samples/iOS/main.m | 35 ++++++++++++++++++++++---------- 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/core/mono-samples/iOS/Program.cs b/core/mono-samples/iOS/Program.cs index 443bd345fb1..f81c9f19bd7 100644 --- a/core/mono-samples/iOS/Program.cs +++ b/core/mono-samples/iOS/Program.cs @@ -19,17 +19,17 @@ public static class Program [DllImport("__Internal")] private extern static void ios_set_text(string value); - // [DllImport("__Internal")] - // private extern static void ios_greet_name(string value); + [DllImport("__Internal")] + private extern static void ios_greet_name(string value); [DllImport("__Internal")] private extern static void ios_register_counter_increment(Action action); - // [DllImport("__Internal")] - // private extern static void ios_register_name_greet(Action action); + [DllImport("__Internal")] + private extern static void ios_register_name_greet(Action action); private static Action incrementHandler = null; - // private static Action nameHandler = null; + private static Action nameHandler = null; private static int counter = 1; @@ -40,18 +40,18 @@ private static void IncrementCounter() ios_set_text("Clicked " + counter++ + " times!"); } - // [MonoPInvokeCallback(typeof(Action))] - // private static void GreetName() - // { - // ios_greet_name("Mitch"); - // } + [MonoPInvokeCallback(typeof(Action))] + private static void GreetName(string name) + { + ios_greet_name(name); + } public static async Task Main(string[] args) { // Register a managed callback (will be called by UIButton, see main.m) // Also, keep the handler alive so GC won't collect it. ios_register_counter_increment(incrementHandler = IncrementCounter); - // ios_register_name_greet(nameHandler = GreetName); + ios_register_name_greet(nameHandler = GreetName); const string msg = "Hello World!"; for (int i = 0; i < msg.Length; i++) diff --git a/core/mono-samples/iOS/main.m b/core/mono-samples/iOS/main.m index f23d84cc606..ef5672ec900 100644 --- a/core/mono-samples/iOS/main.m +++ b/core/mono-samples/iOS/main.m @@ -27,6 +27,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( UITextField *textField; NSString *name = @"iOS"; void (*incrementHandlerPtr)(void); +void (*greetHandlerPtr)(NSString*); @implementation ViewController @@ -60,7 +61,7 @@ - (void)viewDidLoad { [counter setTranslatesAutoresizingMaskIntoConstraints:NO]; counter.textColor = [UIColor greenColor]; counter.font = [UIFont boldSystemFontOfSize: 20]; - counter.numberOfLines = 2; + counter.numberOfLines = 1; counter.textAlignment = NSTextAlignmentCenter; counter.text = @"counter"; [self.view addSubview:counter]; @@ -124,7 +125,7 @@ - (void)viewDidLoad { textField = [[UITextField alloc] init]; [textField setTranslatesAutoresizingMaskIntoConstraints:NO]; textField.textColor = [UIColor greenColor]; - textField.BackgroundColor = [UIColor darkGrayColor]; + textField.backgroundColor = [UIColor darkGrayColor]; textField.font = [UIFont boldSystemFontOfSize: 15]; textField.textAlignment = NSTextAlignmentCenter; textField.placeholder = @"Your name"; @@ -153,7 +154,7 @@ - (void)viewDidLoad { UIButton *enterName = [UIButton buttonWithType:UIButtonTypeInfoDark]; [enterName setTranslatesAutoresizingMaskIntoConstraints:NO]; - // [enterName addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside]; + [enterName addTarget:self action:@selector(greetName:) forControlEvents:UIControlEventTouchUpInside]; [enterName setTitle:@"Enter" forState:UIControlStateNormal]; [enterName setExclusiveTouch:YES]; [self.view addSubview:enterName]; @@ -188,6 +189,11 @@ -(void) incrementCounter:(UIButton*)sender if (incrementHandlerPtr) incrementHandlerPtr(); } +-(void) greetName:(UIButton*)sender +{ + if (greetHandlerPtr) + greetHandlerPtr(textField.text); +} @end @@ -209,14 +215,21 @@ -(void) incrementCounter:(UIButton*)sender } // called from C# sample -// void -// ios_greet_name (const char* value) -// { -// NSString* nsstr = [NSString stringWithUTF8String:strdup(value)]; -// dispatch_async(dispatch_get_main_queue(), ^{ -// name = nsstr; -// }); -// } +void +ios_register_name_greet (void* ptr) +{ + greetHandlerPtr = ptr; +} + +// called from C# sample +void +ios_greet_name (const char* value) +{ + NSString* nsstr = [NSString stringWithUTF8String:strdup(value)]; + dispatch_async(dispatch_get_main_queue(), ^{ + name = nsstr; + }); +} int main(int argc, char * argv[]) { @autoreleasepool { From 17e9c1cb3e68a53d2775285a1ce866ac399704aa Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Wed, 14 Oct 2020 16:52:02 -0400 Subject: [PATCH 19/41] Touch up string replacement --- core/mono-samples/iOS/main.m | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/core/mono-samples/iOS/main.m b/core/mono-samples/iOS/main.m index ef5672ec900..ee27654f69f 100644 --- a/core/mono-samples/iOS/main.m +++ b/core/mono-samples/iOS/main.m @@ -25,7 +25,6 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( UILabel *label; UILabel *counter; UITextField *textField; -NSString *name = @"iOS"; void (*incrementHandlerPtr)(void); void (*greetHandlerPtr)(NSString*); @@ -40,7 +39,7 @@ - (void)viewDidLoad { label.font = [UIFont boldSystemFontOfSize: 20]; label.numberOfLines = 3; label.textAlignment = NSTextAlignmentCenter; - label.text = [NSString stringWithFormat:@"%@%@%@", @"Hello ", name, @"!\nRunning on mono runtime\nUsing C#"]; + label.text = @"Hello iOS!\nRunning on mono runtime\nUsing C#"; [self.view addSubview:label]; [label addConstraint:[NSLayoutConstraint constraintWithItem:label attribute:NSLayoutAttributeWidth @@ -192,7 +191,7 @@ -(void) incrementCounter:(UIButton*)sender -(void) greetName:(UIButton*)sender { if (greetHandlerPtr) - greetHandlerPtr(textField.text); + greetHandlerPtr(strdup ([textField.text UTF8String])); } @end @@ -227,7 +226,7 @@ -(void) greetName:(UIButton*)sender { NSString* nsstr = [NSString stringWithUTF8String:strdup(value)]; dispatch_async(dispatch_get_main_queue(), ^{ - name = nsstr; + label.text = [NSString stringWithFormat:@"%@%@%@", @"Hello ", nsstr, @"!\nRunning on mono runtime\nUsing C#"]; }); } From 9dbdfd7accdddca567276064653ad0584d132557 Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Thu, 15 Oct 2020 15:04:55 -0400 Subject: [PATCH 20/41] Add mono readme and iOS specific readme --- core/mono-samples/README.md | 3 +++ core/mono-samples/iOS/README.md | 25 +++++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 core/mono-samples/README.md create mode 100644 core/mono-samples/iOS/README.md diff --git a/core/mono-samples/README.md b/core/mono-samples/README.md new file mode 100644 index 00000000000..c5fe80fe54a --- /dev/null +++ b/core/mono-samples/README.md @@ -0,0 +1,3 @@ +# Sample .NET mono runtime + +This folder contains sample code demonstrating how to build mobile (iOS, Android, Browser WebAssembly) apps with the mono runtime. The requirements for each sample can be found within the corresponding folder, and each sample can be ran using `dotnet publish`. diff --git a/core/mono-samples/iOS/README.md b/core/mono-samples/iOS/README.md new file mode 100644 index 00000000000..83e7f637ccc --- /dev/null +++ b/core/mono-samples/iOS/README.md @@ -0,0 +1,25 @@ +--- +languages: +- c# +products: +- dotnet +- iOS +- mono runtime +page_type: sample +name: "iOS Sample: Simple greeting and counter (C#)" +description: "An iOS application that contains an example of embedding the mono runtime to invoke unmanaged code with C#." +--- + +# iOS Sample: Simple greeting and counter (C#) + +In this sample, the mono runtime is used to invoke objective-c unmanaged code (main.m) from the C# managed side (Program.cs) and vice versa. With the sample running, you can enter your name and click the corresponding button to modify the greeting message as well as clicking a button to increment a counter. + +NOTE: The purpose of this sample is to demonstrate the concept of building an iOS application on top of the mono runtime. + +## Requirements + +To run the sample for iOS you will need a recent version of XCode installed (e.g. 11.3 or higher). + +## Building the sample + +To build the sample from the command line, run `dotnet publish`. From 49691c41891269d3884275e172fea003bf99bc77 Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Mon, 19 Oct 2020 11:49:49 -0400 Subject: [PATCH 21/41] Update assembly target version --- core/mono-samples/iOS/Program.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/mono-samples/iOS/Program.csproj b/core/mono-samples/iOS/Program.csproj index 9e984604e9c..bad157bb6e4 100644 --- a/core/mono-samples/iOS/Program.csproj +++ b/core/mono-samples/iOS/Program.csproj @@ -10,7 +10,7 @@ + AssemblyFile="$(NuGetPackageRoot)microsoft.net.runtime.ios.sample.mono/6.0.0-dev/tools/net6.0/AppleAppBuilder.dll" /> From 93683dd2d4092a1b1767530a9d1b07325b4eb831 Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Mon, 19 Oct 2020 11:50:12 -0400 Subject: [PATCH 22/41] Clean up README --- core/mono-samples/iOS/README.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/core/mono-samples/iOS/README.md b/core/mono-samples/iOS/README.md index 83e7f637ccc..e3d5f66294d 100644 --- a/core/mono-samples/iOS/README.md +++ b/core/mono-samples/iOS/README.md @@ -1,25 +1,28 @@ --- languages: -- c# +- csharp products: -- dotnet -- iOS -- mono runtime +- dotnet-core page_type: sample name: "iOS Sample: Simple greeting and counter (C#)" description: "An iOS application that contains an example of embedding the mono runtime to invoke unmanaged code with C#." +urlFragment: "mono-ios-csharp" --- # iOS Sample: Simple greeting and counter (C#) In this sample, the mono runtime is used to invoke objective-c unmanaged code (main.m) from the C# managed side (Program.cs) and vice versa. With the sample running, you can enter your name and click the corresponding button to modify the greeting message as well as clicking a button to increment a counter. -NOTE: The purpose of this sample is to demonstrate the concept of building an iOS application on top of the mono runtime. +NOTE: The purpose of this sample is to demonstrate the concept of building an iOS application on top of the mono runtime. The mono runtime headers should be supplied through the build process. -## Requirements +## Sample Prerequisites -To run the sample for iOS you will need a recent version of XCode installed (e.g. 11.3 or higher). +To run the sample for iOS, Xcode and an iOS simulator is needed. +- Xcode: Any version should work with this sample (download Xcode at https://developer.apple.com/xcode/) +- iOS simulator: Minimal version iOS 8.0 + +NOTE: Modify `IosSimulator` under target `BuildAppBundle` from `iPhone 11` to your simulator's device name. ## Building the sample -To build the sample from the command line, run `dotnet publish`. +The source code includes an MSBuild project file for C# (a _.csproj_ file) that targets .NET 5.0. After downloading the _.zip_ file, be sure to have the iOS simulator open and modify `iPhone 11` in `Program.csproj` to the simulator's name. To run the sample, open the command line and navigate to the downloaded folder and run `dotnet publish`. From 0d3b5b8807a74767a9c0398ac3bfae7d9b3836e9 Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Mon, 19 Oct 2020 13:02:56 -0400 Subject: [PATCH 23/41] Clean up notes in README --- core/mono-samples/iOS/README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/core/mono-samples/iOS/README.md b/core/mono-samples/iOS/README.md index e3d5f66294d..7c03c9130bc 100644 --- a/core/mono-samples/iOS/README.md +++ b/core/mono-samples/iOS/README.md @@ -13,15 +13,17 @@ urlFragment: "mono-ios-csharp" In this sample, the mono runtime is used to invoke objective-c unmanaged code (main.m) from the C# managed side (Program.cs) and vice versa. With the sample running, you can enter your name and click the corresponding button to modify the greeting message as well as clicking a button to increment a counter. -NOTE: The purpose of this sample is to demonstrate the concept of building an iOS application on top of the mono runtime. The mono runtime headers should be supplied through the build process. +[!NOTE] +The purpose of this sample is to demonstrate the concept of building an iOS application on top of the mono runtime. The mono runtime headers should be supplied through the build process. ## Sample Prerequisites To run the sample for iOS, Xcode and an iOS simulator is needed. -- Xcode: Any version should work with this sample (download Xcode at https://developer.apple.com/xcode/) -- iOS simulator: Minimal version iOS 8.0 +- Xcode: Any version should work with this sample (download Xcode at https://developer.apple.com/xcode/). +- iOS simulator 8.0 or greater. -NOTE: Modify `IosSimulator` under target `BuildAppBundle` from `iPhone 11` to your simulator's device name. +[!NOTE] +Modify `IosSimulator` under target `BuildAppBundle` from `iPhone 11` to your simulator's device name. ## Building the sample From be096f175c3164c856e4836d8f71c390814b85ca Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Mon, 19 Oct 2020 14:26:14 -0400 Subject: [PATCH 24/41] Add brackets around bare url in README --- core/mono-samples/iOS/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/mono-samples/iOS/README.md b/core/mono-samples/iOS/README.md index 7c03c9130bc..28d000aa31f 100644 --- a/core/mono-samples/iOS/README.md +++ b/core/mono-samples/iOS/README.md @@ -19,7 +19,7 @@ The purpose of this sample is to demonstrate the concept of building an iOS appl ## Sample Prerequisites To run the sample for iOS, Xcode and an iOS simulator is needed. -- Xcode: Any version should work with this sample (download Xcode at https://developer.apple.com/xcode/). +- Xcode: Any version should work with this sample (download Xcode at ). - iOS simulator 8.0 or greater. [!NOTE] From 08f2cf7add6bbd7a584144b6ede6bc8e9addf12c Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Mon, 19 Oct 2020 14:28:41 -0400 Subject: [PATCH 25/41] Remove trailing space and add blank line around list --- core/mono-samples/iOS/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/mono-samples/iOS/README.md b/core/mono-samples/iOS/README.md index 28d000aa31f..a1b7ad4a72c 100644 --- a/core/mono-samples/iOS/README.md +++ b/core/mono-samples/iOS/README.md @@ -18,7 +18,8 @@ The purpose of this sample is to demonstrate the concept of building an iOS appl ## Sample Prerequisites -To run the sample for iOS, Xcode and an iOS simulator is needed. +To run the sample for iOS, Xcode and an iOS simulator is needed. + - Xcode: Any version should work with this sample (download Xcode at ). - iOS simulator 8.0 or greater. From 5947c5222bcf7f6c8de07875154d072580ccc49b Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Tue, 20 Oct 2020 11:30:53 -0400 Subject: [PATCH 26/41] Reference dotnet6 NuGet feed --- core/mono-samples/iOS/NuGet.config | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/mono-samples/iOS/NuGet.config b/core/mono-samples/iOS/NuGet.config index 58d680be9d4..d78fdf55a15 100644 --- a/core/mono-samples/iOS/NuGet.config +++ b/core/mono-samples/iOS/NuGet.config @@ -4,7 +4,6 @@ - - + \ No newline at end of file From c9b2820d53007eda7c1e60610d819dae332e9d25 Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Tue, 20 Oct 2020 12:46:25 -0400 Subject: [PATCH 27/41] Remove nuget local repositoryPath --- core/mono-samples/iOS/NuGet.config | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/mono-samples/iOS/NuGet.config b/core/mono-samples/iOS/NuGet.config index d78fdf55a15..e02aa191e44 100644 --- a/core/mono-samples/iOS/NuGet.config +++ b/core/mono-samples/iOS/NuGet.config @@ -1,8 +1,5 @@ - - - From 2d79b0a4a843d1e40e622044aa294055c3ab7597 Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Tue, 20 Oct 2020 12:47:33 -0400 Subject: [PATCH 28/41] Reword header for clarification --- core/mono-samples/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/mono-samples/README.md b/core/mono-samples/README.md index c5fe80fe54a..bbc5236a206 100644 --- a/core/mono-samples/README.md +++ b/core/mono-samples/README.md @@ -1,3 +1,3 @@ -# Sample .NET mono runtime +# Sample .NET apps using the Mono runtime This folder contains sample code demonstrating how to build mobile (iOS, Android, Browser WebAssembly) apps with the mono runtime. The requirements for each sample can be found within the corresponding folder, and each sample can be ran using `dotnet publish`. From a31b03459fc1f41af7fa8a9f3b4bfabb6d9a6649 Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Tue, 20 Oct 2020 12:52:55 -0400 Subject: [PATCH 29/41] Fix nupkg version match --- core/mono-samples/iOS/Program.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/mono-samples/iOS/Program.csproj b/core/mono-samples/iOS/Program.csproj index bad157bb6e4..91cf49a3630 100644 --- a/core/mono-samples/iOS/Program.csproj +++ b/core/mono-samples/iOS/Program.csproj @@ -6,7 +6,7 @@ - + Date: Tue, 20 Oct 2020 12:57:17 -0400 Subject: [PATCH 30/41] Use PropertyPath instead of NuGetPackageRoot --- core/mono-samples/iOS/Program.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/mono-samples/iOS/Program.csproj b/core/mono-samples/iOS/Program.csproj index 91cf49a3630..815ab5bf908 100644 --- a/core/mono-samples/iOS/Program.csproj +++ b/core/mono-samples/iOS/Program.csproj @@ -6,11 +6,11 @@ - + + AssemblyFile="$(PkgMicrosoft_NET_Runtime_iOS_Sample_Mono)\tools\net6.0\AppleAppBuilder.dll" /> From c6c11ebeeb10edc0b93791d014cae2c2584f5e5a Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Tue, 20 Oct 2020 12:57:33 -0400 Subject: [PATCH 31/41] Remove unnecessary dependencies --- core/mono-samples/iOS/Program.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/mono-samples/iOS/Program.csproj b/core/mono-samples/iOS/Program.csproj index 815ab5bf908..9d92b71237a 100644 --- a/core/mono-samples/iOS/Program.csproj +++ b/core/mono-samples/iOS/Program.csproj @@ -12,7 +12,7 @@ - + $(MSBuildThisFileDirectory)$(PublishDir) x64 From 54c640e89ab6997b743b90c906ad8bf3cbf2e3f6 Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Tue, 20 Oct 2020 12:58:04 -0400 Subject: [PATCH 32/41] Add softcode for runtime identifier --- core/mono-samples/iOS/Program.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/mono-samples/iOS/Program.csproj b/core/mono-samples/iOS/Program.csproj index 9d92b71237a..cf1d1bae6cb 100644 --- a/core/mono-samples/iOS/Program.csproj +++ b/core/mono-samples/iOS/Program.csproj @@ -27,7 +27,7 @@ Date: Tue, 20 Oct 2020 13:00:58 -0400 Subject: [PATCH 33/41] Touch up README --- core/mono-samples/iOS/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/mono-samples/iOS/README.md b/core/mono-samples/iOS/README.md index a1b7ad4a72c..52b63c685bd 100644 --- a/core/mono-samples/iOS/README.md +++ b/core/mono-samples/iOS/README.md @@ -11,14 +11,14 @@ urlFragment: "mono-ios-csharp" # iOS Sample: Simple greeting and counter (C#) -In this sample, the mono runtime is used to invoke objective-c unmanaged code (main.m) from the C# managed side (Program.cs) and vice versa. With the sample running, you can enter your name and click the corresponding button to modify the greeting message as well as clicking a button to increment a counter. +In this sample, the mono runtime is used to invoke Objective-c unmanaged code (main.m) from the C# managed side (Program.cs) and vice versa. With the sample running, you can enter your name and click the corresponding button to modify the greeting message as well as clicking a button to increment a counter. [!NOTE] The purpose of this sample is to demonstrate the concept of building an iOS application on top of the mono runtime. The mono runtime headers should be supplied through the build process. ## Sample Prerequisites -To run the sample for iOS, Xcode and an iOS simulator is needed. +This sample will only run on macOS as it requires Xcode and an iOS simulator. - Xcode: Any version should work with this sample (download Xcode at ). - iOS simulator 8.0 or greater. @@ -28,4 +28,4 @@ Modify `IosSimulator` under target `BuildAppBundle` from `iPhone 11` to your sim ## Building the sample -The source code includes an MSBuild project file for C# (a _.csproj_ file) that targets .NET 5.0. After downloading the _.zip_ file, be sure to have the iOS simulator open and modify `iPhone 11` in `Program.csproj` to the simulator's name. To run the sample, open the command line and navigate to the downloaded folder and run `dotnet publish`. +The source code includes an MSBuild project file for C# (a _.csproj_ file) that targets .NET 5.0. After downloading the _.zip_ file, be sure to have the iOS simulator open and modify `iPhone 11` in `Program.csproj` to the simulator's name. To run the sample, open the command line, navigate to the downloaded folder, and run `dotnet publish`. From 35558ad1b132c53ed82d6b04c2aa8e68e885f824 Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Tue, 20 Oct 2020 13:07:37 -0400 Subject: [PATCH 34/41] Add build of dotnet sdk to prereqs --- core/mono-samples/iOS/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/core/mono-samples/iOS/README.md b/core/mono-samples/iOS/README.md index 52b63c685bd..6ea47411ebe 100644 --- a/core/mono-samples/iOS/README.md +++ b/core/mono-samples/iOS/README.md @@ -22,6 +22,7 @@ This sample will only run on macOS as it requires Xcode and an iOS simulator. - Xcode: Any version should work with this sample (download Xcode at ). - iOS simulator 8.0 or greater. +- Daily master build of the dotnet sdk (). [!NOTE] Modify `IosSimulator` under target `BuildAppBundle` from `iPhone 11` to your simulator's device name. From 2c3b0268f49bb3d4ab1efba4336895eaba8dbd53 Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Wed, 21 Oct 2020 09:57:19 -0400 Subject: [PATCH 35/41] Override with .NET 6 SDK --- core/mono-samples/iOS/global.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 core/mono-samples/iOS/global.json diff --git a/core/mono-samples/iOS/global.json b/core/mono-samples/iOS/global.json new file mode 100644 index 00000000000..5946fac08f0 --- /dev/null +++ b/core/mono-samples/iOS/global.json @@ -0,0 +1,7 @@ +{ + "sdk": { + "version": "6.0.100-alpha", + "rollForward": "major", + "allowPrerelease": true + } +} \ No newline at end of file From b1b465879cd2ba3e0d00ceaddd83b83ca90b23c3 Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Mon, 2 Nov 2020 14:07:56 -0500 Subject: [PATCH 36/41] Fix dotnet version and add installation instructions --- core/mono-samples/README.md | 19 +++++++++++++++++++ core/mono-samples/iOS/README.md | 2 +- core/mono-samples/iOS/global.json | 2 +- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/core/mono-samples/README.md b/core/mono-samples/README.md index bbc5236a206..869ca61e338 100644 --- a/core/mono-samples/README.md +++ b/core/mono-samples/README.md @@ -1,3 +1,22 @@ # Sample .NET apps using the Mono runtime This folder contains sample code demonstrating how to build mobile (iOS, Android, Browser WebAssembly) apps with the mono runtime. The requirements for each sample can be found within the corresponding folder, and each sample can be ran using `dotnet publish`. + +## Prerequisites + +.NET SDK version 6.0.100-alpha.1.20531.2 is needed to run these samples. To install a specific version of the dotnet sdk, download the latest stable version of the dotnet-install script: + +- Bash (Linux/macOS): +- PowerShell (Windows): + +Install version .NET version **6.0.100-alpha.1.20531.2**: + +```bash +./dotnet-install.sh --version 6.0.100-alpha.1.20531.2 +``` + +```powershell +./dotnet-install.ps1 -Version 6.0.100-alpha.1.20531.2 +``` + +For more information, see [dotnet-install script reference](https://docs.microsoft.com/dotnet/core/tools/dotnet-install-script) diff --git a/core/mono-samples/iOS/README.md b/core/mono-samples/iOS/README.md index 6ea47411ebe..187cb02dc80 100644 --- a/core/mono-samples/iOS/README.md +++ b/core/mono-samples/iOS/README.md @@ -22,7 +22,7 @@ This sample will only run on macOS as it requires Xcode and an iOS simulator. - Xcode: Any version should work with this sample (download Xcode at ). - iOS simulator 8.0 or greater. -- Daily master build of the dotnet sdk (). +- .NET sdk 6.0.100-alpha.1.20531.2 (Installation instructions in parent directory). [!NOTE] Modify `IosSimulator` under target `BuildAppBundle` from `iPhone 11` to your simulator's device name. diff --git a/core/mono-samples/iOS/global.json b/core/mono-samples/iOS/global.json index 5946fac08f0..7ee3eb64157 100644 --- a/core/mono-samples/iOS/global.json +++ b/core/mono-samples/iOS/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "6.0.100-alpha", + "version": "6.0.100-alpha.1.20531.2", "rollForward": "major", "allowPrerelease": true } From 2bb0b009bc824359dcc144b236db04a164dfaf67 Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Mon, 2 Nov 2020 14:35:37 -0500 Subject: [PATCH 37/41] Update target framework to target net6.0 --- core/mono-samples/iOS/Program.csproj | 2 +- core/mono-samples/iOS/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/mono-samples/iOS/Program.csproj b/core/mono-samples/iOS/Program.csproj index cf1d1bae6cb..8c8793d58d2 100644 --- a/core/mono-samples/iOS/Program.csproj +++ b/core/mono-samples/iOS/Program.csproj @@ -1,6 +1,6 @@ - net5.0 + net6.0 ios-x64 Exe diff --git a/core/mono-samples/iOS/README.md b/core/mono-samples/iOS/README.md index 187cb02dc80..07837b03a1e 100644 --- a/core/mono-samples/iOS/README.md +++ b/core/mono-samples/iOS/README.md @@ -29,4 +29,4 @@ Modify `IosSimulator` under target `BuildAppBundle` from `iPhone 11` to your sim ## Building the sample -The source code includes an MSBuild project file for C# (a _.csproj_ file) that targets .NET 5.0. After downloading the _.zip_ file, be sure to have the iOS simulator open and modify `iPhone 11` in `Program.csproj` to the simulator's name. To run the sample, open the command line, navigate to the downloaded folder, and run `dotnet publish`. +The source code includes an MSBuild project file for C# (a _.csproj_ file) that targets .NET 6.0. After downloading the _.zip_ file, be sure to have the iOS simulator open and modify `iPhone 11` in `Program.csproj` to the simulator's name. To run the sample, open the command line, navigate to the downloaded folder, and run `dotnet publish`. From f338c178ae0b1c9ff0fbf42ef3df7f0ceed354d1 Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Mon, 2 Nov 2020 14:50:53 -0500 Subject: [PATCH 38/41] Remove handlers and MonoPInvoke Attribute --- core/mono-samples/iOS/Program.cs | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/core/mono-samples/iOS/Program.cs b/core/mono-samples/iOS/Program.cs index f81c9f19bd7..5dd95437bfc 100644 --- a/core/mono-samples/iOS/Program.cs +++ b/core/mono-samples/iOS/Program.cs @@ -6,13 +6,6 @@ using System.Threading.Tasks; using System.Runtime.InteropServices; -// it's not part of the BCL but runtime needs it for native-to-managed callbacks in AOT -// To be replaced with NativeCallableAttribute -public class MonoPInvokeCallbackAttribute : Attribute -{ - public MonoPInvokeCallbackAttribute(Type delegateType) { } -} - public static class Program { // Defined in main.m @@ -28,19 +21,14 @@ public static class Program [DllImport("__Internal")] private extern static void ios_register_name_greet(Action action); - private static Action incrementHandler = null; - private static Action nameHandler = null; - private static int counter = 1; // Called by native code, see main.m - [MonoPInvokeCallback(typeof(Action))] private static void IncrementCounter() { - ios_set_text("Clicked " + counter++ + " times!"); + ios_set_text($"Clicked {counter++} times!"); } - [MonoPInvokeCallback(typeof(Action))] private static void GreetName(string name) { ios_greet_name(name); @@ -50,8 +38,8 @@ public static async Task Main(string[] args) { // Register a managed callback (will be called by UIButton, see main.m) // Also, keep the handler alive so GC won't collect it. - ios_register_counter_increment(incrementHandler = IncrementCounter); - ios_register_name_greet(nameHandler = GreetName); + ios_register_counter_increment(IncrementCounter); + ios_register_name_greet(GreetName); const string msg = "Hello World!"; for (int i = 0; i < msg.Length; i++) From 590a8bbea2d6c5c4954d21fdaab5b6d616f7cc77 Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Tue, 3 Nov 2020 13:40:24 -0500 Subject: [PATCH 39/41] Move TargetArchitecture to project scope --- core/mono-samples/iOS/Program.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/mono-samples/iOS/Program.csproj b/core/mono-samples/iOS/Program.csproj index 8c8793d58d2..7a790da4f48 100644 --- a/core/mono-samples/iOS/Program.csproj +++ b/core/mono-samples/iOS/Program.csproj @@ -1,7 +1,8 @@ net6.0 - ios-x64 + x64 + ios-$(TargetArchitecture) Exe @@ -15,7 +16,6 @@ $(MSBuildThisFileDirectory)$(PublishDir) - x64 iPhone 11 True From 813b9703819563a68449212967f48c0725813d83 Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Wed, 11 Nov 2020 12:07:10 -0500 Subject: [PATCH 40/41] Rename Program to iOSSampleApp and trim assemblies --- core/mono-samples/iOS/README.md | 4 ++-- .../iOS/{Program.cs => iOSSampleApp.cs} | 2 +- .../{Program.csproj => iOSSampleApp.csproj} | 18 ++++++++++-------- 3 files changed, 13 insertions(+), 11 deletions(-) rename core/mono-samples/iOS/{Program.cs => iOSSampleApp.cs} (97%) rename core/mono-samples/iOS/{Program.csproj => iOSSampleApp.csproj} (82%) diff --git a/core/mono-samples/iOS/README.md b/core/mono-samples/iOS/README.md index 07837b03a1e..d19d3197db3 100644 --- a/core/mono-samples/iOS/README.md +++ b/core/mono-samples/iOS/README.md @@ -11,7 +11,7 @@ urlFragment: "mono-ios-csharp" # iOS Sample: Simple greeting and counter (C#) -In this sample, the mono runtime is used to invoke Objective-c unmanaged code (main.m) from the C# managed side (Program.cs) and vice versa. With the sample running, you can enter your name and click the corresponding button to modify the greeting message as well as clicking a button to increment a counter. +In this sample, the mono runtime is used to invoke Objective-c unmanaged code (main.m) from the C# managed side (iOSSampleApp.cs) and vice versa. With the sample running, you can enter your name and click the corresponding button to modify the greeting message as well as clicking a button to increment a counter. [!NOTE] The purpose of this sample is to demonstrate the concept of building an iOS application on top of the mono runtime. The mono runtime headers should be supplied through the build process. @@ -29,4 +29,4 @@ Modify `IosSimulator` under target `BuildAppBundle` from `iPhone 11` to your sim ## Building the sample -The source code includes an MSBuild project file for C# (a _.csproj_ file) that targets .NET 6.0. After downloading the _.zip_ file, be sure to have the iOS simulator open and modify `iPhone 11` in `Program.csproj` to the simulator's name. To run the sample, open the command line, navigate to the downloaded folder, and run `dotnet publish`. +The source code includes an MSBuild project file for C# (a _.csproj_ file) that targets .NET 6.0. After downloading the _.zip_ file, be sure to have the iOS simulator open and modify `iPhone 11` in `iOSSampleApp.csproj` to the simulator's name. To run the sample, open the command line, navigate to the downloaded folder, and run `dotnet publish`. diff --git a/core/mono-samples/iOS/Program.cs b/core/mono-samples/iOS/iOSSampleApp.cs similarity index 97% rename from core/mono-samples/iOS/Program.cs rename to core/mono-samples/iOS/iOSSampleApp.cs index 5dd95437bfc..88abfd9dd00 100644 --- a/core/mono-samples/iOS/Program.cs +++ b/core/mono-samples/iOS/iOSSampleApp.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; using System.Runtime.InteropServices; -public static class Program +public static class iOSSampleApp { // Defined in main.m [DllImport("__Internal")] diff --git a/core/mono-samples/iOS/Program.csproj b/core/mono-samples/iOS/iOSSampleApp.csproj similarity index 82% rename from core/mono-samples/iOS/Program.csproj rename to core/mono-samples/iOS/iOSSampleApp.csproj index 7a790da4f48..281f1e1df15 100644 --- a/core/mono-samples/iOS/Program.csproj +++ b/core/mono-samples/iOS/iOSSampleApp.csproj @@ -4,10 +4,13 @@ x64 ios-$(TargetArchitecture) Exe + True + link + Release - + + NativeMainSource="$(MSBuildThisFileDirectory)main.m"> - - - + + + - + - + \ No newline at end of file From cfaa203558c89fef412642a38b69e21bd7b8a010 Mon Sep 17 00:00:00 2001 From: Andy De George <67293991+adegeo@users.noreply.github.com> Date: Wed, 11 Nov 2020 11:24:46 -0800 Subject: [PATCH 41/41] Minor fixes; pulled prereqs into sample readme --- core/mono-samples/iOS/README.md | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/core/mono-samples/iOS/README.md b/core/mono-samples/iOS/README.md index d19d3197db3..c4541093437 100644 --- a/core/mono-samples/iOS/README.md +++ b/core/mono-samples/iOS/README.md @@ -13,8 +13,8 @@ urlFragment: "mono-ios-csharp" In this sample, the mono runtime is used to invoke Objective-c unmanaged code (main.m) from the C# managed side (iOSSampleApp.cs) and vice versa. With the sample running, you can enter your name and click the corresponding button to modify the greeting message as well as clicking a button to increment a counter. -[!NOTE] -The purpose of this sample is to demonstrate the concept of building an iOS application on top of the mono runtime. The mono runtime headers should be supplied through the build process. +> [!NOTE] +> The purpose of this sample is to demonstrate the concept of building an iOS application on top of the mono runtime. The mono runtime headers should be supplied through the build process. ## Sample Prerequisites @@ -24,8 +24,23 @@ This sample will only run on macOS as it requires Xcode and an iOS simulator. - iOS simulator 8.0 or greater. - .NET sdk 6.0.100-alpha.1.20531.2 (Installation instructions in parent directory). -[!NOTE] -Modify `IosSimulator` under target `BuildAppBundle` from `iPhone 11` to your simulator's device name. +To install a specific version of the dotnet sdk, download the latest stable version of the dotnet-install script: + +- Bash (Linux/macOS): +- PowerShell (Windows): + +Install version .NET version **6.0.100-alpha.1.20531.2**: + +```bash +./dotnet-install.sh --version 6.0.100-alpha.1.20531.2 +``` + +```powershell +./dotnet-install.ps1 -Version 6.0.100-alpha.1.20531.2 +``` + +> [!NOTE] +> Modify `IosSimulator` under target `BuildAppBundle` from `iPhone 11` to your simulator's device name. ## Building the sample