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

ILLink cleanup #3156

Merged
merged 4 commits into from
Apr 29, 2019
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
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,8 @@ Copyright (c) .NET Foundation. All rights reserved.
<IntermediateLinkDir Condition=" !HasTrailingSlash('$(IntermediateLinkDir)') ">$(IntermediateLinkDir)\</IntermediateLinkDir>
<!-- Used to enable incremental build for the linker target. -->
<_LinkSemaphore>$(IntermediateOutputPath)Link.semaphore</_LinkSemaphore>
<!-- Disable old deps file generation logic until
https://github.com/dotnet/sdk/issues/3098 is fixed. -->
<DepsFileGenerationMode>new</DepsFileGenerationMode>
</PropertyGroup>

<ItemGroup>
<TrimmerRootDescriptors Include="$(TrimmerRootDescriptors)" />
</ItemGroup>

<!--
============================================================
_ILLink
Expand Down Expand Up @@ -77,16 +70,16 @@ Copyright (c) .NET Foundation. All rights reserved.
<UsingTask TaskName="ILLink" AssemblyFile="$(ILLinkTasksAssembly)" />
<Target Name="_RunILLink"
DependsOnTargets="_ComputeManagedAssembliesToLink"
Inputs="$(MSBuildAllProjects);@(_ManagedAssembliesToLink);@(TrimmerRootDescriptors);@(ReferencePath)"
Inputs="$(MSBuildAllProjects);@(_ManagedAssembliesToLink);@(TrimmerRootDescriptor);@(ReferencePath)"
Outputs="$(_LinkSemaphore)">

<Delete Files="@(_LinkedResolvedFileToPublishCandidates)" />
<ILLink AssemblyPaths="@(_ManagedAssembliesToLink)"
ReferenceAssemblyPaths="@(ReferencePath)"
RootAssemblyNames="@(IntermediateAssembly->'%(Filename)')"
RootDescriptorFiles="@(TrimmerRootDescriptors)"
RootDescriptorFiles="@(TrimmerRootDescriptor)"
OutputDirectory="$(IntermediateLinkDir)"
ExtraArgs="$(_ExtraTrimmerArgs) --skip-unresolved true" />
ExtraArgs="-u copyused -c copyused -l none --skip-unresolved true $(_ExtraTrimmerArgs)" />

<Touch Files="$(_LinkSemaphore)" AlwaysCreate="true" />

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using FluentAssertions;
Expand Down Expand Up @@ -103,11 +104,19 @@ public void ILLink_accepts_root_descriptor(string targetFramework)

var testProject = CreateTestProjectForILLinkTesting(targetFramework, projectName, referenceProjectName);
var testAsset = _testAssetsManager.CreateTestProject(testProject)
.WithProjectChanges(project => AddRootDescriptor(project, $"{referenceProjectName}.xml"))
.Restore(Log, testProject.Name, args: $"/p:RuntimeIdentifier={rid}");

var publishCommand = new PublishCommand(Log, Path.Combine(testAsset.TestRoot, testProject.Name));
// Inject extra arguments to prevent the linker from
// keeping the entire referenceProject assembly. The
// linker by default runs in a conservative mode that
// keeps all used assemblies, but in this case we want to
// check whether the root descriptor actually roots only
// the specified method.
var extraArgs = $"-p link {referenceProjectName}";
publishCommand.Execute($"/p:RuntimeIdentifier={rid}", $"/p:SelfContained=true", "/p:PublishTrimmed=true",
$"/p:TrimmerRootDescriptors={referenceProjectName}.xml").Should().Pass();
$"/p:_ExtraTrimmerArgs={extraArgs}", "/v:n").Should().Pass();

