From 4cc33f4d8059552eba40e9aac028bf3acabd8e38 Mon Sep 17 00:00:00 2001 From: Sebastien Pouliot Date: Wed, 20 May 2020 13:38:44 -0400 Subject: [PATCH] [src] Use `Runtime.NSLog` instead of `System.Console.WriteLine` (#8626) inside the product assemblies [1]. The latter brings a lot [2] of the BCL into the application for, eventually, ending up back to `NSLog` anyway Also include a, cecil-based, test to ensure we don't regress. [1] except for Xamarin.Mac.dll since there's a workaround for a Sierra (only) bug [2] https://gist.github.com/spouliot/c63343c1a76f4e49248be3a2c7aa25ed --- Xamarin.iOS.sln | 39 ++++++++++++++++++++++++++ src/Foundation/NSObject2.cs | 2 +- src/ObjCRuntime/Dlfcn.cs | 2 +- src/ObjCRuntime/DynamicRegistrar.cs | 2 +- src/ObjCRuntime/ErrorHelper.runtime.cs | 2 +- src/ObjCRuntime/Registrar.cs | 12 ++++++-- src/ObjCRuntime/Runtime.cs | 32 +++++++++++++++------ src/ObjCRuntime/RuntimeOptions.cs | 4 +-- src/Security/SslContext.cs | 2 +- src/UIKit/UIButton.cs | 2 +- tests/cecil-tests/Test.cs | 17 +++++++++++ 11 files changed, 97 insertions(+), 19 deletions(-) diff --git a/Xamarin.iOS.sln b/Xamarin.iOS.sln index b876b99aad..015a5f8033 100644 --- a/Xamarin.iOS.sln +++ b/Xamarin.iOS.sln @@ -27,6 +27,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "generator", "src\generator. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "generator-tests", "tests\generator\generator-tests.csproj", "{10790816-D00E-40A0-8653-2A8AB4DD33A9}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "cecil-tests", "tests\cecil-tests\cecil-tests.csproj", "{0C979851-15E9-4BB6-AD79-5F0C7DF69456}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -449,6 +451,42 @@ Global {10790816-D00E-40A0-8653-2A8AB4DD33A9}.Debug|x86.Build.0 = Debug|Any CPU {10790816-D00E-40A0-8653-2A8AB4DD33A9}.Release|x86.ActiveCfg = Release|Any CPU {10790816-D00E-40A0-8653-2A8AB4DD33A9}.Release|x86.Build.0 = Release|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.Release|Any CPU.Build.0 = Release|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.net_2_0_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.net_2_0_Debug|Any CPU.Build.0 = Debug|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.net_2_0_Release|Any CPU.ActiveCfg = Debug|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.net_2_0_Release|Any CPU.Build.0 = Debug|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.net_3_5_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.net_3_5_Debug|Any CPU.Build.0 = Debug|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.net_3_5_Release|Any CPU.ActiveCfg = Debug|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.net_3_5_Release|Any CPU.Build.0 = Debug|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.net_4_0_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.net_4_0_Debug|Any CPU.Build.0 = Debug|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.net_4_0_Release|Any CPU.ActiveCfg = Debug|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.net_4_0_Release|Any CPU.Build.0 = Debug|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.silverlight_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.silverlight_Debug|Any CPU.Build.0 = Debug|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.silverlight_Release|Any CPU.ActiveCfg = Debug|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.silverlight_Release|Any CPU.Build.0 = Debug|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.winphone_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.winphone_Debug|Any CPU.Build.0 = Debug|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.winphone_Release|Any CPU.ActiveCfg = Debug|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.winphone_Release|Any CPU.Build.0 = Debug|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.Debug|iPhone.Build.0 = Debug|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.Release|iPhone.ActiveCfg = Release|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.Release|iPhone.Build.0 = Release|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.Debug|x86.ActiveCfg = Debug|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.Debug|x86.Build.0 = Debug|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.Release|x86.ActiveCfg = Release|Any CPU + {0C979851-15E9-4BB6-AD79-5F0C7DF69456}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {208744BD-504E-47D7-9A98-1CF02454A6DA} = {2BFA13F8-B568-48BF-9A70-9D43F718C523} @@ -458,6 +496,7 @@ Global {839212D5-C25B-4284-AA96-59C3872B8184} = {2BFA13F8-B568-48BF-9A70-9D43F718C523} {9A1177F5-16E6-45DE-AA69-DC9924EC39B8} = {2BFA13F8-B568-48BF-9A70-9D43F718C523} {10790816-D00E-40A0-8653-2A8AB4DD33A9} = {2BFA13F8-B568-48BF-9A70-9D43F718C523} + {0C979851-15E9-4BB6-AD79-5F0C7DF69456} = {2BFA13F8-B568-48BF-9A70-9D43F718C523} EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution Policies = $0 diff --git a/src/Foundation/NSObject2.cs b/src/Foundation/NSObject2.cs index 33107afc56..c8607163ee 100644 --- a/src/Foundation/NSObject2.cs +++ b/src/Foundation/NSObject2.cs @@ -818,7 +818,7 @@ namespace Foundation { obj = null; cback = null; } else { - Console.Error.WriteLine ("Warning: observer object was not disposed manually with Dispose()"); + Runtime.NSLog ("Warning: observer object was not disposed manually with Dispose()"); } base.Dispose (disposing); } diff --git a/src/ObjCRuntime/Dlfcn.cs b/src/ObjCRuntime/Dlfcn.cs index 1c68b04b36..fb817bfd02 100644 --- a/src/ObjCRuntime/Dlfcn.cs +++ b/src/ObjCRuntime/Dlfcn.cs @@ -116,7 +116,7 @@ namespace ObjCRuntime { // "no cache image with name ()" if (path.IndexOf ('/') == -1){ if (!warningShown){ - Console.WriteLine ("You are using dlopen without a full path, retrying by prepending /usr/lib"); + Runtime.NSLog ("You are using dlopen without a full path, retrying by prepending /usr/lib"); warningShown = true; } diff --git a/src/ObjCRuntime/DynamicRegistrar.cs b/src/ObjCRuntime/DynamicRegistrar.cs index d469d16550..de90b2e504 100644 --- a/src/ObjCRuntime/DynamicRegistrar.cs +++ b/src/ObjCRuntime/DynamicRegistrar.cs @@ -684,7 +684,7 @@ namespace Registrar { protected override void ReportError (int code, string message, params object[] args) { - Console.WriteLine (message, args); + Runtime.NSLog (String.Format (message, args)); } Class.objc_attribute_prop [] GetPropertyAttributes (ObjCProperty property, out int count, bool isProtocol) diff --git a/src/ObjCRuntime/ErrorHelper.runtime.cs b/src/ObjCRuntime/ErrorHelper.runtime.cs index 9628a08a48..83d19016e7 100644 --- a/src/ObjCRuntime/ErrorHelper.runtime.cs +++ b/src/ObjCRuntime/ErrorHelper.runtime.cs @@ -19,7 +19,7 @@ namespace ObjCRuntime { var pe = ex as ProductException; // Show the exception - Console.Error.WriteLine (ex); + Runtime.NSLog (ex.ToString ()); // Add to list of errors if it's an error if (pe?.Error == false) { diff --git a/src/ObjCRuntime/Registrar.cs b/src/ObjCRuntime/Registrar.cs index 1ba877a35e..59f218430a 100644 --- a/src/ObjCRuntime/Registrar.cs +++ b/src/ObjCRuntime/Registrar.cs @@ -45,8 +45,14 @@ using R=ObjCRuntime.Runtime; using ProductException=ObjCRuntime.RuntimeException; #endif +#if !MTOUCH && !MMP +// static registrar needs them but they might not be marked (e.g. if System.Console is not used) +[assembly: Preserve (typeof (System.Action))] +[assembly: Preserve (typeof (System.Action))] +#endif + // -// This file cannot use any cecil code, since it's also compiled into monotouch.dll +// This file cannot use any cecil code, since it's also compiled into Xamarin.[iOS|Mac].dll // #if MONOMAC @@ -2455,8 +2461,8 @@ namespace Registrar { if (exceptions.Count > 0) { Exception ae = exceptions.Count == 1 ? exceptions [0] : new AggregateException (exceptions); -#if !MTOUCH - Console.WriteLine (ae); +#if !MTOUCH && !MMP + Runtime.NSLog (ae.ToString ()); #endif throw ae; } diff --git a/src/ObjCRuntime/Runtime.cs b/src/ObjCRuntime/Runtime.cs index e2183184f9..dff7a55326 100644 --- a/src/ObjCRuntime/Runtime.cs +++ b/src/ObjCRuntime/Runtime.cs @@ -186,16 +186,16 @@ namespace ObjCRuntime { #endif if (options->Size != Marshal.SizeOf (typeof (InitializationOptions))) { string msg = "Version mismatch between the native " + ProductName + " runtime and " + AssemblyName + ". Please reinstall " + ProductName + "."; - Console.Error.WriteLine (msg); + NSLog (msg); #if MONOMAC try { // Print out where Xamarin.Mac.dll and the native runtime was loaded from. - Console.Error.WriteLine (AssemblyName + " was loaded from {0}", typeof (nint).Assembly.Location); + NSLog (AssemblyName + " was loaded from {0}", typeof (nint).Assembly.Location); var sym2 = Dlfcn.dlsym (Dlfcn.RTLD.Default, "xamarin_initialize"); Dlfcn.Dl_info info2; if (Dlfcn.dladdr (sym2, out info2) == 0) { - Console.Error.WriteLine ("The native runtime was loaded from {0}", Marshal.PtrToStringAuto (info2.dli_fname)); + NSLog ("The native runtime was loaded from {0}", Marshal.PtrToStringAuto (info2.dli_fname)); } else if (Dlfcn.dlsym (Dlfcn.RTLD.MainOnly, "xamarin_initialize") != IntPtr.Zero) { byte[] buf = new byte [128]; int length = buf.Length; @@ -203,7 +203,7 @@ namespace ObjCRuntime { Array.Resize (ref buf, length); length = buf.Length; if (_NSGetExecutablePath (buf, ref length) != 0) { - Console.Error.WriteLine ("Could not find out where the native runtime was loaded from."); + NSLog ("Could not find out where the native runtime was loaded from."); buf = null; } } @@ -211,10 +211,10 @@ namespace ObjCRuntime { var strlength = 0; for (int i = 0; i < buf.Length && buf [i] != 0; i++) strlength++; - Console.Error.WriteLine ("The native runtime was loaded from {0}", System.Text.Encoding.UTF8.GetString (buf, 0, strlength)); + NSLog ("The native runtime was loaded from {0}", System.Text.Encoding.UTF8.GetString (buf, 0, strlength)); } } else { - Console.Error.WriteLine ("Could not find out where the native runtime was loaded from."); + NSLog ("Could not find out where the native runtime was loaded from."); } } catch { // Just ignore any exceptions, the above code is just a debug help, and if it fails, @@ -227,7 +227,7 @@ namespace ObjCRuntime { if (IntPtr.Size != sizeof (nint)) { string msg = string.Format ("Native type size mismatch between " + AssemblyName + " and the executing architecture. " + AssemblyName + " was built for {0}-bit, while the current process is {1}-bit.", IntPtr.Size == 4 ? "64" : "32", IntPtr.Size == 4 ? "32" : "64"); - Console.Error.WriteLine (msg); + NSLog (msg); throw ErrorHelper.CreateError (8010, msg); } @@ -505,7 +505,7 @@ namespace ObjCRuntime { if (register_entry_assembly) CollectReferencedAssemblies (assemblies, entry_assembly); } else { - Console.WriteLine ("Could not find the entry assembly."); + NSLog ("Could not find the entry assembly."); } #if MONOMAC @@ -1568,6 +1568,22 @@ namespace ObjCRuntime { extern static void NSLog (IntPtr format, [MarshalAs (UnmanagedType.LPStr)] string s); #endif +#if MONOMAC + [DllImport ("__Internal")] + extern static void xamarin_log (string s); + internal static void NSLog (string s) + { + if (PlatformHelper.CheckSystemVersion (10, 12)) { + Console.WriteLine (s); + } else { + xamarin_log (s); + } + } +#else + [DllImport ("__Internal", EntryPoint="xamarin_log", CharSet=CharSet.Unicode)] + internal extern static void NSLog (string s); +#endif + #if !MONOMAC [DllImport (Constants.FoundationLibrary, EntryPoint = "NSLog")] extern static void NSLog_arm64 (IntPtr format, IntPtr p2, IntPtr p3, IntPtr p4, IntPtr p5, IntPtr p6, IntPtr p7, IntPtr p8, [MarshalAs (UnmanagedType.LPStr)] string s); diff --git a/src/ObjCRuntime/RuntimeOptions.cs b/src/ObjCRuntime/RuntimeOptions.cs index feadde9208..f99690ed17 100644 --- a/src/ObjCRuntime/RuntimeOptions.cs +++ b/src/ObjCRuntime/RuntimeOptions.cs @@ -157,7 +157,7 @@ namespace ObjCRuntime { var handler_name = options?.http_message_handler; #if __WATCHOS__ if (handler_name != null && handler_name != NSUrlSessionHandlerValue) - Console.WriteLine ($"{handler_name} is not a valid HttpMessageHandler, defaulting to NSUrlSessionHandler"); + Runtime.NSLog ($"{handler_name} is not a valid HttpMessageHandler, defaulting to NSUrlSessionHandler"); return new NSUrlSessionHandler (); #else switch (handler_name) { @@ -167,7 +167,7 @@ namespace ObjCRuntime { return new NSUrlSessionHandler (); default: if (handler_name != null && handler_name != HttpClientHandlerValue) - Console.WriteLine ($"{handler_name} is not a valid HttpMessageHandler, defaulting to System.Net.Http.HttpClientHandler"); + Runtime.NSLog ($"{handler_name} is not a valid HttpMessageHandler, defaulting to System.Net.Http.HttpClientHandler"); return new HttpClientHandler (); } #endif diff --git a/src/Security/SslContext.cs b/src/Security/SslContext.cs index 4e01f5394d..a238e24e55 100644 --- a/src/Security/SslContext.cs +++ b/src/Security/SslContext.cs @@ -543,7 +543,7 @@ namespace Security { [Obsolete ("'SetSessionStrengthPolicy' is not available anymore.")] public SslStatus SetSessionStrengthPolicy (SslSessionStrengthPolicy policyStrength) { - Console.WriteLine ("SetSessionStrengthPolicy is not available anymore."); + Runtime.NSLog ("SetSessionStrengthPolicy is not available anymore."); return SslStatus.Success; } #endif diff --git a/src/UIKit/UIButton.cs b/src/UIKit/UIButton.cs index 6b7e42b7dc..c1f6756ab9 100644 --- a/src/UIKit/UIButton.cs +++ b/src/UIKit/UIButton.cs @@ -28,7 +28,7 @@ namespace UIKit { if (GetType () == typeof(UIButton)) return; - Console.WriteLine ("The UIButton subclass {0} called the (UIButtonType) constructor, but this is not allowed. Please use the default UIButton constructor from subclasses.\n{1}", GetType (), Environment.StackTrace); + Runtime.NSLog ("The UIButton subclass {0} called the (UIButtonType) constructor, but this is not allowed. Please use the default UIButton constructor from subclasses.\n{1}", GetType (), Environment.StackTrace); } } } diff --git a/tests/cecil-tests/Test.cs b/tests/cecil-tests/Test.cs index edc20ea605..85aef83a08 100644 --- a/tests/cecil-tests/Test.cs +++ b/tests/cecil-tests/Test.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using NUnit.Framework; @@ -86,5 +87,21 @@ namespace Cecil.Tests { return; // single case, no point in iterating anymore } } + + [TestCaseSource (typeof (Helper), "PlatformAssemblies")] + public void NoSystemConsoleReference (string assemblyPath) + { + if (Path.GetFileName (assemblyPath) == "Xamarin.Mac.dll") + Assert.Ignore ("Xamarin.Mac has a workaround for Sierra bug w/NSLog"); + + var assembly = Helper.GetAssembly (assemblyPath); + if (assembly == null) { + Assert.Ignore ("{assemblyPath} could not be found (might be disabled in build)"); + return; // just to help nullability + } + // this has a quite noticable impact on (small) app size + if (assembly.MainModule.TryGetTypeReference ("System.Console", out var _)) + Assert.Fail ($"{assemblyPath} has a reference to `System.Console`. Please use `Runtime.NSLog` inside the platform assemblies"); + } } }