Skip to content

Commit 9fc93c1

Browse files
authored
Add mono/linker submodule (#778)
Add a simple project for linker, and use the built tool in CoreCLR and CoreFX. Uses a patch to add "-h" arg and reflection heuristics feature. Update baselines: removes ILLink.Tasks, adds additional versions of some existing packages.
1 parent 5d303ed commit 9fc93c1

10 files changed

+308
-10
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,6 @@
6363
[submodule "src/roslyn-tools"]
6464
path = src/roslyn-tools
6565
url = https://github.com/dotnet/roslyn-tools
66+
[submodule "src/linker"]
67+
path = src/linker
68+
url = https://github.com/mono/linker.git

dependencies.props

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,6 @@
1717
<CurrentRefXmlPath>$(MSBuildThisFileFullPath)</CurrentRefXmlPath>
1818
</PropertyGroup>
1919

20-
<!-- ILLink.Tasks package version -->
21-
<PropertyGroup>
22-
<ILLinkTasksPackage>ILLink.Tasks</ILLinkTasksPackage>
23-
<ILLinkTasksPackageVersion>0.1.5-preview-1461378</ILLinkTasksPackageVersion>
24-
</PropertyGroup>
25-
2620
<!--
2721
Packages built by ProdCon, but not source-build. These are included as prebuilts, or embedded in
2822
the product as version strings to be used by the SDK to fetch extra content.

init-tools.msbuild

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,5 @@
1111
Condition="'$(BuildToolsPackageVersion)' != ''"
1212
Version="$(BuildToolsPackageVersion)" />
1313
<PackageReference Include="Microsoft.DotNet.BuildTools.Coreclr" Version="1.0.4-prerelease" />
14-
<PackageReference Include="$(ILLinkTasksPackage)" Version="$(ILLinkTasksPackageVersion)" />
1514
</ItemGroup>
1615
</Project>
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
From d438b2ff6ae4b90424267f8c46f72d25349af76d Mon Sep 17 00:00:00 2001
2+
From: Eugene Rozenfeld <erozen@microsoft.com>
3+
Date: Tue, 4 Apr 2017 23:27:47 -0700
4+
Subject: [PATCH] Add an option to use reflection heuristics during marking
5+
step.
6+
7+
This change adds a -h option that can specify heuristics for keeping
8+
types/methods/fields that may be needed for reflection. Three simple
9+
and coarse-grained heuristic options are added initially (all are off by default):
10+
11+
1. "LdtokenTypeMethods": mark all methods of types whose token is used
12+
in an ldtoken instruction.
13+
2. "LdtokenTypeFields": mark all fields of types whose token is used
14+
in an ldtoken instruction.
15+
3. "InstanceConstructors": mark all instance constructors in types
16+
where an instance member has been marked but none of the instance
17+
constructors have been marked. (The type is likely to be instantiated via CreateInstance).
18+
19+
When -h is specified MarkStep is replaced with MarkStepWithReflectionHeuristics that
20+
derives from MarkStep. The names of heuristics are specified in a comma-separated list.
21+
More heuristics will be added over time and any subset of them can be used for a particular
22+
linker invocation.
23+
24+
https://github.com/dotnet/source-build/issues/777 tracks removing this patch.
25+
---
26+
.../MarkStepWithReflectionHeuristics.cs | 98 +++++++++++++++++++
27+
linker/Linker/Driver.cs | 22 +++++
28+
linker/Mono.Linker.csproj | 1 +
29+
3 files changed, 121 insertions(+)
30+
create mode 100644 linker/Linker.Steps/MarkStepWithReflectionHeuristics.cs
31+
32+
diff --git a/linker/Linker.Steps/MarkStepWithReflectionHeuristics.cs b/linker/Linker.Steps/MarkStepWithReflectionHeuristics.cs
33+
new file mode 100644
34+
index 0000000..3cb98b1
35+
--- /dev/null
36+
+++ b/linker/Linker.Steps/MarkStepWithReflectionHeuristics.cs
37+
@@ -0,0 +1,98 @@
38+
+using System;
39+
+using System.Collections;
40+
+using System.Collections.Generic;
41+
+
42+
+using Mono.Cecil;
43+
+using Mono.Cecil.Cil;
44+
+
45+
+namespace Mono.Linker.Steps {
46+
+
47+
+ public class MarkStepWithReflectionHeuristics : MarkStep {
48+
+
49+
+ protected ICollection<string> _reflectionHeuristics;
50+
+
51+
+ public MarkStepWithReflectionHeuristics (ICollection<string> reflectionHeuristics)
52+
+ {
53+
+ _reflectionHeuristics = reflectionHeuristics;
54+
+ }
55+
+
56+
+ protected override void MarkInstruction (Instruction instruction)
57+
+ {
58+
+ base.MarkInstruction (instruction);
59+
+
60+
+ if (instruction.OpCode == OpCodes.Ldtoken) {
61+
+ object token = instruction.Operand;
62+
+ if (token is TypeReference) {
63+
+ TypeDefinition type = ResolveTypeDefinition (GetOriginalType (((TypeReference) token)));
64+
+ if (type != null) {
65+
+ if (_reflectionHeuristics.Contains ("LdtokenTypeMethods")) {
66+
+ MarkMethods (type);
67+
+ }
68+
+ if (_reflectionHeuristics.Contains ("LdtokenTypeFields")) {
69+
+ MarkFields (type, includeStatic: true);
70+
+ }
71+
+ }
72+
+ }
73+
+ }
74+
+ }
75+
+
76+
+ protected override void DoAdditionalProcessing()
77+
+ {
78+
+ if (_reflectionHeuristics.Contains ("InstanceConstructors")) {
79+
+ ProcessConstructors ();
80+
+ }
81+
+ }
82+
+
83+
+ void ProcessConstructors()
84+
+ {
85+
+ foreach (AssemblyDefinition assembly in _context.GetAssemblies ()) {
86+
+ foreach (TypeDefinition type in assembly.MainModule.Types) {
87+
+ ProcessConstructors (type);
88+
+ }
89+
+ }
90+
+ }
91+
+
92+
+ void ProcessConstructors(TypeDefinition type)
93+
+ {
94+
+ if (Annotations.IsMarked (type)) {
95+
+
96+
+ bool hasMarkedConstructors = false;
97+
+ bool hasMarkedInstanceMember = false;
98+
+ foreach (var method in type.Methods) {
99+
+ if (Annotations.IsMarked (method)) {
100+
+ if (!method.IsStatic) {
101+
+ hasMarkedInstanceMember = true;
102+
+ }
103+
+
104+
+ if (IsInstanceConstructor (method)) {
105+
+ hasMarkedConstructors = true;
106+
+ }
107+
+
108+
+ if (hasMarkedInstanceMember && hasMarkedConstructors) {
109+
+ break;
110+
+ }
111+
+ }
112+
+ }
113+
+
114+
+ if (!hasMarkedConstructors) {
115+
+ if (!hasMarkedInstanceMember) {
116+
+ foreach (var field in type.Fields) {
117+
+ if (!field.IsStatic && Annotations.IsMarked (field)) {
118+
+ hasMarkedInstanceMember = true;
119+
+ break;
120+
+ }
121+
+ }
122+
+ }
123+
+
124+
+ if (hasMarkedInstanceMember) {
125+
+ MarkMethodsIf (type.Methods, IsInstanceConstructor);
126+
+ }
127+
+ }
128+
+
129+
+ foreach (var nestedType in type.NestedTypes) {
130+
+ ProcessConstructors (nestedType);
131+
+ }
132+
+ }
133+
+ }
134+
+ }
135+
+}
136+
diff --git a/linker/Linker/Driver.cs b/linker/Linker/Driver.cs
137+
index 8a380db..0d6a9f6 100644
138+
--- a/linker/Linker/Driver.cs
139+
+++ b/linker/Linker/Driver.cs
140+
@@ -232,6 +232,10 @@ namespace Mono.Linker {
141+
case 'v':
142+
context.KeepMembersForDebugger = bool.Parse (GetParam ());
143+
break;
144+
+ case 'h':
145+
+ ICollection<string> reflectionHeuristics = ParseReflectionHeuristics (GetParam ());
146+
+ p.ReplaceStep (typeof (MarkStep), new MarkStepWithReflectionHeuristics (reflectionHeuristics));
147+
+ break;
148+
default:
149+
Usage ("Unknown option: `" + token [1] + "'");
150+
break;
151+
@@ -340,6 +344,15 @@ namespace Mono.Linker {
152+
return assemblies;
153+
}
154+
155+
+ protected static ICollection<string> ParseReflectionHeuristics(string str)
156+
+ {
157+
+ HashSet<string> heuristics = new HashSet<string> (StringComparer.OrdinalIgnoreCase);
158+
+ string[] parts = str.Split (',');
159+
+ foreach (string part in parts)
160+
+ heuristics.Add (part);
161+
+
162+
+ return heuristics;
163+
+ }
164+
165+
AssemblyAction ParseAssemblyAction (string s)
166+
{
167+
@@ -399,6 +412,15 @@ namespace Mono.Linker {
168+
Console.WriteLine (" -b Generate debug symbols for each linked module (true or false)");
169+
Console.WriteLine (" -g Generate a new unique guid for each linked module (true or false)");
170+
Console.WriteLine (" -v Keep members needed by debugger (true or false)");
171+
+ Console.WriteLine (" -h List of reflection heuristics separated with a comma.");
172+
+ Console.WriteLine (" Supported heuristics:");
173+
+ Console.WriteLine (" LdtokenTypeMethods: mark all methods of types whose token is used");
174+
+ Console.WriteLine (" in an ldtoken instruction");
175+
+ Console.WriteLine (" LdtokenTypeFields: mark all fields of types whose token is used");
176+
+ Console.WriteLine (" in an ldtoken instruction");
177+
+ Console.WriteLine (" InstanceConstructors: mark all instance constructors in types");
178+
+ Console.WriteLine (" where an instance member has been marked but");
179+
+ Console.WriteLine (" none of the instance constructors have been marked");
180+
Console.WriteLine (" -l List of i18n assemblies to copy to the output directory");
181+
Console.WriteLine (" separated with a comma: none,all,cjk,mideast,other,rare,west");
182+
Console.WriteLine (" default is all");
183+
diff --git a/linker/Mono.Linker.csproj b/linker/Mono.Linker.csproj
184+
index d328491..4e8f143 100644
185+
--- a/linker/Mono.Linker.csproj
186+
+++ b/linker/Mono.Linker.csproj
187+
@@ -70,6 +70,7 @@
188+
<Compile Include="Linker.Steps\IStep.cs" />
189+
<Compile Include="Linker.Steps\LoadReferencesStep.cs" />
190+
<Compile Include="Linker.Steps\MarkStep.cs" />
191+
+ <Compile Include="Linker.Steps\MarkStepWithReflectionHeuristics.cs" />
192+
<Compile Include="Linker.Steps\OutputStep.cs" />
193+
<Compile Include="Linker.Steps\ResolveFromXApiStep.cs" />
194+
<Compile Include="Linker.Steps\ResolveFromAssemblyStep.cs" />
195+
--
196+
2.17.1.windows.2
197+

repos/coreclr.proj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
<OfficialBuildId>20180814-03</OfficialBuildId>
1818
</PropertyGroup>
1919

20+
<ItemGroup>
21+
<RepositoryReference Include="linker" />
22+
</ItemGroup>
23+
2024
<ItemGroup>
2125
<EnvironmentVariables Include="OfficialBuildId=$(OfficialBuildId)" />
2226
</ItemGroup>

repos/corefx.proj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,15 @@
99
<OverrideTargetRid Condition="'$(TargetOS)' == 'OSX'">osx-x64</OverrideTargetRid>
1010

1111
<BuildArguments>-$(Configuration) -buildArch=$(Platform) -portable=$(OverridePortableBuild) -BuildTests=false -PackageRid=$(OverrideTargetRid)</BuildArguments>
12-
<BuildCommand>$(ProjectDirectory)/build$(ShellExtension) $(BuildArguments) -- /p:ILLinkTrimAssembly=false /bl</BuildCommand>
12+
<BuildCommand>$(ProjectDirectory)/build$(ShellExtension) $(BuildArguments) -- /bl</BuildCommand>
1313
<BuildCommand Condition="$(Platform.Contains('arm'))">$(ArmEnvironmentVariables) $(BuildCommand)</BuildCommand>
1414
<PackagesOutput>$(ProjectDirectory)/bin/packages/$(Configuration)</PackagesOutput>
1515
<CleanCommand>$(ProjectDirectory)/clean$(ShellExtension)</CleanCommand>
1616
<OfficialBuildId>20180814-02</OfficialBuildId>
1717
</PropertyGroup>
1818

1919
<ItemGroup>
20+
<RepositoryReference Include="linker" />
2021
<RepositoryReference Include="coreclr" />
2122
<RepositoryReference Include="standard" />
2223
</ItemGroup>

repos/linker.proj

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))/dir.props" />
4+
<PropertyGroup>
5+
<!-- Package version is pinned to what CoreFX expects because CoreFX doesn't take an override property. -->
6+
<ILLinkTasksPackageId>ILLink.Tasks</ILLinkTasksPackageId>
7+
<ILLinkTasksPackageVersion>0.1.5-preview-1461378</ILLinkTasksPackageVersion>
8+
9+
<BuildCommandArgs>restore /bl:restore.binlog</BuildCommandArgs>
10+
<BuildCommandArgs>$(BuildCommandArgs) $(ProjectDirectory)corebuild/integration/linker.sln</BuildCommandArgs>
11+
12+
<!-- These are intended to be auto-detected via NuGetRestoreTargets, but it doesn't seem to work. -->
13+
<BuildCommandArgs>$(BuildCommandArgs) /p:ILLinkBuild=true</BuildCommandArgs>
14+
<BuildCommandArgs>$(BuildCommandArgs) /p:NetStandard=true</BuildCommandArgs>
15+
16+
<BuildCommand>$(DotnetToolCommand) $(BuildCommandArgs)</BuildCommand>
17+
18+
<BuildPackagesCommandArgs>pack /bl:pack.binlog</BuildPackagesCommandArgs>
19+
<BuildPackagesCommandArgs>$(BuildPackagesCommandArgs) /p:Version=$(ILLinkTasksPackageVersion)</BuildPackagesCommandArgs>
20+
<BuildPackagesCommandArgs>$(BuildPackagesCommandArgs) $(ProjectDirectory)corebuild/integration/ILLink.Tasks/ILLink.Tasks.csproj</BuildPackagesCommandArgs>
21+
<BuildPackagesCommand>$(DotnetToolCommand) $(BuildPackagesCommandArgs)</BuildPackagesCommand>
22+
23+
<PackagesOutput>$(ProjectDirectory)corebuild/integration/bin/nupkgs</PackagesOutput>
24+
25+
<RepoApiImplemented>false</RepoApiImplemented>
26+
<OrchestratedManifestBuildName>N/A</OrchestratedManifestBuildName>
27+
</PropertyGroup>
28+
29+
<!-- Extract this package into packages dir, because repos assume it's restored as a tool. -->
30+
<Target Name="ExtractLinkerPackageToCache"
31+
AfterTargets="Package">
32+
<PropertyGroup>
33+
<ILLinkTasksPackageFile>$(PackagesOutput)/$(ILLinkTasksPackageId).$(ILLinkTasksPackageVersion).nupkg</ILLinkTasksPackageFile>
34+
<ILLinkTasksPackageIdToLower>$(ILLinkTasksPackageId.ToLowerInvariant())</ILLinkTasksPackageIdToLower>
35+
</PropertyGroup>
36+
37+
<Message Importance="high" Text="Extracting $(ILLinkTasksPackageFile) to package cache..." />
38+
39+
<ZipFileExtractToDirectory SourceArchive="$(ILLinkTasksPackageFile)"
40+
DestinationDirectory="$(PackagesDir)$(ILLinkTasksPackageIdToLower)/$(ILLinkTasksPackageVersion)/"
41+
OverwriteDestination="true" />
42+
</Target>
43+
44+
<!-- Replace file includes in nuspec as recommended in the linker repo's ./corebuild/README.md -->
45+
<Target Name="ReplaceNuspecDllIncludeLines" BeforeTargets="Build">
46+
<PropertyGroup>
47+
<LinkerTasksNuspecFile>$(ProjectDirectory)corebuild/integration/ILLink.Tasks/ILLink.Tasks.nuspec</LinkerTasksNuspecFile>
48+
<NuspecFileContents>
49+
<![CDATA[<?xml version="1.0" encoding="utf-8"?>
50+
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
51+
<metadata>
52+
<id>$id$</id>
53+
<version>$version$</version>
54+
<authors>$authors$</authors>
55+
<description>$description$</description>
56+
</metadata>
57+
<files>
58+
<file src="ILLink.Tasks.targets" target="build" />
59+
<file src="ILLink.CrossGen.targets" target="build" />
60+
<file src="netcoreapp2.0/**/*.dll" target="tools/netcoreapp2.0" />
61+
</files>
62+
</package>
63+
]]>
64+
</NuspecFileContents>
65+
</PropertyGroup>
66+
67+
<WriteLinesToFile File="$(LinkerTasksNuspecFile)"
68+
Lines="$(NuspecFileContents)"
69+
Overwrite="true" />
70+
</Target>
71+
72+
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))/dir.targets" />
73+
</Project>

src/linker

Submodule linker added at 9e8bcb4

0 commit comments

Comments
 (0)