var publishDirectory = publishCommand.GetOutputDirectory(targetFramework: targetFramework, runtimeIdentifier: rid).FullName;
var publishedDll = Path.Combine(publishDirectory, $"{projectName}.dll");
Expand Down Expand Up @@ -161,6 +170,7 @@ public void ILLink_does_not_include_leftover_artifacts_on_second_run(string targ

var testProject = CreateTestProjectForILLinkTesting(targetFramework, projectName, referenceProjectName);
var testAsset = _testAssetsManager.CreateTestProject(testProject)
.WithProjectChanges(project => AddRootDescriptor(project, $"{referenceProjectName}.xml"))
.Restore(Log, testProject.Name, args: $"/p:RuntimeIdentifier={rid}");

var publishCommand = new PublishCommand(Log, Path.Combine(testAsset.TestRoot, testProject.Name));
Expand All @@ -172,8 +182,9 @@ public void ILLink_does_not_include_leftover_artifacts_on_second_run(string targ
var linkSemaphore = Path.Combine(intermediateDirectory, "Link.semaphore");

// Link, keeping classlib
publishCommand.Execute($"/p:RuntimeIdentifier={rid}", $"/p:SelfContained=true", "/p:PublishTrimmed=true",
$"/p:TrimmerRootDescriptors={referenceProjectName}.xml").Should().Pass();
publishCommand.Execute($"/p:RuntimeIdentifier={rid}", $"/p:SelfContained=true", "/p:PublishTrimmed=true").Should().Pass();
DateTime semaphoreFirstModifiedTime = File.GetLastWriteTimeUtc(linkSemaphore);

var publishedDllKeptFirstTimeOnly = Path.Combine(publishDirectory, $"{referenceProjectName}.dll");
var linkedDllKeptFirstTimeOnly = Path.Combine(linkedDirectory, $"{referenceProjectName}.dll");
File.Exists(linkedDllKeptFirstTimeOnly).Should().BeTrue();
Expand All @@ -182,12 +193,18 @@ public void ILLink_does_not_include_leftover_artifacts_on_second_run(string targ
// Delete kept dll from publish output (works around lack of incremental publish)
File.Delete(publishedDllKeptFirstTimeOnly);

// Modify input timestamp to force a re-build and re-link
// Remove root descriptor to change the linker behavior.
WaitForUtcNowToAdvance();
File.SetLastWriteTimeUtc(Path.Combine(testAsset.TestRoot, testProject.Name, $"{projectName}.cs"), DateTime.UtcNow);
// File.SetLastWriteTimeUtc(Path.Combine(testAsset.TestRoot, testProject.Name, $"{projectName}.cs"), DateTime.UtcNow);
testAsset = testAsset.WithProjectChanges(project => RemoveRootDescriptor(project));

// Link, discarding classlib
publishCommand.Execute($"/p:RuntimeIdentifier={rid}", $"/p:SelfContained=true", "/p:PublishTrimmed=true").Should().Pass();
DateTime semaphoreSecondModifiedTime = File.GetLastWriteTimeUtc(linkSemaphore);

// Check that the linker actually ran again
semaphoreFirstModifiedTime.Should().NotBe(semaphoreSecondModifiedTime);

File.Exists(linkedDllKeptFirstTimeOnly).Should().BeFalse();
File.Exists(publishedDllKeptFirstTimeOnly).Should().BeFalse();

Expand Down Expand Up @@ -270,6 +287,25 @@ private TestPackageReference GetPackageReference(TestProject project)
return new TestPackageReference(project.Name, "1.0.0", pack.GetNuGetPackage(project.Name));
}

private void AddRootDescriptor(XDocument project, string rootDescriptorFileName)
{
var ns = project.Root.Name.Namespace;

var itemGroup = new XElement(ns + "ItemGroup");
project.Root.Add(itemGroup);
itemGroup.Add(new XElement(ns + "TrimmerRootDescriptor",
new XAttribute("Include", rootDescriptorFileName)));
}

private void RemoveRootDescriptor(XDocument project)
{
var ns = project.Root.Name.Namespace;

project.Root.Elements(ns + "ItemGroup")
.Where(ig => ig.Elements(ns + "TrimmerRootDescriptor").Any())
.First().Remove();
}

private TestProject CreateTestProjectForILLinkTesting(string targetFramework, string mainProjectName, string referenceProjectName)
{
var referenceProject = new TestProject()
Expand Down