Merge pull request #1519 from rolfbjarne/fastdev-binding-projects

[mtouch] Fix linking of native libraries with incremental builds. Fixes #51548.
This commit is contained in:
Rolf Bjarne Kvinge 2017-01-19 07:52:09 +01:00 коммит произвёл GitHub
Родитель 948d3d652d 2d104f32d9
Коммит cc80b4659d
20 изменённых файлов: 144 добавлений и 77 удалений

Просмотреть файл

@ -265,7 +265,7 @@ namespace XamCore.Registrar {
return SharedDynamic.GetOneAttribute<ExportAttribute> (GetBasePropertyInTypeHierarchy (property) ?? property);
}
protected override RegisterAttribute GetRegisterAttribute (Type type)
public override RegisterAttribute GetRegisterAttribute (Type type)
{
return SharedDynamic.GetOneAttribute<RegisterAttribute> (type);
}

Просмотреть файл

@ -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<TMethod, List<TMethod>> 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) {

Просмотреть файл

@ -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 $$@

Просмотреть файл

@ -45,8 +45,9 @@ namespace Xamarin.Bundler {
public HashSet<string> Frameworks = new HashSet<string> ();
public HashSet<string> WeakFrameworks = new HashSet<string> ();
public List<string> LinkerFlags = new List<string> (); // list of extra linker flags
public List<string> LinkWith = new List<string> (); // list of paths to native libraries to link with.
public List<string> LinkWith = new List<string> (); // list of paths to native libraries to link with, from LinkWith attributes
public HashSet<ModuleReference> 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;

Просмотреть файл

@ -34,6 +34,15 @@ namespace Xamarin.Utils
UnresolvedSymbols.Add (symbol);
}
public void ReferenceSymbols (IEnumerable<string> symbols)
{
if (UnresolvedSymbols == null)
UnresolvedSymbols = new HashSet<string> ();
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));
}
}

Просмотреть файл

@ -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<string, List<MemberReference>> required_symbols;
List<MethodDefinition> marshal_exception_pinvokes;
Dictionary<string, TypeDefinition> objectivec_classes;
public List<MemberReference> GetRequiredSymbolList (string symbol)
{
List<MemberReference> rv;
if (!RequiredSymbols.TryGetValue (symbol, out rv))
required_symbols [symbol] = rv = new List<MemberReference> ();
return rv;
}
public Dictionary<string, List<MemberReference>> RequiredSymbols {
get {
if (required_symbols == null)
required_symbols = new Dictionary<string, List<MemberReference>> ();
return required_symbols;
}
}
public List<MethodDefinition> MarshalExceptionPInvokes {
get {
if (marshal_exception_pinvokes == null)
marshal_exception_pinvokes = new List<MethodDefinition> ();
return marshal_exception_pinvokes;
}
}
public Dictionary<string, TypeDefinition> ObjectiveCClasses {
get {
if (objectivec_classes == null)
objectivec_classes = new Dictionary<string, TypeDefinition> ();
return objectivec_classes;
}
}
public DerivedLinkContext (Pipeline pipeline, AssemblyResolver resolver)
: base (pipeline, resolver)
{
}
}
}

Просмотреть файл

@ -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;

Просмотреть файл

@ -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

Просмотреть файл

@ -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);
}
}
}

Просмотреть файл

@ -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 {
//

Просмотреть файл

@ -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 \

Просмотреть файл

@ -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<string, List<MethodDefinition>> pinvokes = new Dictionary<string, List<MethodDefinition>> ();
public Dictionary<string, MemberReference> RequiredSymbols = new Dictionary<string, MemberReference> ();
List<MethodDefinition> marshal_exception_pinvokes;
public MonoMacLinkContext (Pipeline pipeline, AssemblyResolver resolver) : base (pipeline, resolver)
{
@ -67,14 +66,6 @@ namespace MonoMac.Tuner {
public IDictionary<string, List<MethodDefinition>> PInvokeModules {
get { return pinvokes; }
}
public List<MethodDefinition> MarshalExceptionPInvokes {
get {
if (marshal_exception_pinvokes == null)
marshal_exception_pinvokes = new List<MethodDefinition> ();
return marshal_exception_pinvokes;
}
}
}
class Linker {

Просмотреть файл

@ -292,6 +292,9 @@
<Compile Include="..\common\Target.cs">
<Link>external\Target.cs</Link>
</Compile>
<Compile Include="..\common\DerivedLinkContext.cs">
<Link>external\DerivedLinkContext.cs</Link>
</Compile>
<Compile Include="..\..\src\ObjCRuntime\Registrar.core.cs">
<Link>external\Registrar.core.cs</Link>
</Compile>

Просмотреть файл

@ -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}. " +

Просмотреть файл

@ -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 ()

Просмотреть файл

@ -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 \

Просмотреть файл

@ -167,8 +167,8 @@ namespace Xamarin.Bundler
Frameworks.Add ("CFNetwork"); // required by xamarin_start_wwan
}
Dictionary<string, MemberReference> entry_points;
public IDictionary<string, MemberReference> GetEntryPoints ()
Dictionary<string, List<MemberReference>> entry_points;
public IDictionary<string, List<MemberReference>> 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<string, MemberReference> ();
entry_points = new Dictionary<string, List<MemberReference>> ();
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<string, MemberReference> ();
entry_points = new Dictionary<string, List<MemberReference>> ();
marshal_exception_pinvokes = new List<MethodDefinition> ();
} else {
entry_points = LinkContext.RequiredSymbols;
@ -214,9 +214,31 @@ namespace Xamarin.Bundler
return entry_points.Keys;
}
public MemberReference GetMemberForSymbol (string symbol)
public IEnumerable<string> 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<MemberReference> GetMembersForSymbol (string symbol)
{
List<MemberReference> 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;

Просмотреть файл

@ -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<string, MemberReference> required_symbols;
List<MethodDefinition> marshal_exception_pinvokes;
public Dictionary<string, MemberReference> RequiredSymbols {
get {
if (required_symbols == null)
required_symbols = new Dictionary<string, MemberReference> ();
return required_symbols;
}
}
public List<MethodDefinition> MarshalExceptionPInvokes {
get {
if (marshal_exception_pinvokes == null)
marshal_exception_pinvokes = new List<MethodDefinition> ();
return marshal_exception_pinvokes;
}
}
public class MonoTouchLinkContext : DerivedLinkContext {
public MonoTouchLinkContext (Pipeline pipeline, AssemblyResolver resolver)
: base (pipeline, resolver)
{

Просмотреть файл

@ -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 ();

Просмотреть файл

@ -262,6 +262,9 @@
<Compile Include="..\common\Target.cs">
<Link>external\Target.cs</Link>
</Compile>
<Compile Include="..\common\DerivedLinkContext.cs">
<Link>external\DerivedLinkContext.cs</Link>
</Compile>
<Compile Include="..\common\Frameworks.cs">
<Link>external\Frameworks.cs</Link>
</Compile>