Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes for .NET 6 linker #11739

Merged
merged 19 commits into from
Jun 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 49 additions & 5 deletions dotnet/targets/Xamarin.Shared.Sdk.targets
Original file line number Diff line number Diff line change
Expand Up @@ -317,11 +317,55 @@
<!-- Mark our entry assembly as a root assembly. -->
<TrimmerRootAssembly Include="@(ResolvedFileToPublish)" Condition="'%(ResolvedFileToPublish.Filename)' == '$(AssemblyName)' And '%(ResolvedFileToPublish.Extension)' == '.dll'" />

<!-- add a custom step which inserts any other steps we need -->
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)">
<BeforeStep>MarkStep</BeforeStep>
<Type>Xamarin.SetupStep</Type>
</_TrimmerCustomSteps>
<!--
pre-mark custom steps
-->
<!-- TODO: reverse the pre-mark steps once we get the fix from https://github.com/mono/linker/pull/2082 -->
<!-- TODO: these steps should probably run after mark. -->
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Condition="'$(_LinkMode)' != 'None'" Type="Xamarin.Linker.Steps.PreMarkDispatcher" />
<!-- The final decision to remove/keep the dynamic registrar must be done before the linking step -->
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="MonoTouch.Tuner.RegistrarRemovalTrackingStep" />
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="MonoTouch.Tuner.CoreTypeMapStep" />
<!-- Load the list of assemblies loaded by the linker. -->
<!-- This would not be needed if LinkContext.GetAssemblies () was exposed to us. -->
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.CollectAssembliesStep" />
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.SetupStep" />

<!--
IMarkHandlers which run during Mark
-->
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_LinkMode)' != 'None'" Type="Xamarin.Linker.Steps.PreserveBlockCodeHandler" />
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_LinkMode)' != 'None'" Type="Xamarin.Linker.OptimizeGeneratedCodeHandler" />
<!-- MarkDispatcher substeps will run for all marked assemblies. -->
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_LinkMode)' != 'None'" Type="Xamarin.Linker.Steps.MarkDispatcher" />
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_LinkMode)' != 'None'" Type="Xamarin.Linker.Steps.PreserveSmartEnumConversionsHandler" />

<!--
post-sweep custom steps
-->
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" AfterStep="SweepStep" Condition="'$(_LinkMode)' != 'None'" Type="Xamarin.Linker.Steps.PostSweepDispatcher" />

<!--
pre-output custom steps
-->
<!-- TODO: reverse the pre-output steps once we get the fix from https://github.com/mono/linker/pull/2082 -->
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="OutputStep" Type="Xamarin.Linker.Steps.PreOutputDispatcher" />
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="OutputStep" Type="Xamarin.Linker.ExtractBindingLibrariesStep" />
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="OutputStep" Type="Xamarin.Linker.LoadNonSkippedAssembliesStep" />
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="OutputStep" Type="Xamarin.Linker.Steps.ListExportedSymbols" />

<!--
post-output steps
-->
<!-- TODO: remove AfterStep="OutputStep" from the post-output steps once we get the fix from https://github.com/mono/linker/pull/2082 -->
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" AfterStep="OutputStep" Type="Xamarin.Linker.RegistrarStep" />
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" AfterStep="OutputStep" Type="Xamarin.GenerateMainStep" />
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" AfterStep="OutputStep" Type="Xamarin.GenerateReferencesStep" />
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" AfterStep="OutputStep" Type="Xamarin.GatherFrameworksStep" />
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" AfterStep="OutputStep" Type="Xamarin.Linker.ComputeNativeBuildFlagsStep" />
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" AfterStep="OutputStep" Type="Xamarin.Linker.ComputeAOTArguments" />
<!-- Must be the last step. -->
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" AfterStep="OutputStep" Type="Xamarin.Linker.DoneStep" />

<!-- _BundlerXmlDefinitions comes from any -xml arguments to mtouch/mmp -->
<TrimmerRootDescriptor Include="@(_BundlerXmlDefinitions)" />
Expand Down
4 changes: 2 additions & 2 deletions tests/dotnet/UnitTests/ProjectTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -442,14 +442,14 @@ void AssertThatLinkerExecuted (ExecutionResult result)
{
var output = BinLog.PrintToString (result.BinLogPath);
Assert.That (output, Does.Contain ("Building target \"_RunILLink\" completely."), "Linker did not executed as expected.");
Assert.That (output, Does.Contain ("Pipeline Steps:"), "Custom steps did not run as expected.");
Assert.That (output, Does.Contain ("LinkerConfiguration:"), "Custom steps did not run as expected.");
}

