diff --git a/dotnet/targets/Xamarin.Shared.Sdk.targets b/dotnet/targets/Xamarin.Shared.Sdk.targets
index b8a19b2cc698..5c76b98d6cd8 100644
--- a/dotnet/targets/Xamarin.Shared.Sdk.targets
+++ b/dotnet/targets/Xamarin.Shared.Sdk.targets
@@ -493,6 +493,7 @@
PlatformAssembly=$(_PlatformAssemblyName).dll
RelativeAppBundlePath=$(_RelativeAppBundlePath)
Registrar=$(_BundlerRegistrar)
+ RequirePInvokeWrappers=$(_RequirePInvokeWrappers)
RuntimeConfigurationFile=$(_RuntimeConfigurationFile)
SdkDevPath=$(_SdkDevPath)
SdkRootDirectory=$(_XamarinSdkRootDirectory)
diff --git a/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/ParseBundlerArgumentsTaskBase.cs b/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/ParseBundlerArgumentsTaskBase.cs
index 43f432399535..012845537ae8 100644
--- a/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/ParseBundlerArgumentsTaskBase.cs
+++ b/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/ParseBundlerArgumentsTaskBase.cs
@@ -43,6 +43,9 @@ public abstract class ParseBundlerArgumentsTaskBase : XamarinTask {
[Output]
public string Registrar { get; set; }
+ [Output]
+ public string RequirePInvokeWrappers { get; set; }
+
// This is input too
[Output]
public string NoStrip { get; set; }
@@ -141,6 +144,9 @@ public override bool Execute ()
case "package-debug-symbols":
PackageDebugSymbols = string.IsNullOrEmpty (value) ? "true" : value;
break;
+ case "require-pinvoke-wrappers":
+ RequirePInvokeWrappers = string.IsNullOrEmpty (value) ? "true" : value;
+ break;
case "registrar":
value = hasValue ? value : nextValue; // requires a value, which might be the next option
Registrar = value;
diff --git a/msbuild/Xamarin.Shared/Xamarin.Shared.targets b/msbuild/Xamarin.Shared/Xamarin.Shared.targets
index 1bf3fdcd7775..d57ca0314dfe 100644
--- a/msbuild/Xamarin.Shared/Xamarin.Shared.targets
+++ b/msbuild/Xamarin.Shared/Xamarin.Shared.targets
@@ -1780,6 +1780,7 @@ Copyright (C) 2018 Microsoft. All rights reserved.
+
diff --git a/tools/common/Application.cs b/tools/common/Application.cs
index 30d07342f922..ab12a7cb8476 100644
--- a/tools/common/Application.cs
+++ b/tools/common/Application.cs
@@ -611,8 +611,16 @@ public string Name {
get { return Path.GetFileNameWithoutExtension (AppDirectory); }
}
+ bool? requires_pinvoke_wrappers;
public bool RequiresPInvokeWrappers {
get {
+ if (requires_pinvoke_wrappers.HasValue)
+ return requires_pinvoke_wrappers.Value;
+
+ // By default this is disabled for .NET
+ if (Driver.IsDotNet)
+ return false;
+
if (Platform == ApplePlatform.MacOSX)
return false;
@@ -624,6 +632,9 @@ public bool RequiresPInvokeWrappers {
return MarshalObjectiveCExceptions == MarshalObjectiveCExceptionMode.ThrowManagedException || MarshalObjectiveCExceptions == MarshalObjectiveCExceptionMode.Abort;
}
+ set {
+ requires_pinvoke_wrappers = value;
+ }
}
public string PlatformName {
diff --git a/tools/common/Driver.cs b/tools/common/Driver.cs
index 60f725232cf9..ad8a4a8fe3c6 100644
--- a/tools/common/Driver.cs
+++ b/tools/common/Driver.cs
@@ -253,6 +253,9 @@ static bool ParseOptions (Application app, Mono.Options.OptionSet options, strin
options.Add ("rid=", "The runtime identifier we're building for", v => {
app.RuntimeIdentifier = v;
}, true /* hidden - this is only for build-time --runregistrar support */);
+ options.Add ("require-pinvoke-wrappers:", v => {
+ app.RequiresPInvokeWrappers = ParseBool (v, "--require-pinvoke-wrappers");
+ });
// Keep the ResponseFileSource option at the end.
diff --git a/tools/dotnet-linker/LinkerConfiguration.cs b/tools/dotnet-linker/LinkerConfiguration.cs
index a8363a78492a..572d72b23e78 100644
--- a/tools/dotnet-linker/LinkerConfiguration.cs
+++ b/tools/dotnet-linker/LinkerConfiguration.cs
@@ -57,6 +57,8 @@ public class LinkerConfiguration {
Dictionary> msbuild_items = new Dictionary> ();
+ internal PInvokeWrapperGenerator PInvokeWrapperGenerationState;
+
public static LinkerConfiguration GetInstance (LinkContext context, bool createIfNotFound = true)
{
if (!configurations.TryGetValue (context, out var instance) && createIfNotFound) {
@@ -231,6 +233,11 @@ public static LinkerConfiguration GetInstance (LinkContext context, bool createI
case "Registrar":
Application.ParseRegistrar (value);
break;
+ case "RequirePInvokeWrappers":
+ if (!TryParseOptionalBoolean (value, out var require_pinvoke_wrappers))
+ throw new InvalidOperationException ($"Unable to parse the {key} value: {value} in {linker_file}");
+ Application.RequiresPInvokeWrappers = require_pinvoke_wrappers.Value;
+ break;
case "RuntimeConfigurationFile":
Application.RuntimeConfigurationFile = value;
break;
@@ -401,6 +408,7 @@ public void Write ()
Console.WriteLine ($" RelativeAppBundlePath: {RelativeAppBundlePath}");
Console.WriteLine ($" Registrar: {Application.Registrar} (Options: {Application.RegistrarOptions})");
Console.WriteLine ($" RuntimeConfigurationFile: {Application.RuntimeConfigurationFile}");
+ Console.WriteLine ($" RequirePInvokeWrappers: {Application.RequiresPInvokeWrappers}");
Console.WriteLine ($" SdkDevPath: {Driver.SdkRoot}");
Console.WriteLine ($" SdkRootDirectory: {SdkRootDirectory}");
Console.WriteLine ($" SdkVersion: {SdkVersion}");
diff --git a/tools/dotnet-linker/Steps/GenerateMainStep.cs b/tools/dotnet-linker/Steps/GenerateMainStep.cs
index 5d9d7cc550dd..485f1f972fad 100644
--- a/tools/dotnet-linker/Steps/GenerateMainStep.cs
+++ b/tools/dotnet-linker/Steps/GenerateMainStep.cs
@@ -55,6 +55,24 @@ protected override void TryEndProcess ()
if (app.EnableDebug)
item.Metadata.Add ("Arguments", "-DDEBUG");
items.Add (item);
+
+ if (app.RequiresPInvokeWrappers) {
+ var state = Configuration.PInvokeWrapperGenerationState;
+ if (state.Started) {
+ // The generator is 'started' by the linker, which means it may not
+ // be started if the linker was not executed due to re-using cached results.
+ state.End ();
+ }
+ item = new MSBuildItem {
+ Include = state.SourcePath,
+ Metadata = {
+ { "Arch", abi.AsArchString () },
+ },
+ };
+ if (app.EnableDebug)
+ item.Metadata.Add ("Arguments", "-DDEBUG");
+ items.Add (item);
+ }
}
Configuration.WriteOutputForMSBuild ("_MainFile", items);
diff --git a/tools/linker/MonoTouch.Tuner/ListExportedSymbols.cs b/tools/linker/MonoTouch.Tuner/ListExportedSymbols.cs
index 465fcb2724df..193cf5117771 100644
--- a/tools/linker/MonoTouch.Tuner/ListExportedSymbols.cs
+++ b/tools/linker/MonoTouch.Tuner/ListExportedSymbols.cs
@@ -18,27 +18,56 @@ namespace Xamarin.Linker.Steps
public class ListExportedSymbols : BaseStep
{
PInvokeWrapperGenerator state;
+#if !NET
bool skip_sdk_assemblies;
+#endif
+
+ PInvokeWrapperGenerator State {
+ get {
+#if NET
+ if (state is null && DerivedLinkContext.App.RequiresPInvokeWrappers) {
+ Configuration.PInvokeWrapperGenerationState = new PInvokeWrapperGenerator () {
+ App = DerivedLinkContext.App,
+ SourcePath = Path.Combine (Configuration.CacheDirectory, "pinvokes.mm"),
+ HeaderPath = Path.Combine (Configuration.CacheDirectory, "pinvokes.h"),
+ Registrar = DerivedLinkContext.StaticRegistrar,
+ };
+ state = Configuration.PInvokeWrapperGenerationState;
+ }
+#endif
+ return state;
+ }
+ }
+
+#if NET
+ public LinkerConfiguration Configuration {
+ get {
+ return LinkerConfiguration.GetInstance (Context);
+ }
+ }
+#endif
public DerivedLinkContext DerivedLinkContext {
get {
#if NET
- return LinkerConfiguration.GetInstance (Context).DerivedLinkContext;
+ return Configuration.DerivedLinkContext;
#else
return (DerivedLinkContext) Context;
#endif
}
}
- public ListExportedSymbols () : this (null)
+#if NET
+ public ListExportedSymbols ()
{
}
-
+#else
internal ListExportedSymbols (PInvokeWrapperGenerator state, bool skip_sdk_assemblies = false)
{
this.state = state;
this.skip_sdk_assemblies = skip_sdk_assemblies;
}
+#endif
protected override void ProcessAssembly (AssemblyDefinition assembly)
{
@@ -64,23 +93,34 @@ protected override void ProcessAssembly (AssemblyDefinition assembly)
if (!hasSymbols)
return;
+ var modified = false;
foreach (var type in assembly.MainModule.Types)
- ProcessType (type);
+ modified |= ProcessType (type);
+
+ // Make sure the linker saves any changes in the assembly.
+ if (modified) {
+ var action = Context.Annotations.GetAction (assembly);
+ if (action == AssemblyAction.Copy)
+ Context.Annotations.SetAction (assembly, AssemblyAction.Save);
+ }
}
- void ProcessType (TypeDefinition type)
+ bool ProcessType (TypeDefinition type)
{
+ var modified = false;
if (type.HasNestedTypes) {
foreach (var nested in type.NestedTypes)
- ProcessType (nested);
+ modified |= ProcessType (nested);
}
if (type.HasMethods) {
foreach (var method in type.Methods)
- ProcessMethod (method);
+ modified |= ProcessMethod (method);
}
AddRequiredObjectiveCType (type);
+
+ return modified;
}
void AddRequiredObjectiveCType (TypeDefinition type)
@@ -106,20 +146,23 @@ void AddRequiredObjectiveCType (TypeDefinition type)
}
}
- void ProcessMethod (MethodDefinition method)
+ bool ProcessMethod (MethodDefinition method)
{
+ var modified = false;
+
if (method.IsPInvokeImpl && method.HasPInvokeInfo && method.PInvokeInfo != null) {
var pinfo = method.PInvokeInfo;
bool addPInvokeSymbol = false;
- if (state != null) {
+ if (State != null) {
switch (pinfo.EntryPoint) {
case "objc_msgSend":
case "objc_msgSendSuper":
case "objc_msgSend_stret":
case "objc_msgSendSuper_stret":
case "objc_msgSend_fpret":
- state.ProcessMethod (method);
+ State.ProcessMethod (method);
+ modified = true;
break;
default:
break;
@@ -181,6 +224,8 @@ void ProcessMethod (MethodDefinition method)
DerivedLinkContext.RequiredSymbols.AddField ((string) symbol).AddMember (property);
}
}
+
+ return modified;
}
}
}