From 6240e848f3d0da626a875bd1fa5eeff12154cf8e Mon Sep 17 00:00:00 2001 From: Rolf Bjarne Kvinge Date: Thu, 22 Oct 2020 21:05:58 +0200 Subject: [PATCH] [mtouch] Move mtouch's GenerateMain to shared Target code. This means moving a lot of supporting code to shared code as well. --- tools/common/Application.cs | 120 ++++++++++ tools/common/Assembly.cs | 9 + tools/common/BitCodeMode.cs | 8 + tools/common/Target.cs | 265 +++++++++++++++++++++++ tools/dotnet-linker/Compat.cs | 8 - tools/dotnet-linker/dotnet-linker.csproj | 3 + tools/mmp/mmp.csproj | 6 + tools/mtouch/Application.mtouch.cs | 123 ----------- tools/mtouch/Assembly.mtouch.cs | 9 - tools/mtouch/BuildTasks.mtouch.cs | 2 +- tools/mtouch/mtouch.cs | 264 ---------------------- tools/mtouch/mtouch.csproj | 3 + 12 files changed, 415 insertions(+), 405 deletions(-) create mode 100644 tools/common/BitCodeMode.cs diff --git a/tools/common/Application.cs b/tools/common/Application.cs index de6bb7bb0d..b104b0c404 100644 --- a/tools/common/Application.cs +++ b/tools/common/Application.cs @@ -79,6 +79,8 @@ namespace Xamarin.Bundler { public bool IsExtension; public ApplePlatform Platform { get { return Driver.TargetFramework.Platform; } } + public List InterpretedAssemblies = new List (); + // Linker config public LinkMode LinkMode = LinkMode.Full; public List LinkSkipped = new List (); @@ -112,6 +114,80 @@ namespace Xamarin.Bundler { public bool? DisableOmitFramePointer = null; // Only applicable to Xamarin.Mac public string CustomBundleName = "MonoBundle"; // Only applicable to Xamarin.Mac + public bool? UseMonoFramework; + + public BitCodeMode BitCodeMode { get; set; } + + public bool EnableAsmOnlyBitCode { get { return BitCodeMode == BitCodeMode.ASMOnly; } } + public bool EnableLLVMOnlyBitCode { get { return BitCodeMode == BitCodeMode.LLVMOnly; } } + public bool EnableMarkerOnlyBitCode { get { return BitCodeMode == BitCodeMode.MarkerOnly; } } + public bool EnableBitCode { get { return BitCodeMode != BitCodeMode.None; } } + + Dictionary> assembly_build_targets = new Dictionary> (); + + public AssemblyBuildTarget LibMonoLinkMode { + get { + if (Embeddinator) { + return AssemblyBuildTarget.StaticObject; + } else if (HasFrameworks || UseMonoFramework.Value) { + return AssemblyBuildTarget.Framework; + } else if (HasDynamicLibraries) { + return AssemblyBuildTarget.DynamicLibrary; + } else { + return AssemblyBuildTarget.StaticObject; + } + } + } + public AssemblyBuildTarget LibXamarinLinkMode { + get { + if (Embeddinator) { + return AssemblyBuildTarget.StaticObject; + } else if (HasFrameworks) { + return AssemblyBuildTarget.Framework; + } else if (HasDynamicLibraries) { + return AssemblyBuildTarget.DynamicLibrary; + } else { + return AssemblyBuildTarget.StaticObject; + } + } + } + public AssemblyBuildTarget LibPInvokesLinkMode => LibXamarinLinkMode; + public AssemblyBuildTarget LibProfilerLinkMode => OnlyStaticLibraries ? AssemblyBuildTarget.StaticObject : AssemblyBuildTarget.DynamicLibrary; + public AssemblyBuildTarget LibMonoNativeLinkMode => HasDynamicLibraries ? AssemblyBuildTarget.DynamicLibrary : AssemblyBuildTarget.StaticObject; + + public bool OnlyStaticLibraries { + get { + return assembly_build_targets.All ((abt) => abt.Value.Item1 == AssemblyBuildTarget.StaticObject); + } + } + + public bool HasDynamicLibraries { + get { + return assembly_build_targets.Any ((abt) => abt.Value.Item1 == AssemblyBuildTarget.DynamicLibrary); + } + } + + public bool HasFrameworks { + get { + return assembly_build_targets.Any ((abt) => abt.Value.Item1 == AssemblyBuildTarget.Framework); + } + } + + public bool HasFrameworksDirectory { + get { + if (Platform == ApplePlatform.MacOSX) + return false; + + if (!IsExtension) + return true; + + if (IsWatchExtension && Platform == ApplePlatform.WatchOS) + return true; + + return false; + } + } + bool RequiresXcodeHeaders { get { switch (Platform) { @@ -1108,5 +1184,49 @@ namespace Xamarin.Bundler { break; } } + + public bool IsInterpreted (string assembly) + { + // IsAOTCompiled and IsInterpreted are not opposites: mscorlib.dll can be both. + if (!UseInterpreter) + return false; + + // Go through the list of assemblies to interpret in reverse order, + // so that the last option passed to mtouch takes precedence. + for (int i = InterpretedAssemblies.Count - 1; i >= 0; i--) { + var opt = InterpretedAssemblies [i]; + if (opt == "all") + return true; + else if (opt == "-all") + return false; + else if (opt == assembly) + return true; + else if (opt [0] == '-' && opt.Substring (1) == assembly) + return false; + } + + // There's an implicit 'all' at the start of the list. + return true; + } + + public bool IsAOTCompiled (string assembly) + { + if (!UseInterpreter) + return true; + + // IsAOTCompiled and IsInterpreted are not opposites: mscorlib.dll can be both: + // - mscorlib will always be processed by the AOT compiler to generate required wrapper functions for the interpreter to work + // - mscorlib might also be fully AOT-compiled (both when the interpreter is enabled and when it's not) + if (assembly == "mscorlib") + return true; + + return !IsInterpreted (assembly); + } + + public string AssemblyName { + get { + return Path.GetFileName (RootAssemblies [0]); + } + } } } diff --git a/tools/common/Assembly.cs b/tools/common/Assembly.cs index 668bbd3336..ba4a65a32d 100644 --- a/tools/common/Assembly.cs +++ b/tools/common/Assembly.cs @@ -48,6 +48,9 @@ namespace Xamarin.Bundler { public partial class Assembly { + public AssemblyBuildTarget BuildTarget; + public string BuildTargetName; + public bool IsCodeShared; public List Satellites; public Application App { get { return Target.App; } } @@ -722,6 +725,12 @@ namespace Xamarin.Bundler { Application.UpdateFile (config_src, config_target, true); } } + + public bool IsAOTCompiled { + get { + return App.IsAOTCompiled (Identity); + } + } } public sealed class NormalizedStringComparer : IEqualityComparer diff --git a/tools/common/BitCodeMode.cs b/tools/common/BitCodeMode.cs new file mode 100644 index 0000000000..6e5c911124 --- /dev/null +++ b/tools/common/BitCodeMode.cs @@ -0,0 +1,8 @@ +namespace Xamarin.Bundler { + public enum BitCodeMode { + None = 0, + ASMOnly = 1, + LLVMOnly = 2, + MarkerOnly = 3, + } +} diff --git a/tools/common/Target.cs b/tools/common/Target.cs index aabad89ec4..a7177e0131 100644 --- a/tools/common/Target.cs +++ b/tools/common/Target.cs @@ -559,5 +559,270 @@ namespace Xamarin.Bundler { return sb.ToString (); } + // note: this is executed under Parallel.ForEach + public string GenerateIOSMain (Abi abi, string main_source, IList registration_methods) + { + var app = App; + var assemblies = Assemblies; + var assembly_name = App.AssemblyName; + var assembly_externs = new StringBuilder (); + var assembly_aot_modules = new StringBuilder (); + var register_assemblies = new StringBuilder (); + var assembly_location = new StringBuilder (); + var assembly_location_count = 0; + var enable_llvm = (abi & Abi.LLVM) != 0; + + register_assemblies.AppendLine ("\tguint32 exception_gchandle = 0;"); + foreach (var s in assemblies) { + if (!s.IsAOTCompiled) + continue; + if ((abi & Abi.SimulatorArchMask) == 0) { + var info = s.AssemblyDefinition.Name.Name; + info = EncodeAotSymbol (info); + assembly_externs.Append ("extern void *mono_aot_module_").Append (info).AppendLine ("_info;"); + assembly_aot_modules.Append ("\tmono_aot_register_module (mono_aot_module_").Append (info).AppendLine ("_info);"); + } + string sname = s.FileName; + if (assembly_name != sname && IsBoundAssembly (s)) { + register_assemblies.Append ("\txamarin_open_and_register (\"").Append (sname).Append ("\", &exception_gchandle);").AppendLine (); + register_assemblies.AppendLine ("\txamarin_process_managed_exception_gchandle (exception_gchandle);"); + } + } + + if ((abi & Abi.SimulatorArchMask) == 0 || app.Embeddinator) { + var frameworks = assemblies.Where ((a) => a.BuildTarget == AssemblyBuildTarget.Framework) + .OrderBy ((a) => a.Identity, StringComparer.Ordinal); + foreach (var asm_fw in frameworks) { + var asm_name = asm_fw.Identity; + if (asm_fw.BuildTargetName == asm_name) + continue; // this is deduceable + var prefix = string.Empty; + if (!app.HasFrameworksDirectory && asm_fw.IsCodeShared) + prefix = "../../"; + var suffix = string.Empty; + if (app.IsSimulatorBuild) + suffix = "/simulator"; + assembly_location.AppendFormat ("\t{{ \"{0}\", \"{2}Frameworks/{1}.framework/MonoBundle{3}\" }},\n", asm_name, asm_fw.BuildTargetName, prefix, suffix); + assembly_location_count++; + } + } + + try { + StringBuilder sb = new StringBuilder (); + using (var sw = new StringWriter (sb)) { + sw.WriteLine ("#include \"xamarin/xamarin.h\""); + + if (assembly_location.Length > 0) { + sw.WriteLine (); + sw.WriteLine ("struct AssemblyLocation assembly_location_entries [] = {"); + sw.WriteLine (assembly_location); + sw.WriteLine ("};"); + + sw.WriteLine (); + sw.WriteLine ("struct AssemblyLocations assembly_locations = {{ {0}, assembly_location_entries }};", assembly_location_count); + } + + sw.WriteLine (); + sw.WriteLine (assembly_externs); + + sw.WriteLine ("void xamarin_register_modules_impl ()"); + sw.WriteLine ("{"); + sw.WriteLine (assembly_aot_modules); + sw.WriteLine ("}"); + sw.WriteLine (); + + sw.WriteLine ("void xamarin_register_assemblies_impl ()"); + sw.WriteLine ("{"); + sw.WriteLine (register_assemblies); + sw.WriteLine ("}"); + sw.WriteLine (); + + if (registration_methods != null) { + foreach (var method in registration_methods) { + sw.Write ("extern \"C\" void "); + sw.Write (method); + sw.WriteLine ("();"); + } + } + + // Burn in a reference to the profiling symbol so that the native linker doesn't remove it + // On iOS we can pass -u to the native linker, but that doesn't work on tvOS, where + // we're building with bitcode (even when bitcode is disabled, we still build with the + // bitcode marker, which makes the linker reject -u). + if (app.EnableProfiling) { + sw.WriteLine ("extern \"C\" { void mono_profiler_init_log (); }"); + sw.WriteLine ("typedef void (*xamarin_profiler_symbol_def)();"); + sw.WriteLine ("extern xamarin_profiler_symbol_def xamarin_profiler_symbol;"); + sw.WriteLine ("xamarin_profiler_symbol_def xamarin_profiler_symbol = NULL;"); + } + + if (app.UseInterpreter) { + sw.WriteLine ("extern \"C\" { void mono_ee_interp_init (const char *); }"); + sw.WriteLine ("extern \"C\" { void mono_icall_table_init (void); }"); + sw.WriteLine ("extern \"C\" { void mono_marshal_ilgen_init (void); }"); + sw.WriteLine ("extern \"C\" { void mono_method_builder_ilgen_init (void); }"); + sw.WriteLine ("extern \"C\" { void mono_sgen_mono_ilgen_init (void); }"); + } + + sw.WriteLine ("void xamarin_setup_impl ()"); + sw.WriteLine ("{"); + + if (app.EnableProfiling) + sw.WriteLine ("\txamarin_profiler_symbol = mono_profiler_init_log;"); + + if (app.EnableLLVMOnlyBitCode) + sw.WriteLine ("\tmono_jit_set_aot_mode (MONO_AOT_MODE_LLVMONLY);"); + else if (app.UseInterpreter) { + sw.WriteLine ("\tmono_icall_table_init ();"); + sw.WriteLine ("\tmono_marshal_ilgen_init ();"); + sw.WriteLine ("\tmono_method_builder_ilgen_init ();"); + sw.WriteLine ("\tmono_sgen_mono_ilgen_init ();"); + sw.WriteLine ("\tmono_ee_interp_init (NULL);"); + sw.WriteLine ("\tmono_jit_set_aot_mode (MONO_AOT_MODE_INTERP);"); + } else if (app.IsDeviceBuild) + sw.WriteLine ("\tmono_jit_set_aot_mode (MONO_AOT_MODE_FULL);"); + + if (assembly_location.Length > 0) + sw.WriteLine ("\txamarin_set_assembly_directories (&assembly_locations);"); + + if (registration_methods != null) { + for (int i = 0; i < registration_methods.Count; i++) { + sw.Write ("\t"); + sw.Write (registration_methods [i]); + sw.WriteLine ("();"); + } + } + + if (app.MonoNativeMode != MonoNativeMode.None) { + string mono_native_lib; + if (app.LibMonoNativeLinkMode == AssemblyBuildTarget.StaticObject) + mono_native_lib = "__Internal"; + else + mono_native_lib = app.GetLibNativeName () + ".dylib"; + sw.WriteLine (); + sw.WriteLine ($"\tmono_dllmap_insert (NULL, \"System.Native\", NULL, \"{mono_native_lib}\", NULL);"); + sw.WriteLine ($"\tmono_dllmap_insert (NULL, \"System.Security.Cryptography.Native.Apple\", NULL, \"{mono_native_lib}\", NULL);"); + sw.WriteLine ($"\tmono_dllmap_insert (NULL, \"System.Net.Security.Native\", NULL, \"{mono_native_lib}\", NULL);"); + sw.WriteLine (); + } + + if (app.EnableDebug) + sw.WriteLine ("\txamarin_gc_pump = {0};", app.DebugTrack.Value ? "TRUE" : "FALSE"); + sw.WriteLine ("\txamarin_init_mono_debug = {0};", app.PackageManagedDebugSymbols ? "TRUE" : "FALSE"); + sw.WriteLine ("\txamarin_executable_name = \"{0}\";", assembly_name); + sw.WriteLine ("\tmono_use_llvm = {0};", enable_llvm ? "TRUE" : "FALSE"); + sw.WriteLine ("\txamarin_log_level = {0};", Driver.Verbosity.ToString (CultureInfo.InvariantCulture)); + sw.WriteLine ("\txamarin_arch_name = \"{0}\";", abi.AsArchString ()); + if (!app.IsDefaultMarshalManagedExceptionMode) + sw.WriteLine ("\txamarin_marshal_managed_exception_mode = MarshalManagedExceptionMode{0};", app.MarshalManagedExceptions); + sw.WriteLine ("\txamarin_marshal_objectivec_exception_mode = MarshalObjectiveCExceptionMode{0};", app.MarshalObjectiveCExceptions); + if (app.EnableDebug) + sw.WriteLine ("\txamarin_debug_mode = TRUE;"); + if (!string.IsNullOrEmpty (app.MonoGCParams)) + sw.WriteLine ("\tsetenv (\"MONO_GC_PARAMS\", \"{0}\", 1);", app.MonoGCParams); + foreach (var kvp in app.EnvironmentVariables) + sw.WriteLine ("\tsetenv (\"{0}\", \"{1}\", 1);", kvp.Key.Replace ("\"", "\\\""), kvp.Value.Replace ("\"", "\\\"")); + sw.WriteLine ("\txamarin_supports_dynamic_registration = {0};", app.DynamicRegistrationSupported ? "TRUE" : "FALSE"); + sw.WriteLine ("}"); + sw.WriteLine (); + sw.Write ("int "); + sw.Write (app.IsWatchExtension ? "xamarin_watchextension_main" : "main"); + sw.WriteLine (" (int argc, char **argv)"); + sw.WriteLine ("{"); + sw.WriteLine ("\tNSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];"); + if (app.IsExtension) { + // the name of the executable must be the bundle id (reverse dns notation) + // but we do not want to impose that (ugly) restriction to the managed .exe / project name / ... + sw.WriteLine ("\targv [0] = (char *) \"{0}\";", Path.GetFileNameWithoutExtension (app.RootAssemblies [0])); + sw.WriteLine ("\tint rv = xamarin_main (argc, argv, XamarinLaunchModeExtension);"); + } else { + sw.WriteLine ("\tint rv = xamarin_main (argc, argv, XamarinLaunchModeApp);"); + } + sw.WriteLine ("\t[pool drain];"); + sw.WriteLine ("\treturn rv;"); + sw.WriteLine ("}"); + + string extension_main = null; + if (app.Platform == ApplePlatform.WatchOS && app.IsWatchExtension) { + // We're building a watch extension, and we have multiple scenarios, depending on the watchOS version we're executing on: + // + // * watchOS 2.0 -> 5.*: we must call a `main` function provided in the WatchKit framework. + // * watchOS 6.0 -> * : we must call a `WKExtensionMain` function provided in the WatchKit framework. + // * watchOS 7.0 -> * : The `WKExtensionMain` function uses dlsym to find any `main` functions in the + // main executable, and calls that function (otherwise WKExtensionMain will call + // UIApplicationMain and normal startup occurs) + // + // * We can't call our entry point "main", because we call WKExtensionMain, and then we run into an + // infinite loop on watchOS 7.0. So we call it xamarin_watch_extension_main. + // * The watchOS 6+ SDK helpfully provides a static library (WKExtensionMainLegacy) that has a + // WKExtensionMain function, which we use when the deployment target is earlier than watchOS 6.0. + // This means that calling WKExtensionMain works everywhere (as long as we're using the + // watchOS 6+ SDK to build; otherwise we just call "main" directly and don't link with the + // WKExtensionMainLegacy library) + + if (app.SdkVersion.Major >= 6) { + extension_main = "WKExtensionMain"; + } else { + extension_main = "main"; + } + } + + if (!string.IsNullOrEmpty (extension_main)) { + sw.WriteLine ($"extern \"C\" {{ int {extension_main} (int argc, char* argv[]); }}"); + sw.WriteLine (); + } + + sw.WriteLine (); + sw.WriteLine ("void xamarin_initialize_callbacks () __attribute__ ((constructor));"); + sw.WriteLine ("void xamarin_initialize_callbacks ()"); + sw.WriteLine ("{"); + sw.WriteLine ("\txamarin_setup = xamarin_setup_impl;"); + sw.WriteLine ("\txamarin_register_assemblies = xamarin_register_assemblies_impl;"); + sw.WriteLine ("\txamarin_register_modules = xamarin_register_modules_impl;"); + if (!string.IsNullOrEmpty (extension_main)) + sw.WriteLine ($"\txamarin_extension_main = {extension_main};"); + sw.WriteLine ("}"); + } + Driver.WriteIfDifferent (main_source, sb.ToString (), true); + } catch (ProductException) { + throw; + } catch (Exception e) { + throw new ProductException (4001, true, e, Errors.MT4001, main_source); + } + + return main_source; + } + + static string EncodeAotSymbol (string symbol) + { + var sb = new StringBuilder (); + /* This mimics what the aot-compiler does */ + foreach (var b in System.Text.Encoding.UTF8.GetBytes (symbol)) { + char c = (char) b; + if ((c >= '0' && c <= '9') || + (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z')) { + sb.Append (c); + continue; + } + sb.Append ('_'); + } + return sb.ToString (); + } + + static bool IsBoundAssembly (Assembly s) + { + if (s.IsFrameworkAssembly == true) + return false; + + AssemblyDefinition ad = s.AssemblyDefinition; + + foreach (ModuleDefinition md in ad.Modules) + foreach (TypeDefinition td in md.Types) + if (td.IsNSObject (s.Target.LinkContext)) + return true; + + return false; + } } } diff --git a/tools/dotnet-linker/Compat.cs b/tools/dotnet-linker/Compat.cs index 9d84a4612c..64ed94e963 100644 --- a/tools/dotnet-linker/Compat.cs +++ b/tools/dotnet-linker/Compat.cs @@ -57,14 +57,6 @@ namespace Xamarin.Bundler { Driver.Log (1, $"Registrar mode: {Registrar}"); } - public AssemblyBuildTarget LibMonoLinkMode { - get { throw new NotImplementedException (); } - } - - public AssemblyBuildTarget LibXamarinLinkMode { - get { throw new NotImplementedException (); } - } - public bool HasAnyDynamicLibraries { get { throw new NotImplementedException (); } } diff --git a/tools/dotnet-linker/dotnet-linker.csproj b/tools/dotnet-linker/dotnet-linker.csproj index b239323b92..39ece52afd 100644 --- a/tools/dotnet-linker/dotnet-linker.csproj +++ b/tools/dotnet-linker/dotnet-linker.csproj @@ -182,6 +182,9 @@ external\Xamarin.MacDev\Xamarin.MacDev\PListObject.cs + + external\tools\common\BitCodeMode.cs + diff --git a/tools/mmp/mmp.csproj b/tools/mmp/mmp.csproj index 19999a5cd3..ac32088966 100644 --- a/tools/mmp/mmp.csproj +++ b/tools/mmp/mmp.csproj @@ -455,6 +455,12 @@ external\tools\mtouch\Stripper.cs + + tools\common\AssemblyBuildTarget.cs + + + tools\common\BitCodeMode.cs + diff --git a/tools/mtouch/Application.mtouch.cs b/tools/mtouch/Application.mtouch.cs index 9124286419..b3633d9fbc 100644 --- a/tools/mtouch/Application.mtouch.cs +++ b/tools/mtouch/Application.mtouch.cs @@ -17,13 +17,6 @@ using Xamarin.Utils; namespace Xamarin.Bundler { - public enum BitCodeMode { - None = 0, - ASMOnly = 1, - LLVMOnly = 2, - MarkerOnly = 3, - } - public enum DlsymOptions { Default, @@ -57,7 +50,6 @@ namespace Xamarin.Bundler { public DlsymOptions DlsymOptions; public List> DlsymAssemblies; - public bool? UseMonoFramework; public bool? PackageMonoFramework; public bool NoFastSim; @@ -69,7 +61,6 @@ namespace Xamarin.Bundler { public List AotOtherArguments = null; public bool? LLVMAsmWriter; public Dictionary LLVMOptimizations = new Dictionary (); - public List InterpretedAssemblies = new List (); // // Linker config @@ -80,44 +71,6 @@ namespace Xamarin.Bundler { public bool? BuildDSym; - public bool IsInterpreted (string assembly) - { - // IsAOTCompiled and IsInterpreted are not opposites: mscorlib.dll can be both. - if (!UseInterpreter) - return false; - - // Go through the list of assemblies to interpret in reverse order, - // so that the last option passed to mtouch takes precedence. - for (int i = InterpretedAssemblies.Count - 1; i >= 0; i--) { - var opt = InterpretedAssemblies [i]; - if (opt == "all") - return true; - else if (opt == "-all") - return false; - else if (opt == assembly) - return true; - else if (opt [0] == '-' && opt.Substring (1) == assembly) - return false; - } - - // There's an implicit 'all' at the start of the list. - return true; - } - - public bool IsAOTCompiled (string assembly) - { - if (!UseInterpreter) - return true; - - // IsAOTCompiled and IsInterpreted are not opposites: mscorlib.dll can be both: - // - mscorlib will always be processed by the AOT compiler to generate required wrapper functions for the interpreter to work - // - mscorlib might also be fully AOT-compiled (both when the interpreter is enabled and when it's not) - if (assembly == "mscorlib") - return true; - - return !IsInterpreted (assembly); - } - public List UserGccFlags; // If we didn't link the final executable because the existing binary is up-to-date. @@ -136,52 +89,8 @@ namespace Xamarin.Bundler { BuildTasks build_tasks; BuildTask final_build_task; // either lipo or file copy (to final destination) - Dictionary> assembly_build_targets = new Dictionary> (); - - public AssemblyBuildTarget LibMonoLinkMode { - get { - if (Embeddinator) { - return AssemblyBuildTarget.StaticObject; - } else if (HasFrameworks || UseMonoFramework.Value) { - return AssemblyBuildTarget.Framework; - } else if (HasDynamicLibraries) { - return AssemblyBuildTarget.DynamicLibrary; - } else { - return AssemblyBuildTarget.StaticObject; - } - } - } - public AssemblyBuildTarget LibXamarinLinkMode { - get { - if (Embeddinator) { - return AssemblyBuildTarget.StaticObject; - } else if (HasFrameworks) { - return AssemblyBuildTarget.Framework; - } else if (HasDynamicLibraries) { - return AssemblyBuildTarget.DynamicLibrary; - } else { - return AssemblyBuildTarget.StaticObject; - } - } - } - public AssemblyBuildTarget LibPInvokesLinkMode => LibXamarinLinkMode; - public AssemblyBuildTarget LibProfilerLinkMode => OnlyStaticLibraries ? AssemblyBuildTarget.StaticObject : AssemblyBuildTarget.DynamicLibrary; - public AssemblyBuildTarget LibMonoNativeLinkMode => HasDynamicLibraries ? AssemblyBuildTarget.DynamicLibrary : AssemblyBuildTarget.StaticObject; - Dictionary bundle_files = new Dictionary (); - public bool OnlyStaticLibraries { - get { - return assembly_build_targets.All ((abt) => abt.Value.Item1 == AssemblyBuildTarget.StaticObject); - } - } - - public bool HasDynamicLibraries { - get { - return assembly_build_targets.Any ((abt) => abt.Value.Item1 == AssemblyBuildTarget.DynamicLibrary); - } - } - public bool HasAnyDynamicLibraries { get { if (LibMonoLinkMode == AssemblyBuildTarget.DynamicLibrary) @@ -198,12 +107,6 @@ namespace Xamarin.Bundler { } } - public bool HasFrameworks { - get { - return assembly_build_targets.Any ((abt) => abt.Value.Item1 == AssemblyBuildTarget.Framework); - } - } - public void ClearAssemblyBuildTargets () { assembly_build_targets.Clear (); @@ -455,13 +358,6 @@ namespace Xamarin.Bundler { } } - public BitCodeMode BitCodeMode { get; set; } - - public bool EnableAsmOnlyBitCode { get { return BitCodeMode == BitCodeMode.ASMOnly; } } - public bool EnableLLVMOnlyBitCode { get { return BitCodeMode == BitCodeMode.LLVMOnly; } } - public bool EnableMarkerOnlyBitCode { get { return BitCodeMode == BitCodeMode.MarkerOnly; } } - public bool EnableBitCode { get { return BitCodeMode != BitCodeMode.None; } } - public ICollection AllArchitectures { get { if (all_architectures == null) { @@ -477,19 +373,6 @@ namespace Xamarin.Bundler { } } - public bool HasFrameworksDirectory { - get { - if (!IsExtension) - return true; - - if (IsWatchExtension && Platform == ApplePlatform.WatchOS) - return true; - - return false; - } - } - - public string BundleId { get { return GetStringFromInfoPList ("CFBundleIdentifier"); @@ -1125,12 +1008,6 @@ namespace Xamarin.Bundler { return rv; } - public string AssemblyName { - get { - return Path.GetFileName (RootAssemblies [0]); - } - } - public string Executable { get { if (Embeddinator) diff --git a/tools/mtouch/Assembly.mtouch.cs b/tools/mtouch/Assembly.mtouch.cs index d17a22bd80..9f93d799c4 100644 --- a/tools/mtouch/Assembly.mtouch.cs +++ b/tools/mtouch/Assembly.mtouch.cs @@ -23,9 +23,6 @@ namespace Xamarin.Bundler { public partial class Assembly { - public AssemblyBuildTarget BuildTarget; - public string BuildTargetName; - public bool IsCodeShared; public bool BundleInContainerApp; public Dictionary AotInfos = new Dictionary (); @@ -45,12 +42,6 @@ namespace Xamarin.Bundler { } } - public bool IsAOTCompiled { - get { - return App.IsAOTCompiled (Identity); - } - } - // Recursively list all the assemblies the specified assembly depends on. HashSet ComputeDependencies (List warnings) { diff --git a/tools/mtouch/BuildTasks.mtouch.cs b/tools/mtouch/BuildTasks.mtouch.cs index 10482e4202..bd10a9e937 100644 --- a/tools/mtouch/BuildTasks.mtouch.cs +++ b/tools/mtouch/BuildTasks.mtouch.cs @@ -83,7 +83,7 @@ namespace Xamarin.Bundler protected override void Execute () { - Driver.GenerateMain (Target, Target.Assemblies, Target.App.AssemblyName, Abi, MainM, RegistrationMethods); + Target.GenerateIOSMain (Abi, MainM, RegistrationMethods); } } diff --git a/tools/mtouch/mtouch.cs b/tools/mtouch/mtouch.cs index 553907b336..6b9882716e 100644 --- a/tools/mtouch/mtouch.cs +++ b/tools/mtouch/mtouch.cs @@ -294,255 +294,6 @@ namespace Xamarin.Bundler return args; } - static string EncodeAotSymbol (string symbol) - { - var sb = new StringBuilder (); - /* This mimics what the aot-compiler does */ - foreach (var b in System.Text.Encoding.UTF8.GetBytes (symbol)) { - char c = (char) b; - if ((c >= '0' && c <= '9') || - (c >= 'a' && c <= 'z') || - (c >= 'A' && c <= 'Z')) { - sb.Append (c); - continue; - } - sb.Append ('_'); - } - return sb.ToString (); - } - - // note: this is executed under Parallel.ForEach - public static string GenerateMain (Target target, IEnumerable assemblies, string assembly_name, Abi abi, string main_source, IList registration_methods) - { - var app = target.App; - var assembly_externs = new StringBuilder (); - var assembly_aot_modules = new StringBuilder (); - var register_assemblies = new StringBuilder (); - var assembly_location = new StringBuilder (); - var assembly_location_count = 0; - var enable_llvm = (abi & Abi.LLVM) != 0; - - register_assemblies.AppendLine ("\tguint32 exception_gchandle = 0;"); - foreach (var s in assemblies) { - if (!s.IsAOTCompiled) - continue; - if ((abi & Abi.SimulatorArchMask) == 0) { - var info = s.AssemblyDefinition.Name.Name; - info = EncodeAotSymbol (info); - assembly_externs.Append ("extern void *mono_aot_module_").Append (info).AppendLine ("_info;"); - assembly_aot_modules.Append ("\tmono_aot_register_module (mono_aot_module_").Append (info).AppendLine ("_info);"); - } - string sname = s.FileName; - if (assembly_name != sname && IsBoundAssembly (s)) { - register_assemblies.Append ("\txamarin_open_and_register (\"").Append (sname).Append ("\", &exception_gchandle);").AppendLine (); - register_assemblies.AppendLine ("\txamarin_process_managed_exception_gchandle (exception_gchandle);"); - } - } - - if ((abi & Abi.SimulatorArchMask) == 0 || app.Embeddinator) { - var frameworks = assemblies.Where ((a) => a.BuildTarget == AssemblyBuildTarget.Framework) - .OrderBy ((a) => a.Identity, StringComparer.Ordinal); - foreach (var asm_fw in frameworks) { - var asm_name = asm_fw.Identity; - if (asm_fw.BuildTargetName == asm_name) - continue; // this is deduceable - var prefix = string.Empty; - if (!app.HasFrameworksDirectory && asm_fw.IsCodeShared) - prefix = "../../"; - var suffix = string.Empty; - if (app.IsSimulatorBuild) - suffix = "/simulator"; - assembly_location.AppendFormat ("\t{{ \"{0}\", \"{2}Frameworks/{1}.framework/MonoBundle{3}\" }},\n", asm_name, asm_fw.BuildTargetName, prefix, suffix); - assembly_location_count++; - } - } - - try { - StringBuilder sb = new StringBuilder (); - using (var sw = new StringWriter (sb)) { - sw.WriteLine ("#include \"xamarin/xamarin.h\""); - - if (assembly_location.Length > 0) { - sw.WriteLine (); - sw.WriteLine ("struct AssemblyLocation assembly_location_entries [] = {"); - sw.WriteLine (assembly_location); - sw.WriteLine ("};"); - - sw.WriteLine (); - sw.WriteLine ("struct AssemblyLocations assembly_locations = {{ {0}, assembly_location_entries }};", assembly_location_count); - } - - sw.WriteLine (); - sw.WriteLine (assembly_externs); - - sw.WriteLine ("void xamarin_register_modules_impl ()"); - sw.WriteLine ("{"); - sw.WriteLine (assembly_aot_modules); - sw.WriteLine ("}"); - sw.WriteLine (); - - sw.WriteLine ("void xamarin_register_assemblies_impl ()"); - sw.WriteLine ("{"); - sw.WriteLine (register_assemblies); - sw.WriteLine ("}"); - sw.WriteLine (); - - if (registration_methods != null) { - foreach (var method in registration_methods) { - sw.Write ("extern \"C\" void "); - sw.Write (method); - sw.WriteLine ("();"); - } - } - - // Burn in a reference to the profiling symbol so that the native linker doesn't remove it - // On iOS we can pass -u to the native linker, but that doesn't work on tvOS, where - // we're building with bitcode (even when bitcode is disabled, we still build with the - // bitcode marker, which makes the linker reject -u). - if (app.EnableProfiling) { - sw.WriteLine ("extern \"C\" { void mono_profiler_init_log (); }"); - sw.WriteLine ("typedef void (*xamarin_profiler_symbol_def)();"); - sw.WriteLine ("extern xamarin_profiler_symbol_def xamarin_profiler_symbol;"); - sw.WriteLine ("xamarin_profiler_symbol_def xamarin_profiler_symbol = NULL;"); - } - - if (app.UseInterpreter) { - sw.WriteLine ("extern \"C\" { void mono_ee_interp_init (const char *); }"); - sw.WriteLine ("extern \"C\" { void mono_icall_table_init (void); }"); - sw.WriteLine ("extern \"C\" { void mono_marshal_ilgen_init (void); }"); - sw.WriteLine ("extern \"C\" { void mono_method_builder_ilgen_init (void); }"); - sw.WriteLine ("extern \"C\" { void mono_sgen_mono_ilgen_init (void); }"); - } - - sw.WriteLine ("void xamarin_setup_impl ()"); - sw.WriteLine ("{"); - - if (app.EnableProfiling) - sw.WriteLine ("\txamarin_profiler_symbol = mono_profiler_init_log;"); - - if (app.EnableLLVMOnlyBitCode) - sw.WriteLine ("\tmono_jit_set_aot_mode (MONO_AOT_MODE_LLVMONLY);"); - else if (app.UseInterpreter) { - sw.WriteLine ("\tmono_icall_table_init ();"); - sw.WriteLine ("\tmono_marshal_ilgen_init ();"); - sw.WriteLine ("\tmono_method_builder_ilgen_init ();"); - sw.WriteLine ("\tmono_sgen_mono_ilgen_init ();"); - sw.WriteLine ("\tmono_ee_interp_init (NULL);"); - sw.WriteLine ("\tmono_jit_set_aot_mode (MONO_AOT_MODE_INTERP);"); - } else if (app.IsDeviceBuild) - sw.WriteLine ("\tmono_jit_set_aot_mode (MONO_AOT_MODE_FULL);"); - - if (assembly_location.Length > 0) - sw.WriteLine ("\txamarin_set_assembly_directories (&assembly_locations);"); - - if (registration_methods != null) { - for (int i = 0; i < registration_methods.Count; i++) { - sw.Write ("\t"); - sw.Write (registration_methods [i]); - sw.WriteLine ("();"); - } - } - - if (app.MonoNativeMode != MonoNativeMode.None) { - string mono_native_lib; - if (app.LibMonoNativeLinkMode == AssemblyBuildTarget.StaticObject) - mono_native_lib = "__Internal"; - else - mono_native_lib = app.GetLibNativeName () + ".dylib"; - sw.WriteLine (); - sw.WriteLine ($"\tmono_dllmap_insert (NULL, \"System.Native\", NULL, \"{mono_native_lib}\", NULL);"); - sw.WriteLine ($"\tmono_dllmap_insert (NULL, \"System.Security.Cryptography.Native.Apple\", NULL, \"{mono_native_lib}\", NULL);"); - sw.WriteLine ($"\tmono_dllmap_insert (NULL, \"System.Net.Security.Native\", NULL, \"{mono_native_lib}\", NULL);"); - sw.WriteLine (); - } - - if (app.EnableDebug) - sw.WriteLine ("\txamarin_gc_pump = {0};", app.DebugTrack.Value ? "TRUE" : "FALSE"); - sw.WriteLine ("\txamarin_init_mono_debug = {0};", app.PackageManagedDebugSymbols ? "TRUE" : "FALSE"); - sw.WriteLine ("\txamarin_executable_name = \"{0}\";", assembly_name); - sw.WriteLine ("\tmono_use_llvm = {0};", enable_llvm ? "TRUE" : "FALSE"); - sw.WriteLine ("\txamarin_log_level = {0};", Verbosity.ToString (CultureInfo.InvariantCulture)); - sw.WriteLine ("\txamarin_arch_name = \"{0}\";", abi.AsArchString ()); - if (!app.IsDefaultMarshalManagedExceptionMode) - sw.WriteLine ("\txamarin_marshal_managed_exception_mode = MarshalManagedExceptionMode{0};", app.MarshalManagedExceptions); - sw.WriteLine ("\txamarin_marshal_objectivec_exception_mode = MarshalObjectiveCExceptionMode{0};", app.MarshalObjectiveCExceptions); - if (app.EnableDebug) - sw.WriteLine ("\txamarin_debug_mode = TRUE;"); - if (!string.IsNullOrEmpty (app.MonoGCParams)) - sw.WriteLine ("\tsetenv (\"MONO_GC_PARAMS\", \"{0}\", 1);", app.MonoGCParams); - foreach (var kvp in app.EnvironmentVariables) - sw.WriteLine ("\tsetenv (\"{0}\", \"{1}\", 1);", kvp.Key.Replace ("\"", "\\\""), kvp.Value.Replace ("\"", "\\\"")); - sw.WriteLine ("\txamarin_supports_dynamic_registration = {0};", app.DynamicRegistrationSupported ? "TRUE" : "FALSE"); - sw.WriteLine ("}"); - sw.WriteLine (); - sw.Write ("int "); - sw.Write (app.IsWatchExtension ? "xamarin_watchextension_main" : "main"); - sw.WriteLine (" (int argc, char **argv)"); - sw.WriteLine ("{"); - sw.WriteLine ("\tNSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];"); - if (app.IsExtension) { - // the name of the executable must be the bundle id (reverse dns notation) - // but we do not want to impose that (ugly) restriction to the managed .exe / project name / ... - sw.WriteLine ("\targv [0] = (char *) \"{0}\";", Path.GetFileNameWithoutExtension (app.RootAssemblies [0])); - sw.WriteLine ("\tint rv = xamarin_main (argc, argv, XamarinLaunchModeExtension);"); - } else { - sw.WriteLine ("\tint rv = xamarin_main (argc, argv, XamarinLaunchModeApp);"); - } - sw.WriteLine ("\t[pool drain];"); - sw.WriteLine ("\treturn rv;"); - sw.WriteLine ("}"); - - string extension_main = null; - if (app.Platform == ApplePlatform.WatchOS && app.IsWatchExtension) { - // We're building a watch extension, and we have multiple scenarios, depending on the watchOS version we're executing on: - // - // * watchOS 2.0 -> 5.*: we must call a `main` function provided in the WatchKit framework. - // * watchOS 6.0 -> * : we must call a `WKExtensionMain` function provided in the WatchKit framework. - // * watchOS 7.0 -> * : The `WKExtensionMain` function uses dlsym to find any `main` functions in the - // main executable, and calls that function (otherwise WKExtensionMain will call - // UIApplicationMain and normal startup occurs) - // - // * We can't call our entry point "main", because we call WKExtensionMain, and then we run into an - // infinite loop on watchOS 7.0. So we call it xamarin_watch_extension_main. - // * The watchOS 6+ SDK helpfully provides a static library (WKExtensionMainLegacy) that has a - // WKExtensionMain function, which we use when the deployment target is earlier than watchOS 6.0. - // This means that calling WKExtensionMain works everywhere (as long as we're using the - // watchOS 6+ SDK to build; otherwise we just call "main" directly and don't link with the - // WKExtensionMainLegacy library) - - if (app.SdkVersion.Major >= 6) { - extension_main = "WKExtensionMain"; - } else { - extension_main = "main"; - } - } - - if (!string.IsNullOrEmpty (extension_main)) { - sw.WriteLine ($"extern \"C\" {{ int {extension_main} (int argc, char* argv[]); }}"); - sw.WriteLine (); - } - - sw.WriteLine (); - sw.WriteLine ("void xamarin_initialize_callbacks () __attribute__ ((constructor));"); - sw.WriteLine ("void xamarin_initialize_callbacks ()"); - sw.WriteLine ("{"); - sw.WriteLine ("\txamarin_setup = xamarin_setup_impl;"); - sw.WriteLine ("\txamarin_register_assemblies = xamarin_register_assemblies_impl;"); - sw.WriteLine ("\txamarin_register_modules = xamarin_register_modules_impl;"); - if (!string.IsNullOrEmpty (extension_main)) - sw.WriteLine ($"\txamarin_extension_main = {extension_main};"); - sw.WriteLine ("}"); - } - WriteIfDifferent (main_source, sb.ToString (), true); - } catch (ProductException) { - throw; - } catch (Exception e) { - throw new ProductException (4001, true, e, Errors.MT4001, main_source); - } - - return main_source; - } - public static void CopyAssembly (string source, string target, string target_dir = null) { if (File.Exists (target)) @@ -1175,20 +926,5 @@ namespace Xamarin.Bundler } } } - - static bool IsBoundAssembly (Assembly s) - { - if (s.IsFrameworkAssembly == true) - return false; - - AssemblyDefinition ad = s.AssemblyDefinition; - - foreach (ModuleDefinition md in ad.Modules) - foreach (TypeDefinition td in md.Types) - if (td.IsNSObject (s.Target.LinkContext)) - return true; - - return false; - } } } diff --git a/tools/mtouch/mtouch.csproj b/tools/mtouch/mtouch.csproj index 061f23721f..8ecf7d3cb7 100644 --- a/tools/mtouch/mtouch.csproj +++ b/tools/mtouch/mtouch.csproj @@ -472,6 +472,9 @@ tools\common\Driver.execution.cs + + tools\common\BitCodeMode.cs +