void AssertThatLinkerDidNotExecute (ExecutionResult result)
{
var output = BinLog.PrintToString (result.BinLogPath);
Assert.That (output, Does.Not.Contain ("Building target \"_RunILLink\" completely."), "Linker did not executed as expected.");
Assert.That (output, Does.Not.Contain ("Pipeline Steps:"), "Custom steps did not run as expected.");
Assert.That (output, Does.Not.Contain ("LinkerConfiguration:"), "Custom steps did not run as expected.");
}

void AssertAppContents (ApplePlatform platform, string app_directory)
Expand Down
32 changes: 32 additions & 0 deletions tools/dotnet-linker/Extensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using Mono.Cecil;
using Mono.Linker;
using Mono.Tuner;
using System;

namespace Xamarin.Linker {
public static class Extensions {
public static bool Inherits (this TypeReference self, string @namespace, string name, IMetadataResolver resolver)
{
if (@namespace == null)
throw new ArgumentNullException ("namespace");
if (name == null)
throw new ArgumentNullException ("name");
if (self == null)
return false;

TypeReference current = resolver.Resolve (self);
while (current != null) {
if (current.Is (@namespace, name))
return true;
if (current.Is ("System", "Object"))
return false;

TypeDefinition td = resolver.Resolve (current);
if (td == null)
return false; // could not resolve type
current = td.BaseType;
}
return false;
}
}
}
117 changes: 0 additions & 117 deletions tools/dotnet-linker/SetupStep.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,129 +17,12 @@ public class SetupStep : ConfigurationAwareStep {
protected override string Name { get; } = "Setup";
protected override int ErrorCode { get; } = 2300;

List<IStep> _steps;
public List<IStep> Steps {
get {
if (_steps == null) {
var pipeline = typeof (LinkContext).GetProperty ("Pipeline").GetGetMethod ().Invoke (Context, null);
_steps = (List<IStep>) pipeline.GetType ().GetField ("_steps", BindingFlags.Instance | BindingFlags.NonPublic).GetValue (pipeline);
}
return _steps;
}
}

List<IMarkHandler> _markHandlers;
List<IMarkHandler> MarkHandlers {
get {
if (_markHandlers == null) {
var pipeline = typeof (LinkContext).GetProperty ("Pipeline").GetGetMethod ().Invoke (Context, null);
_markHandlers = (List<IMarkHandler>) pipeline.GetType ().GetProperty ("MarkHandlers").GetValue (pipeline);
}
return _markHandlers;
}
}

void InsertBefore (IStep step, string stepName)
{
for (int i = 0; i < Steps.Count; i++) {
if (Steps [i].GetType ().Name == stepName) {
Steps.Insert (i, step);
return;
}
}
DumpSteps ();
throw new InvalidOperationException ($"Could not insert {step} before {stepName} because {stepName} wasn't found.");
}

void InsertAfter (IStep step, string stepName)
{
for (int i = 0; i < Steps.Count;) {
if (Steps [i++].GetType ().Name == stepName) {
Steps.Insert (i, step);
return;
}
}
DumpSteps ();
throw new InvalidOperationException ($"Could not insert {step} after {stepName} because {stepName} wasn't found.");
}

protected override void TryProcess ()
{
// Don't use --custom-step to load each step, because this assembly
// is loaded into the current process once per --custom-step,
// which makes it very difficult to share state between steps.

// Load the list of assemblies loaded by the linker.
// This would not be needed of LinkContext.GetAssemblies () was exposed to us.
InsertBefore (new CollectAssembliesStep (), "MarkStep");

// the final decision to remove/keep the dynamic registrar must be done before the linking step
InsertBefore (new RegistrarRemovalTrackingStep (), "MarkStep");

var pre_mark_substeps = new DotNetSubStepDispatcher ();
InsertBefore (pre_mark_substeps, "MarkStep");

var post_sweep_substeps = new DotNetSubStepDispatcher ();
InsertAfter (post_sweep_substeps, "SweepStep");

if (Configuration.LinkMode != LinkMode.None) {
MarkHandlers.Add (new PreserveBlockCodeHandler ());

// We need to run the ApplyPreserveAttribute step even we're only linking sdk assemblies, because even
// though we know that sdk assemblies will never have Preserve attributes, user assemblies may have
// [assembly: LinkSafe] attributes, which means we treat them as sdk assemblies and those may have
// Preserve attributes.
MarkHandlers.Add (new DotNetMarkAssemblySubStepDispatcher (new ApplyPreserveAttribute ()));
MarkHandlers.Add (new OptimizeGeneratedCodeHandler ());
MarkHandlers.Add (new DotNetMarkAssemblySubStepDispatcher (new MarkNSObjects ()));
MarkHandlers.Add (new PreserveSmartEnumConversionsHandler ());

// This step could be run after Mark to avoid tracking all members:
// https://github.com/xamarin/xamarin-macios/issues/11447
pre_mark_substeps.Add (new CollectUnmarkedMembersSubStep ());
pre_mark_substeps.Add (new StoreAttributesStep ());

post_sweep_substeps.Add (new RemoveAttributesStep ());
}

InsertBefore (new ListExportedSymbols (null), "OutputStep");
InsertBefore (new LoadNonSkippedAssembliesStep (), "OutputStep");
InsertBefore (new ExtractBindingLibrariesStep (), "OutputStep");
InsertBefore (new DotNetSubStepDispatcher (new RemoveUserResourcesSubStep ()), "OutputStep");
Steps.Add (new RegistrarStep ());
Steps.Add (new GenerateMainStep ());
Steps.Add (new GenerateReferencesStep ());
Steps.Add (new GatherFrameworksStep ());
Steps.Add (new ComputeNativeBuildFlagsStep ());
Steps.Add (new ComputeAOTArguments ());
Steps.Add (new DoneStep ()); // Must be the last step.

Configuration.Write ();

if (Configuration.Verbosity > 0) {
DumpSteps ();
}

ErrorHelper.Platform = Configuration.Platform;
Directory.CreateDirectory (Configuration.ItemsDirectory);
Directory.CreateDirectory (Configuration.CacheDirectory);
}

void DumpSteps ()
{
Console.WriteLine ();
Console.WriteLine ("Pipeline Steps:");
foreach (var step in Steps) {
Console.WriteLine ($" {step}");
if (step is SubStepsDispatcher) {
var substeps = typeof (SubStepsDispatcher).GetField ("substeps", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue (step) as IEnumerable<ISubStep>;
if (substeps != null) {
foreach (var substep in substeps) {
Console.WriteLine ($" {substep}");
}
}
}
}
}
}
}
11 changes: 0 additions & 11 deletions tools/dotnet-linker/Steps/DotNetMarkAssemblyDispatcher.cs

