Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/linker.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/linker/Linker.Steps/MarkStep.cs9
-rw-r--r--src/linker/Linker.Steps/OutputStep.cs16
-rw-r--r--src/linker/Linker/Driver.cs7
-rw-r--r--src/linker/Linker/LinkContext.cs5
-rw-r--r--src/linker/Linker/PInvokeInfo.cs38
-rw-r--r--test/Mono.Linker.Tests.Cases/Interop/PInvoke/Individual/CanOutputPInvokes.cs43
-rw-r--r--test/Mono.Linker.Tests.Cases/Interop/PInvoke/Individual/Dependencies/CanOutputPInvokes_CopyAssembly.cs19
-rw-r--r--test/Mono.Linker.Tests.Cases/Interop/PInvoke/Individual/Dependencies/CanOutputPInvokes_LinkAssembly.cs10
-rw-r--r--test/Mono.Linker.Tests/Mono.Linker.Tests.csproj9
-rw-r--r--test/Mono.Linker.Tests/TestCases/Dependencies/PInvokesExpectations.json32
-rw-r--r--test/Mono.Linker.Tests/TestCases/IndividualTests.cs28
11 files changed, 213 insertions, 3 deletions
diff --git a/src/linker/Linker.Steps/MarkStep.cs b/src/linker/Linker.Steps/MarkStep.cs
index 3112fed3d..608505b60 100644
--- a/src/linker/Linker.Steps/MarkStep.cs
+++ b/src/linker/Linker.Steps/MarkStep.cs
@@ -2151,6 +2151,15 @@ namespace Mono.Linker.Steps {
{
TypeDefinition returnTypeDefinition = method.ReturnType.Resolve ();
+ if (!string.IsNullOrEmpty(_context.PInvokesListFile) && method.IsPInvokeImpl) {
+ _context.PInvokes.Add (new PInvokeInfo {
+ AssemblyName = method.DeclaringType.Module.Name,
+ EntryPoint = method.PInvokeInfo.EntryPoint,
+ FullName = method.FullName,
+ ModuleName = method.PInvokeInfo.Module.Name
+ });
+ }
+
const bool includeStaticFields = false;
if (returnTypeDefinition != null && !returnTypeDefinition.IsImport) {
MarkDefaultConstructor (returnTypeDefinition);
diff --git a/src/linker/Linker.Steps/OutputStep.cs b/src/linker/Linker.Steps/OutputStep.cs
index 2adfefc35..06d2fba8e 100644
--- a/src/linker/Linker.Steps/OutputStep.cs
+++ b/src/linker/Linker.Steps/OutputStep.cs
@@ -30,7 +30,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
-
+using System.Runtime.Serialization.Json;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Cecil.PE;
@@ -76,6 +76,7 @@ namespace Mono.Linker.Steps {
protected override void Process ()
{
CheckOutputDirectory ();
+ OutputPInvokes ();
Tracer.Finish ();
}
@@ -160,6 +161,19 @@ namespace Mono.Linker.Steps {
}
}
+ private void OutputPInvokes ()
+ {
+ if (Context.PInvokesListFile == null)
+ return;
+
+ using (var fs = File.Open (Path.Combine (Context.OutputDirectory, Context.PInvokesListFile), FileMode.Create)) {
+ Context.PInvokes.Distinct ();
+ Context.PInvokes.Sort ();
+ var jsonSerializer = new DataContractJsonSerializer (typeof (List<PInvokeInfo>));
+ jsonSerializer.WriteObject (fs, Context.PInvokes);
+ }
+ }
+
protected virtual void DeleteAssembly(AssemblyDefinition assembly, string directory)
{
var target = GetAssemblyFileName (assembly, directory);
diff --git a/src/linker/Linker/Driver.cs b/src/linker/Linker/Driver.cs
index 8807a73dd..256bd2bbc 100644
--- a/src/linker/Linker/Driver.cs
+++ b/src/linker/Linker/Driver.cs
@@ -347,6 +347,12 @@ namespace Mono.Linker {
continue;
+ case "--output-pinvokes":
+ if (!GetStringParam (token, l => context.PInvokesListFile = l))
+ return false;
+
+ continue;
+
case "--version":
Version ();
return true;
@@ -872,6 +878,7 @@ namespace Mono.Linker {
Console.WriteLine (" --ignore-descriptors Skips reading embedded descriptors (short -z). Defaults to false");
Console.WriteLine (" --keep-facades Keep assemblies with type-forwarders (short -t). Defaults to false");
Console.WriteLine (" --skip-unresolved Ignore unresolved types, methods, and assemblies. Defaults to false");
+ Console.WriteLine (" --output-pinvokes PATH Output a JSON file with all modules and entry points of the P/Invokes found");
Console.WriteLine ();
Console.WriteLine ("Linking");
diff --git a/src/linker/Linker/LinkContext.cs b/src/linker/Linker/LinkContext.cs
index be851f014..4d6231967 100644
--- a/src/linker/Linker/LinkContext.cs
+++ b/src/linker/Linker/LinkContext.cs
@@ -120,6 +120,10 @@ namespace Mono.Linker {
public List<string> Substitutions { get; private set; }
+ public List<PInvokeInfo> PInvokes { get; private set; }
+
+ public string PInvokesListFile;
+
public System.Collections.IDictionary Actions {
get { return _actions; }
}
@@ -195,6 +199,7 @@ namespace Mono.Linker {
ReflectionPatternRecorder = new LoggingReflectionPatternRecorder (this);
MarkedKnownMembers = new KnownMembers ();
StripResources = true;
+ PInvokes = new List<PInvokeInfo> ();
// See https://github.com/mono/linker/issues/612
const CodeOptimizations defaultOptimizations =
diff --git a/src/linker/Linker/PInvokeInfo.cs b/src/linker/Linker/PInvokeInfo.cs
new file mode 100644
index 000000000..e9f12fd11
--- /dev/null
+++ b/src/linker/Linker/PInvokeInfo.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Runtime.Serialization;
+
+namespace Mono.Linker
+{
+ [DataContract]
+ public class PInvokeInfo : IComparable
+ {
+ [DataMember (Name = "assembly")]
+ internal string AssemblyName { get; set; }
+
+ [DataMember (Name = "entryPoint")]
+ internal string EntryPoint { get; set; }
+
+ [DataMember (Name = "fullName")]
+ internal string FullName { get; set; }
+
+ [DataMember (Name = "moduleName")]
+ internal string ModuleName { get; set; }
+
+ public int CompareTo (object obj)
+ {
+ if (obj == null) return 1;
+
+ PInvokeInfo compareTo = obj as PInvokeInfo;
+ int compareField = string.Compare (this.AssemblyName, compareTo.AssemblyName, StringComparison.Ordinal);
+ if (compareField != 0) return compareField;
+
+ compareField = string.Compare (this.ModuleName, compareTo.ModuleName, StringComparison.Ordinal);
+ if (compareField != 0) return compareField;
+
+ compareField = string.Compare (this.FullName, compareTo.FullName, StringComparison.Ordinal);
+ if (compareField != 0) return compareField;
+
+ return string.Compare (this.EntryPoint, compareTo.EntryPoint, StringComparison.Ordinal);
+ }
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/Interop/PInvoke/Individual/CanOutputPInvokes.cs b/test/Mono.Linker.Tests.Cases/Interop/PInvoke/Individual/CanOutputPInvokes.cs
new file mode 100644
index 000000000..7cb2ed65f
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/Interop/PInvoke/Individual/CanOutputPInvokes.cs
@@ -0,0 +1,43 @@
+using System.Runtime.InteropServices;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+using Mono.Linker.Tests.Cases.Interop.PInvoke.Individual.Dependencies;
+
+namespace Mono.Linker.Tests.Cases.Interop.PInvoke.Individual
+{
+ [SetupLinkerAction ("copy", "copyassembly")]
+ [SetupLinkerAction ("link", "linkassembly")]
+ [SetupCompileBefore ("copyassembly.dll", new [] { typeof (CanOutputPInvokes_CopyAssembly) })]
+ [SetupCompileBefore ("linkassembly.dll", new [] { typeof (CanOutputPInvokes_LinkAssembly) })]
+ [SetupLinkerArgument ("--output-pinvokes", new [] { "pinvokes.json" })]
+
+ public class CanOutputPInvokes
+ {
+ public static void Main ()
+ {
+ var foo = FooEntryPoint ();
+ var bar = CustomEntryPoint ();
+ var baz = CustomEntryPoint0 ();
+
+ var copyAssembly = new CanOutputPInvokes_CopyAssembly ();
+ }
+
+ class Foo
+ {
+ public Foo ()
+ {
+ }
+ }
+
+ [DllImport ("lib")]
+ private static extern Foo FooEntryPoint ();
+
+ [DllImport ("lib", EntryPoint = "CustomEntryPoint")]
+ private static extern Foo CustomEntryPoint ();
+
+ [DllImport ("lib", EntryPoint = "CustomEntryPoint")]
+ private static extern Foo CustomEntryPoint0 ();
+
+ [DllImport ("lib")]
+ private static extern Foo UnreachableDllImport ();
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/Interop/PInvoke/Individual/Dependencies/CanOutputPInvokes_CopyAssembly.cs b/test/Mono.Linker.Tests.Cases/Interop/PInvoke/Individual/Dependencies/CanOutputPInvokes_CopyAssembly.cs
new file mode 100644
index 000000000..905cd323e
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/Interop/PInvoke/Individual/Dependencies/CanOutputPInvokes_CopyAssembly.cs
@@ -0,0 +1,19 @@
+using System.Runtime.InteropServices;
+
+namespace Mono.Linker.Tests.Cases.Interop.PInvoke.Individual.Dependencies
+{
+ public class CanOutputPInvokes_CopyAssembly
+ {
+ public CanOutputPInvokes_CopyAssembly ()
+ {
+ var foo = FooEntryPoint ();
+ var bar = CustomEntryPoint ();
+ }
+
+ [DllImport ("lib_copyassembly")]
+ private static extern CanOutputPInvokes_CopyAssembly FooEntryPoint ();
+
+ [DllImport ("lib_copyassembly", EntryPoint = "CustomEntryPoint")]
+ private static extern CanOutputPInvokes_CopyAssembly CustomEntryPoint ();
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/Interop/PInvoke/Individual/Dependencies/CanOutputPInvokes_LinkAssembly.cs b/test/Mono.Linker.Tests.Cases/Interop/PInvoke/Individual/Dependencies/CanOutputPInvokes_LinkAssembly.cs
new file mode 100644
index 000000000..1bee84379
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/Interop/PInvoke/Individual/Dependencies/CanOutputPInvokes_LinkAssembly.cs
@@ -0,0 +1,10 @@
+using System.Runtime.InteropServices;
+
+namespace Mono.Linker.Tests.Cases.Interop.PInvoke.Individual.Dependencies
+{
+ public class CanOutputPInvokes_LinkAssembly
+ {
+ [DllImport ("lib_linkassembly")]
+ private static extern CanOutputPInvokes_LinkAssembly UnreachableWhenLinked ();
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests/Mono.Linker.Tests.csproj b/test/Mono.Linker.Tests/Mono.Linker.Tests.csproj
index e4b13a53c..2e93533ee 100644
--- a/test/Mono.Linker.Tests/Mono.Linker.Tests.csproj
+++ b/test/Mono.Linker.Tests/Mono.Linker.Tests.csproj
@@ -64,6 +64,12 @@
<PackageReference Include="NUnit3TestAdapter" Version="3.10.0" />
</ItemGroup>
+ <ItemGroup>
+ <None Update="TestCases\Dependencies\PInvokesExpectations.json">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </None>
+ </ItemGroup>
+
<Target Name="RunTestsOnMono" Condition="'$(MonoBuild)' != ''">
<Exec Command="mono $(PkgNUnit_ConsoleRunner)/tools/nunit3-console.exe --result=TestResults.xml $(OutputPath)Mono.Linker.Tests.dll" />
</Target>
@@ -72,8 +78,7 @@
<!-- Arcade's custom test imports assume that we are using xunit. -->
<!-- Map the Arcade "Test" target to the "VSTest" target used by "dotnet test" -->
- <Target Name="Test"
- Condition="'$(MonoBuild)' == ''">
+ <Target Name="Test" Condition="'$(MonoBuild)' == ''">
<MSBuild Projects="$(MSBuildProjectFile)" Targets="VSTest" />
</Target>
diff --git a/test/Mono.Linker.Tests/TestCases/Dependencies/PInvokesExpectations.json b/test/Mono.Linker.Tests/TestCases/Dependencies/PInvokesExpectations.json
new file mode 100644
index 000000000..872915eca
--- /dev/null
+++ b/test/Mono.Linker.Tests/TestCases/Dependencies/PInvokesExpectations.json
@@ -0,0 +1,32 @@
+[
+ {
+ "assembly": "copyassembly.dll",
+ "entryPoint": "CustomEntryPoint",
+ "fullName": "Mono.Linker.Tests.Cases.Interop.PInvoke.Individual.Dependencies.CanOutputPInvokes_CopyAssembly Mono.Linker.Tests.Cases.Interop.PInvoke.Individual.Dependencies.CanOutputPInvokes_CopyAssembly::CustomEntryPoint()",
+ "moduleName": "lib_copyassembly"
+ },
+ {
+ "assembly": "copyassembly.dll",
+ "entryPoint": "FooEntryPoint",
+ "fullName": "Mono.Linker.Tests.Cases.Interop.PInvoke.Individual.Dependencies.CanOutputPInvokes_CopyAssembly Mono.Linker.Tests.Cases.Interop.PInvoke.Individual.Dependencies.CanOutputPInvokes_CopyAssembly::FooEntryPoint()",
+ "moduleName": "lib_copyassembly"
+ },
+ {
+ "assembly": "test.exe",
+ "entryPoint": "CustomEntryPoint",
+ "fullName": "Mono.Linker.Tests.Cases.Interop.PInvoke.Individual.CanOutputPInvokes\/Foo Mono.Linker.Tests.Cases.Interop.PInvoke.Individual.CanOutputPInvokes::CustomEntryPoint()",
+ "moduleName": "lib"
+ },
+ {
+ "assembly": "test.exe",
+ "entryPoint": "CustomEntryPoint",
+ "fullName": "Mono.Linker.Tests.Cases.Interop.PInvoke.Individual.CanOutputPInvokes\/Foo Mono.Linker.Tests.Cases.Interop.PInvoke.Individual.CanOutputPInvokes::CustomEntryPoint0()",
+ "moduleName": "lib"
+ },
+ {
+ "assembly": "test.exe",
+ "entryPoint": "FooEntryPoint",
+ "fullName": "Mono.Linker.Tests.Cases.Interop.PInvoke.Individual.CanOutputPInvokes\/Foo Mono.Linker.Tests.Cases.Interop.PInvoke.Individual.CanOutputPInvokes::FooEntryPoint()",
+ "moduleName": "lib"
+ }
+] \ No newline at end of file
diff --git a/test/Mono.Linker.Tests/TestCases/IndividualTests.cs b/test/Mono.Linker.Tests/TestCases/IndividualTests.cs
index 439caf37e..7ded3ee80 100644
--- a/test/Mono.Linker.Tests/TestCases/IndividualTests.cs
+++ b/test/Mono.Linker.Tests/TestCases/IndividualTests.cs
@@ -1,12 +1,18 @@
using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.Serialization.Json;
using System.Xml;
using Mono.Cecil;
using Mono.Linker.Tests.Cases.CommandLine.Mvid;
+using Mono.Linker.Tests.Cases.Interop.PInvoke.Individual;
using Mono.Linker.Tests.Cases.References.Individual;
using Mono.Linker.Tests.Cases.Tracing.Individual;
using Mono.Linker.Tests.Extensions;
using Mono.Linker.Tests.TestCasesRunner;
using NUnit.Framework;
+using NUnit.Framework.Internal;
namespace Mono.Linker.Tests.TestCases
{
@@ -27,6 +33,28 @@ namespace Mono.Linker.Tests.TestCases
}
[Test]
+ public void CanOutputPInvokes ()
+ {
+ var testcase = CreateIndividualCase (typeof (CanOutputPInvokes));
+ var result = Run (testcase);
+
+ var outputPath = result.OutputAssemblyPath.Parent.Combine ("pinvokes.json");
+ if (!outputPath.Exists ())
+ Assert.Fail ($"The json file with the list of all the PInvokes found by the linker is missing. Expected it to exist at {outputPath}");
+
+ var jsonSerializer = new DataContractJsonSerializer (typeof (List<PInvokeInfo>));
+
+ using (var fsActual = File.Open(outputPath, FileMode.Open))
+ using (var fsExpected = File.Open("TestCases/Dependencies/PInvokesExpectations.json", FileMode.Open)) {
+ var actual = jsonSerializer.ReadObject (fsActual) as List<PInvokeInfo>;
+ var expected = jsonSerializer.ReadObject (fsExpected) as List<PInvokeInfo>;
+ foreach (var pinvokePair in Enumerable.Zip(actual, expected, (fst, snd) => Tuple.Create(fst, snd))) {
+ Assert.That (pinvokePair.Item1.CompareTo (pinvokePair.Item2), Is.EqualTo (0));
+ }
+ }
+ }
+
+ [Test]
public void CanEnableDependenciesDump ()
{
var testcase = CreateIndividualCase (typeof (CanEnableDependenciesDump));