diff --git a/src/ObjCRuntime/DynamicRegistrar.cs b/src/ObjCRuntime/DynamicRegistrar.cs index 315587eef8..cfe0b8cbb4 100644 --- a/src/ObjCRuntime/DynamicRegistrar.cs +++ b/src/ObjCRuntime/DynamicRegistrar.cs @@ -265,7 +265,7 @@ namespace XamCore.Registrar { return SharedDynamic.GetOneAttribute (GetBasePropertyInTypeHierarchy (property) ?? property); } - protected override RegisterAttribute GetRegisterAttribute (Type type) + public override RegisterAttribute GetRegisterAttribute (Type type) { return SharedDynamic.GetOneAttribute (type); } diff --git a/src/ObjCRuntime/Registrar.cs b/src/ObjCRuntime/Registrar.cs index 82a47caff4..daec445bd0 100644 --- a/src/ObjCRuntime/Registrar.cs +++ b/src/ObjCRuntime/Registrar.cs @@ -786,7 +786,7 @@ namespace XamCore.Registrar { protected abstract ExportAttribute GetExportAttribute (TProperty property); // Return null if no attribute is found. Must check the base property (i.e. if property is overriding a property in a base class, must check the overridden property for the attribute). protected abstract ExportAttribute GetExportAttribute (TMethod method); // Return null if no attribute is found. Must check the base method (i.e. if method is overriding a method in a base class, must check the overridden method for the attribute). protected abstract Dictionary> PrepareMethodMapping (TType type); - protected abstract RegisterAttribute GetRegisterAttribute (TType type); // Return null if no attribute is found. Do not consider base types. + public abstract RegisterAttribute GetRegisterAttribute (TType type); // Return null if no attribute is found. Do not consider base types. protected abstract CategoryAttribute GetCategoryAttribute (TType type); // Return null if no attribute is found. Do not consider base types. protected abstract ConnectAttribute GetConnectAttribute (TProperty property); // Return null if no attribute is found. Do not consider inherited properties. protected abstract ProtocolAttribute GetProtocolAttribute (TType type); // Return null if no attribute is found. Do not consider base types. @@ -1043,7 +1043,7 @@ namespace XamCore.Registrar { // overridable so that descendant classes can provide a faster implementation // do not check base types. - protected virtual bool HasProtocolAttribute (TType type) + public virtual bool HasProtocolAttribute (TType type) { object dummy; return TryGetAttribute (type, Foundation, StringConstants.ProtocolAttribute, out dummy); @@ -2058,7 +2058,7 @@ namespace XamCore.Registrar { return name; } - protected string GetExportedTypeName (TType type, RegisterAttribute register_attribute) + public string GetExportedTypeName (TType type, RegisterAttribute register_attribute) { string name = null; if (register_attribute != null) { diff --git a/tests/test-libraries/Makefile b/tests/test-libraries/Makefile index e15b14fda4..e4c503176c 100644 --- a/tests/test-libraries/Makefile +++ b/tests/test-libraries/Makefile @@ -63,15 +63,15 @@ EXTRA_DEPENDENCIES = libtest.h $(GENERATED_FILES) $(Q) rm -f $$@ $$(call Q_2,AR [$(1)]) $(XCODE_DEVELOPER_ROOT)/Toolchains/XcodeDefault.xctoolchain/usr/bin/ar cru $$@ $$^ -.libs/$(1)/libtest.a: $$(foreach arch,$(3),.libs/$(1)/libtest.$$(arch).o) +.libs/$(1)/libtest.a: $$(foreach arch,$(3),.libs/$(1)/libtest.$$(arch).a) $(Q) rm -f $$@ $$(call Q_2,LIPO [$(1)]) $(XCODE_DEVELOPER_ROOT)/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo $$^ -create -output $$@ -.libs/$(1)/libtest-object.a: $$(foreach arch,$(3),.libs/$(1)/libtest-object.$$(arch).o) +.libs/$(1)/libtest-object.a: $$(foreach arch,$(3),.libs/$(1)/libtest-object.$$(arch).a) $(Q) rm -f $$@ $$(call Q_2,LIPO [$(1)]) $(XCODE_DEVELOPER_ROOT)/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo $$^ -create -output $$@ -.libs/$(1)/libtest-ar.a: $$(foreach arch,$(3),.libs/$(1)/libtest-ar.$$(arch).o) +.libs/$(1)/libtest-ar.a: $$(foreach arch,$(3),.libs/$(1)/libtest-ar.$$(arch).a) $(Q) rm -f $$@ $$(call Q_2,LIPO [$(1)]) $(XCODE_DEVELOPER_ROOT)/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo $$^ -create -output $$@ diff --git a/tools/common/Assembly.cs b/tools/common/Assembly.cs index 7f5951cb93..a57c487dfa 100644 --- a/tools/common/Assembly.cs +++ b/tools/common/Assembly.cs @@ -45,8 +45,9 @@ namespace Xamarin.Bundler { public HashSet Frameworks = new HashSet (); public HashSet WeakFrameworks = new HashSet (); public List LinkerFlags = new List (); // list of extra linker flags - public List LinkWith = new List (); // list of paths to native libraries to link with. + public List LinkWith = new List (); // list of paths to native libraries to link with, from LinkWith attributes public HashSet UnresolvedModuleReferences; + public bool HasLinkWithAttributes { get; private set; } bool? symbols_loaded; @@ -123,6 +124,7 @@ namespace Xamarin.Bundler { continue; // Let the linker remove it the attribute from the assembly + HasLinkWithAttributes = true; LinkWithAttribute linkWith = GetLinkWithAttribute (attr); string libraryName = linkWith.LibraryName; diff --git a/tools/common/CompilerFlags.cs b/tools/common/CompilerFlags.cs index 91fef3b5c5..8064b97d92 100644 --- a/tools/common/CompilerFlags.cs +++ b/tools/common/CompilerFlags.cs @@ -34,6 +34,15 @@ namespace Xamarin.Utils UnresolvedSymbols.Add (symbol); } + public void ReferenceSymbols (IEnumerable symbols) + { + if (UnresolvedSymbols == null) + UnresolvedSymbols = new HashSet (); + + foreach (var symbol in symbols) + UnresolvedSymbols.Add (symbol); + } + public void AddDefine (string define) { if (Defines == null) @@ -201,7 +210,7 @@ namespace Xamarin.Utils if (UnresolvedSymbols != null) { foreach (var symbol in UnresolvedSymbols) - args.Append (" -u _").Append (symbol); + args.Append (" -u ").Append (Driver.Quote ("_" + symbol)); } } diff --git a/tools/common/DerivedLinkContext.cs b/tools/common/DerivedLinkContext.cs new file mode 100644 index 0000000000..07932bc179 --- /dev/null +++ b/tools/common/DerivedLinkContext.cs @@ -0,0 +1,54 @@ +using System.Collections.Generic; + +using Mono.Cecil; +using Mono.Linker; + +using XamCore.Registrar; + +namespace Xamarin.Tuner +{ + public class DerivedLinkContext : LinkContext + { + internal StaticRegistrar StaticRegistrar; + Dictionary> required_symbols; + List marshal_exception_pinvokes; + Dictionary objectivec_classes; + + public List GetRequiredSymbolList (string symbol) + { + List rv; + if (!RequiredSymbols.TryGetValue (symbol, out rv)) + required_symbols [symbol] = rv = new List (); + return rv; + } + + public Dictionary> RequiredSymbols { + get { + if (required_symbols == null) + required_symbols = new Dictionary> (); + return required_symbols; + } + } + + public List MarshalExceptionPInvokes { + get { + if (marshal_exception_pinvokes == null) + marshal_exception_pinvokes = new List (); + return marshal_exception_pinvokes; + } + } + + public Dictionary ObjectiveCClasses { + get { + if (objectivec_classes == null) + objectivec_classes = new Dictionary (); + return objectivec_classes; + } + } + + public DerivedLinkContext (Pipeline pipeline, AssemblyResolver resolver) + : base (pipeline, resolver) + { + } + } +} diff --git a/tools/common/StaticRegistrar.cs b/tools/common/StaticRegistrar.cs index 6013f9956c..9f6f1b80d2 100644 --- a/tools/common/StaticRegistrar.cs +++ b/tools/common/StaticRegistrar.cs @@ -1090,7 +1090,7 @@ namespace XamCore.Registrar { return res; } - protected override RegisterAttribute GetRegisterAttribute (TypeReference type) + public override RegisterAttribute GetRegisterAttribute (TypeReference type) { CustomAttribute attrib; RegisterAttribute rv = null; diff --git a/tools/linker/MobileMarkStep.cs b/tools/linker/MobileMarkStep.cs index c955a72981..8b247a9d95 100644 --- a/tools/linker/MobileMarkStep.cs +++ b/tools/linker/MobileMarkStep.cs @@ -9,12 +9,6 @@ using Mono.Linker; using Mono.Linker.Steps; using Mono.Tuner; -#if MONOMAC -using DerivedLinkContext = MonoMac.Tuner.MonoMacLinkContext; -#else -using DerivedLinkContext = MonoTouch.Tuner.MonoTouchLinkContext; -#endif - namespace Xamarin.Linker.Steps { // XML definition files have their limits, i.e. they are good to keep stuff around unconditionnally diff --git a/tools/linker/MonoTouch.Tuner/ListExportedSymbols.cs b/tools/linker/MonoTouch.Tuner/ListExportedSymbols.cs index 2f4e0b57ea..6562113840 100644 --- a/tools/linker/MonoTouch.Tuner/ListExportedSymbols.cs +++ b/tools/linker/MonoTouch.Tuner/ListExportedSymbols.cs @@ -8,12 +8,7 @@ using Mono.Tuner; using Xamarin.Bundler; using Xamarin.Linker; - -#if MONOMAC -using DerivedLinkContext = MonoMac.Tuner.MonoMacLinkContext; -#else -using DerivedLinkContext = MonoTouch.Tuner.MonoTouchLinkContext; -#endif +using Xamarin.Tuner; namespace MonoTouch.Tuner { @@ -22,6 +17,12 @@ namespace MonoTouch.Tuner PInvokeWrapperGenerator state; bool skip_sdk_assemblies; + public DerivedLinkContext DerivedLinkContext { + get { + return (DerivedLinkContext) Context; + } + } + internal ListExportedSymbols (PInvokeWrapperGenerator state, bool skip_sdk_assemblies = false) { this.state = state; @@ -65,6 +66,12 @@ namespace MonoTouch.Tuner foreach (var method in type.Methods) ProcessMethod (method); } + + var registerAttribute = DerivedLinkContext.StaticRegistrar?.GetRegisterAttribute (type); + if (registerAttribute != null && registerAttribute.IsWrapper && !DerivedLinkContext.StaticRegistrar.HasProtocolAttribute (type)) { + var exportedName = DerivedLinkContext.StaticRegistrar.GetExportedTypeName (type, registerAttribute); + DerivedLinkContext.ObjectiveCClasses [exportedName] = type; + } } void ProcessMethod (MethodDefinition method) @@ -72,7 +79,7 @@ namespace MonoTouch.Tuner if (method.IsPInvokeImpl && method.HasPInvokeInfo) { var pinfo = method.PInvokeInfo; if (pinfo.Module.Name == "__Internal") - ((DerivedLinkContext) Context).RequiredSymbols [pinfo.EntryPoint] = method; + DerivedLinkContext.GetRequiredSymbolList (pinfo.EntryPoint).Add (method); if (state != null) { switch (pinfo.EntryPoint) { @@ -94,7 +101,7 @@ namespace MonoTouch.Tuner object symbol; // The Field attribute may have been linked away, but we've stored it in an annotation. if (property != null && Context.Annotations.GetCustomAnnotations ("ExportedFields").TryGetValue (property, out symbol)) { - ((DerivedLinkContext) Context).RequiredSymbols[(string) symbol] = property; + DerivedLinkContext.GetRequiredSymbolList ((string) symbol).Add (property); } } } diff --git a/tools/linker/MonoTouch.Tuner/ProcessExportedFields.cs b/tools/linker/MonoTouch.Tuner/ProcessExportedFields.cs index 4b418e7d4b..189b98e490 100644 --- a/tools/linker/MonoTouch.Tuner/ProcessExportedFields.cs +++ b/tools/linker/MonoTouch.Tuner/ProcessExportedFields.cs @@ -7,12 +7,6 @@ using Mono.Linker.Steps; using Mono.Tuner; using Xamarin.Linker; -#if MONOMAC -using DerivedLinkContext = MonoMac.Tuner.MonoMacLinkContext; -#else -using DerivedLinkContext = MonoTouch.Tuner.MonoTouchLinkContext; -#endif - namespace MonoTouch.Tuner { // diff --git a/tools/mmp/Makefile b/tools/mmp/Makefile index 3ba38e3ff4..0db824609f 100644 --- a/tools/mmp/Makefile +++ b/tools/mmp/Makefile @@ -117,6 +117,7 @@ mmp_sources = \ $(TOP)/tools/common/Target.cs \ $(TOP)/tools/common/Application.cs \ $(TOP)/tools/common/Assembly.cs \ + $(TOP)/tools/common/DerivedLinkContext.cs \ $(TOP)/src/Foundation/ConnectAttribute.cs \ $(TOP)/src/Foundation/ExportAttribute.cs \ $(TOP)/src/ObjCRuntime/ArgumentSemantic.cs \ diff --git a/tools/mmp/Tuning.cs b/tools/mmp/Tuning.cs index 688fe21770..cecc6839db 100644 --- a/tools/mmp/Tuning.cs +++ b/tools/mmp/Tuning.cs @@ -11,6 +11,7 @@ using MonoTouch.Tuner; using Xamarin.Bundler; using Xamarin.Linker; using Xamarin.Linker.Steps; +using Xamarin.Tuner; using Xamarin.Utils; using Mono.Cecil; @@ -54,11 +55,9 @@ namespace MonoMac.Tuner { } } - public class MonoMacLinkContext : LinkContext { + public class MonoMacLinkContext : DerivedLinkContext { Dictionary> pinvokes = new Dictionary> (); - public Dictionary RequiredSymbols = new Dictionary (); - List marshal_exception_pinvokes; public MonoMacLinkContext (Pipeline pipeline, AssemblyResolver resolver) : base (pipeline, resolver) { @@ -67,14 +66,6 @@ namespace MonoMac.Tuner { public IDictionary> PInvokeModules { get { return pinvokes; } } - - public List MarshalExceptionPInvokes { - get { - if (marshal_exception_pinvokes == null) - marshal_exception_pinvokes = new List (); - return marshal_exception_pinvokes; - } - } } class Linker { diff --git a/tools/mmp/mmp.csproj b/tools/mmp/mmp.csproj index 9f18fd4830..6dd3e44c92 100644 --- a/tools/mmp/mmp.csproj +++ b/tools/mmp/mmp.csproj @@ -292,6 +292,9 @@ external\Target.cs + + external\DerivedLinkContext.cs + external\Registrar.core.cs diff --git a/tools/mtouch/Application.cs b/tools/mtouch/Application.cs index 4dfe00d2bf..2dc1c11f16 100644 --- a/tools/mtouch/Application.cs +++ b/tools/mtouch/Application.cs @@ -1256,8 +1256,9 @@ namespace Xamarin.Bundler { "Native linking failed, undefined Objective-C class: {0}. The symbol '{1}' could not be found in any of the libraries or frameworks linked with your application.", symbol.Replace ("_OBJC_CLASS_$_", ""), symbol)); } else { - var member = target.GetMemberForSymbol (symbol.Substring (1)); - if (member != null) { + var members = target.GetMembersForSymbol (symbol.Substring (1)); + if (members != null && members.Count > 0) { + var member = members.First (); // Just report the first one. // Neither P/Invokes nor fields have IL, so we can't find the source code location. errors.Add (new MonoTouchException (5214, error, "Native linking failed, undefined symbol: {0}. " + diff --git a/tools/mtouch/Assembly.cs b/tools/mtouch/Assembly.cs index c1804567a1..1e7f0bd056 100644 --- a/tools/mtouch/Assembly.cs +++ b/tools/mtouch/Assembly.cs @@ -333,6 +333,9 @@ namespace Xamarin.Bundler { if (Target.GetEntryPoints ().ContainsKey ("UIApplicationMain")) compiler_flags.AddFramework ("UIKit"); compiler_flags.LinkWithPInvokes (abi); + + if (HasLinkWithAttributes && !App.EnableBitCode) + compiler_flags.ReferenceSymbols (Target.GetRequiredSymbols (this, true)); } link_task = new LinkTask () diff --git a/tools/mtouch/Makefile b/tools/mtouch/Makefile index 0909aaf534..3e3e8a1c71 100644 --- a/tools/mtouch/Makefile +++ b/tools/mtouch/Makefile @@ -124,6 +124,7 @@ MTOUCH_SOURCES = \ BitcodeConverter.cs \ $(TOP)/tools/common/Application.cs \ $(TOP)/tools/common/Assembly.cs \ + $(TOP)/tools/common/DerivedLinkContext.cs \ $(TOP)/tools/common/Target.cs \ $(TOP)/tools/common/CompilerFlags.cs \ $(TOP)/src/Foundation/ExportAttribute.cs \ diff --git a/tools/mtouch/Target.cs b/tools/mtouch/Target.cs index bd05551630..26a9ca24f4 100644 --- a/tools/mtouch/Target.cs +++ b/tools/mtouch/Target.cs @@ -167,8 +167,8 @@ namespace Xamarin.Bundler Frameworks.Add ("CFNetwork"); // required by xamarin_start_wwan } - Dictionary entry_points; - public IDictionary GetEntryPoints () + Dictionary> entry_points; + public IDictionary> GetEntryPoints () { if (entry_points == null) GetRequiredSymbols (); @@ -182,7 +182,7 @@ namespace Xamarin.Bundler var cache_location = Path.Combine (App.Cache.Location, "entry-points.txt"); if (cached_link || !any_assembly_updated) { - entry_points = new Dictionary (); + entry_points = new Dictionary> (); foreach (var ep in File.ReadAllLines (cache_location)) entry_points.Add (ep, null); } else { @@ -191,7 +191,7 @@ namespace Xamarin.Bundler // This happens when using the simlauncher and the msbuild tasks asked for a list // of symbols (--symbollist). In that case just produce an empty list, since the // binary shouldn't end up stripped anyway. - entry_points = new Dictionary (); + entry_points = new Dictionary> (); marshal_exception_pinvokes = new List (); } else { entry_points = LinkContext.RequiredSymbols; @@ -214,9 +214,31 @@ namespace Xamarin.Bundler return entry_points.Keys; } - public MemberReference GetMemberForSymbol (string symbol) + public IEnumerable GetRequiredSymbols (Assembly assembly, bool includeObjectiveCClasses) { - MemberReference rv = null; + if (entry_points == null) + GetRequiredSymbols (); + + foreach (var ep in entry_points) { + if (ep.Value == null) + continue; + foreach (var mr in ep.Value) { + if (mr.Module.Assembly == assembly.AssemblyDefinition) + yield return ep.Key; + } + } + + if (includeObjectiveCClasses) { + foreach (var kvp in LinkContext.ObjectiveCClasses) { + if (kvp.Value.Module.Assembly == assembly.AssemblyDefinition) + yield return $"OBJC_CLASS_$_{kvp.Key}"; + } + } + } + + public List GetMembersForSymbol (string symbol) + { + List rv = null; entry_points?.TryGetValue (symbol, out rv); return rv; } @@ -409,7 +431,7 @@ namespace Xamarin.Bundler DumpDependencies = App.LinkerDumpDependencies, RuntimeOptions = App.RuntimeOptions, MarshalNativeExceptionsState = MarshalNativeExceptionsState, - Application = App, + Target = this, }; MonoTouch.Tuner.Linker.Process (LinkerOptions, out link_context, out assemblies); @@ -804,11 +826,9 @@ namespace Xamarin.Bundler // allow the native linker to remove unused symbols (if the caller was removed by the managed linker) if (!bitcode) { - foreach (var entry in GetRequiredSymbols ()) { - // Note that we include *all* (__Internal) p/invoked symbols here - // We also include any fields from [Field] attributes. - compiler_flags.ReferenceSymbol (entry); - } + // Note that we include *all* (__Internal) p/invoked symbols here + // We also include any fields from [Field] attributes. + compiler_flags.ReferenceSymbols (GetRequiredSymbols ()); } string mainlib; diff --git a/tools/mtouch/Tuning.cs b/tools/mtouch/Tuning.cs index c714fd4506..659c2dc8a5 100644 --- a/tools/mtouch/Tuning.cs +++ b/tools/mtouch/Tuning.cs @@ -12,6 +12,7 @@ using Mono.Tuner; using Xamarin.Bundler; using Xamarin.Linker; using Xamarin.Linker.Steps; +using Xamarin.Tuner; namespace MonoTouch.Tuner { @@ -35,7 +36,8 @@ namespace MonoTouch.Tuner { internal RuntimeOptions RuntimeOptions { get; set; } public MonoTouchLinkContext LinkContext { get; set; } - public Application Application { get; set; } + public Target Target { get; set; } + public Application Application { get { return Target.App; } } public static I18nAssemblies ParseI18nAssemblies (string i18n) { @@ -101,6 +103,7 @@ namespace MonoTouch.Tuner { context.LinkSymbols = options.LinkSymbols; context.OutputDirectory = options.OutputDirectory; context.SetParameter ("debug-build", options.DebugBuild.ToString ()); + context.StaticRegistrar = options.Target.StaticRegistrar; options.LinkContext = context; @@ -223,26 +226,7 @@ namespace MonoTouch.Tuner { } } - public class MonoTouchLinkContext : LinkContext { - Dictionary required_symbols; - List marshal_exception_pinvokes; - - public Dictionary RequiredSymbols { - get { - if (required_symbols == null) - required_symbols = new Dictionary (); - return required_symbols; - } - } - - public List MarshalExceptionPInvokes { - get { - if (marshal_exception_pinvokes == null) - marshal_exception_pinvokes = new List (); - return marshal_exception_pinvokes; - } - } - + public class MonoTouchLinkContext : DerivedLinkContext { public MonoTouchLinkContext (Pipeline pipeline, AssemblyResolver resolver) : base (pipeline, resolver) { diff --git a/tools/mtouch/mtouch.cs b/tools/mtouch/mtouch.cs index 52f7a63f3f..25ac3ff70a 100644 --- a/tools/mtouch/mtouch.cs +++ b/tools/mtouch/mtouch.cs @@ -753,7 +753,7 @@ namespace Xamarin.Bundler public static string Quote (string f) { - if (f.IndexOf (' ') == -1 && f.IndexOf ('\'') == -1 && f.IndexOf (',') == -1) + if (f.IndexOf (' ') == -1 && f.IndexOf ('\'') == -1 && f.IndexOf (',') == -1 && f.IndexOf ('$') == -1) return f; var s = new StringBuilder (); diff --git a/tools/mtouch/mtouch.csproj b/tools/mtouch/mtouch.csproj index 6b40d72d0f..3f0d0091ff 100644 --- a/tools/mtouch/mtouch.csproj +++ b/tools/mtouch/mtouch.csproj @@ -262,6 +262,9 @@ external\Target.cs + + external\DerivedLinkContext.cs + external\Frameworks.cs