This file was deleted.

14 changes: 14 additions & 0 deletions tools/dotnet-linker/Steps/MarkDispatcher.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Mono.Linker.Steps;
using Xamarin.Linker;

namespace Xamarin.Linker.Steps {
class MarkDispatcher : MarkSubStepsDispatcher {
public MarkDispatcher ()
: base (new BaseSubStep[] {
new ApplyPreserveAttribute (),
new MarkNSObjects ()
})
{
}
}
}
11 changes: 11 additions & 0 deletions tools/dotnet-linker/Steps/PostSweepDispatcher.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using Mono.Linker.Steps;
using Xamarin.Linker;

namespace Xamarin.Linker.Steps {
class PostSweepDispatcher : SubStepsDispatcher {
public PostSweepDispatcher ()
: base (new [] { new RemoveAttributesStep () })
{
}
}
}
14 changes: 14 additions & 0 deletions tools/dotnet-linker/Steps/PreMarkDispatcher.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Mono.Linker.Steps;
using Xamarin.Linker;

namespace Xamarin.Linker.Steps {
class PreMarkDispatcher : SubStepsDispatcher {
public PreMarkDispatcher ()
: base (new BaseSubStep [] {
new CollectUnmarkedMembersSubStep (),
new StoreAttributesStep ()
})
{
}
}
}
11 changes: 11 additions & 0 deletions tools/dotnet-linker/Steps/PreOutputDispatcher.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using Mono.Linker.Steps;
using Xamarin.Linker;

namespace Xamarin.Linker.Steps {
class PreOutputDispatcher : SubStepsDispatcher {
public PreOutputDispatcher ()
: base (new [] { new RemoveUserResourcesSubStep () })
{
}
}
}
3 changes: 3 additions & 0 deletions tools/dotnet-linker/dotnet-linker.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@
<Compile Include="..\linker\CoreOptimizeGeneratedCode.cs">
<Link>external\tools\linker\CoreOptimizeGeneratedCode.cs</Link>
</Compile>
<Compile Include="..\linker\CoreTypeMapStep.cs">
<Link>external\tools\linker\CoreTypeMapStep.cs</Link>
</Compile>
<Compile Include="..\..\src\ObjCRuntime\Registrar.cs">
<Link>external\src\ObjCRuntime\Registrar.cs</Link>
</Compile>
Expand Down
4 changes: 4 additions & 0 deletions tools/linker/ApplyPreserveAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ public class ApplyPreserveAttribute : ApplyPreserveAttributeBase {
HashSet<TypeDefinition> preserve_synonyms;
#endif

// We need to run the ApplyPreserveAttribute step even if we're only linking sdk assemblies, because even
// though we know that sdk assemblies will never have Preserve attributes, user assemblies may have
// [assembly: LinkSafe] attributes, which means we treat them as sdk assemblies and those may have
// Preserve attributes.
public override bool IsActiveFor (AssemblyDefinition assembly)
{
return Annotations.GetAction (assembly) == AssemblyAction.Link;
Expand Down
Loading