diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 8de744c8301a..00824e505453 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -125,9 +125,9 @@
https://github.com/microsoft/vstest
b1452a516a80672fa814f4ebdf2151c0875d0b20
-
+
https://github.com/dotnet/linker
- ef2d0f25b72469b55925251a79f12bcbf98644bf
+ b6f1fb4d67f6aab530382e1973b898ba858709e0
@@ -135,9 +135,9 @@
206dccb7945aaa3f26599fbe742de9022ca7ef91
-
+
https://github.com/dotnet/linker
- ef2d0f25b72469b55925251a79f12bcbf98644bf
+ b6f1fb4d67f6aab530382e1973b898ba858709e0
https://github.com/dotnet/runtime
diff --git a/eng/Versions.props b/eng/Versions.props
index 9dc41a46869f..283931ef70a3 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -83,7 +83,7 @@
- 7.0.100-1.22354.1
+ 7.0.100-1.22357.2
$(MicrosoftNETILLinkTasksPackageVersion)
diff --git a/src/BlazorWasmSdk/Targets/Microsoft.NET.Sdk.BlazorWebAssembly.Current.props b/src/BlazorWasmSdk/Targets/Microsoft.NET.Sdk.BlazorWebAssembly.Current.props
index 58ee0bcdac04..b7f228be4019 100644
--- a/src/BlazorWasmSdk/Targets/Microsoft.NET.Sdk.BlazorWebAssembly.Current.props
+++ b/src/BlazorWasmSdk/Targets/Microsoft.NET.Sdk.BlazorWebAssembly.Current.props
@@ -29,7 +29,7 @@ Copyright (c) .NET Foundation. All rights reserved.
true
- link
+ partial
false
diff --git a/src/Tests/Microsoft.NET.Build.Tests/ReferenceExeTests.cs b/src/Tests/Microsoft.NET.Build.Tests/ReferenceExeTests.cs
index ee2195b22e6c..940b231fa79e 100644
--- a/src/Tests/Microsoft.NET.Build.Tests/ReferenceExeTests.cs
+++ b/src/Tests/Microsoft.NET.Build.Tests/ReferenceExeTests.cs
@@ -29,6 +29,10 @@ public ReferenceExeTests(ITestOutputHelper log) : base(log)
private bool TestWithPublish { get; set; } = false;
+ private bool PublishTrimmed = false;
+
+ private bool ReferenceExeInCode = false;
+
private TestProject MainProject { get; set; }
private TestProject ReferencedProject { get; set; }
@@ -44,10 +48,31 @@ private void CreateProjects()
};
MainProject.PackageReferences.Add(new TestPackageReference("Humanizer", "2.8.26"));
- MainProject.SourceFiles["Program.cs"] = @"using Humanizer; System.Console.WriteLine(""MainProject"".Humanize());";
+ var mainProjectSrc = @"
+using System;
+using Humanizer;
+Console.WriteLine(""MainProject"".Humanize());";
+
+ if (PublishTrimmed)
+ {
+ MainProject.AdditionalProperties["PublishTrimmed"] = "true";
+
+ // If we're fully trimming, unless the trimmed project contains an explicit reference in code
+ // to the referenced project, it will get trimmed away
+ if (ReferenceExeInCode)
+ {
+ mainProjectSrc += @"
+// Always false, but the trimmer doesn't know that
+if (string.Empty.Length > 0)
+{
+ ReferencedExeProgram.Main();
+}";
+
+ }
+ }
- // By default we don't create the app host on Mac for FDD. For these tests, we want to create it everywhere
- MainProject.AdditionalProperties["UseAppHost"] = "true";
+
+ MainProject.SourceFiles["Program.cs"] = mainProjectSrc;
if (MainSelfContained)
{
@@ -62,8 +87,6 @@ private void CreateProjects()
IsExe = true,
};
- ReferencedProject.AdditionalProperties["UseAppHost"] = "true";
-
if (ReferencedSelfContained)
{
ReferencedProject.RuntimeIdentifier = EnvironmentInfo.GetCompatibleRid();
@@ -71,7 +94,15 @@ private void CreateProjects()
// Use a lower version of a library in the referenced project
ReferencedProject.PackageReferences.Add(new TestPackageReference("Humanizer", "2.7.9"));
- ReferencedProject.SourceFiles["Program.cs"] = @"using Humanizer; System.Console.WriteLine(""ReferencedProject"".Humanize());";
+ ReferencedProject.SourceFiles["Program.cs"] = @"
+using Humanizer;
+public class ReferencedExeProgram
+{
+ public static void Main()
+ {
+ System.Console.WriteLine(""ReferencedProject"".Humanize());
+ }
+}";
MainProject.ReferencedProjects.Add(ReferencedProject);
}
@@ -122,11 +153,23 @@ private void RunTest(string buildFailureCode = null, [CallerMemberName] string c
var referencedExeResult = new RunExeCommand(Log, referencedExePath)
.Execute();
- referencedExeResult
- .Should()
- .Pass()
- .And
- .HaveStdOut("Referenced project");
+ // If we're trimming and didn't reference the exe in source we would expect it to be trimmed from the output
+ if (PublishTrimmed && !ReferenceExeInCode)
+ {
+ referencedExeResult
+ .Should()
+ .Fail()
+ .And
+ .HaveStdErrContaining("The application to execute does not exist");
+ }
+ else
+ {
+ referencedExeResult
+ .Should()
+ .Pass()
+ .And
+ .HaveStdOut("Referenced project");
+ }
}
else
{
@@ -238,25 +281,20 @@ public void ReferencedExeCanRunWhenPublished(bool selfContained)
RunTest();
}
- [Fact]
- public void ReferencedExeCanRunWhenPublishedWithTrimming()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void ReferencedExeCanRunWhenPublishedWithTrimming(bool referenceExeInCode)
{
MainSelfContained = true;
ReferencedSelfContained = true;
TestWithPublish = true;
+ PublishTrimmed = true;
+ ReferenceExeInCode = referenceExeInCode;
CreateProjects();
- if (MainSelfContained)
- {
- MainProject.AdditionalProperties["PublishTrimmed"] = "True";
- }
- if (ReferencedSelfContained)
- {
- ReferencedProject.AdditionalProperties["PublishTrimmed"] = "True";
- }
-
RunTest();
}
diff --git a/src/Tests/Microsoft.NET.Publish.Tests/GivenThatWeWantToRunILLink.cs b/src/Tests/Microsoft.NET.Publish.Tests/GivenThatWeWantToRunILLink.cs
index d4bd36d1d608..449e626529ce 100644
--- a/src/Tests/Microsoft.NET.Publish.Tests/GivenThatWeWantToRunILLink.cs
+++ b/src/Tests/Microsoft.NET.Publish.Tests/GivenThatWeWantToRunILLink.cs
@@ -23,6 +23,7 @@
using Xunit;
using Xunit.Abstractions;
using static Microsoft.NET.Publish.Tests.PublishTestUtils;
+using System.Security.Permissions;
namespace Microsoft.NET.Publish.Tests
{
@@ -187,6 +188,10 @@ public void PrepareForILLink_can_set_TrimMode(string targetFramework)
[RequiresMSBuildVersionTheory("17.0.0.32901")]
[InlineData("net5.0", "link")]
[InlineData(ToolsetInfo.CurrentTargetFramework, "copyused")]
+ [InlineData("net6.0", "full")]
+ [InlineData(ToolsetInfo.CurrentTargetFramework, "full")]
+ [InlineData("net6.0", "partial")]
+ [InlineData(ToolsetInfo.CurrentTargetFramework, "partial")]
public void ILLink_respects_global_TrimMode(string targetFramework, string trimMode)
{
var projectName = "HelloWorld";
@@ -210,7 +215,7 @@ public void ILLink_respects_global_TrimMode(string targetFramework, string trimM
File.Exists(publishedDll).Should().BeTrue();
File.Exists(isTrimmableDll).Should().BeTrue();
DoesImageHaveMethod(isTrimmableDll, "UnusedMethodToRoot").Should().BeTrue();
- if (trimMode == "link") {
+ if (trimMode is "link" or "full" or "partial") {
// Check that the assembly was trimmed at the member level
DoesImageHaveMethod(isTrimmableDll, "UnusedMethod").Should().BeFalse();
} else {
@@ -269,7 +274,8 @@ public void ILLink_respects_TrimmableAssembly(string targetFramework)
}
[RequiresMSBuildVersionTheory("17.0.0.32901")]
- [MemberData(nameof(Net6Plus), MemberType = typeof(PublishTestUtils))]
+ [InlineData("net6.0")]
+ [InlineData("net7.0")]
public void ILLink_respects_IsTrimmable_attribute(string targetFramework)
{
string projectName = "HelloWorld";
@@ -287,7 +293,16 @@ public void ILLink_respects_IsTrimmable_attribute(string targetFramework)
// Only unused non-trimmable assemblies are kept
File.Exists(unusedTrimmableDll).Should().BeFalse();
- DoesImageHaveMethod(unusedNonTrimmableDll, "UnusedMethod").Should().BeTrue();
+ if (targetFramework == "net6.0")
+ {
+ // In net6.0 the default is to keep assemblies not marked trimmable
+ DoesImageHaveMethod(unusedNonTrimmableDll, "UnusedMethod").Should().BeTrue();
+ }
+ else
+ {
+ // In net7.0+ the default is to keep assemblies not marked trimmable
+ File.Exists(unusedNonTrimmableDll).Should().BeFalse();
+ }
}
[RequiresMSBuildVersionTheory("17.0.0.32901")]
@@ -298,6 +313,7 @@ public void ILLink_IsTrimmable_metadata_can_override_attribute(string targetFram
var rid = EnvironmentInfo.GetCompatibleRid(targetFramework);
var testProject = CreateTestProjectWithIsTrimmableAttributes(targetFramework, projectName);
var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework)
+ .WithProjectChanges(project => SetGlobalTrimMode(project, "partial"))
.WithProjectChanges(project => SetMetadata(project, "UnusedTrimmableAssembly", "IsTrimmable", "false"))
.WithProjectChanges(project => SetMetadata(project, "UnusedNonTrimmableAssembly", "IsTrimmable", "true"));
@@ -316,7 +332,7 @@ public void ILLink_IsTrimmable_metadata_can_override_attribute(string targetFram
}
[RequiresMSBuildVersionTheory("17.0.0.32901")]
- [MemberData(nameof(Net6Plus), MemberType = typeof(PublishTestUtils))]
+ [InlineData("net6.0")]
public void ILLink_TrimMode_applies_to_IsTrimmable_assemblies(string targetFramework)
{
string projectName = "HelloWorld";
@@ -343,6 +359,47 @@ public void ILLink_TrimMode_applies_to_IsTrimmable_assemblies(string targetFrame
DoesImageHaveMethod(unusedNonTrimmableDll, "UnusedMethod").Should().BeTrue();
}
+ [RequiresMSBuildVersionTheory("17.0.0.32901")]
+ [InlineData(ToolsetInfo.CurrentTargetFramework, "full")]
+ [InlineData(ToolsetInfo.CurrentTargetFramework, "partial")]
+ public void ILLink_TrimMode_new_options(string targetFramework, string trimMode)
+ {
+ string projectName = "HelloWorld";
+ var rid = EnvironmentInfo.GetCompatibleRid(targetFramework);
+ var testProject = CreateTestProjectWithIsTrimmableAttributes(targetFramework, projectName);
+ var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework + trimMode)
+ .WithProjectChanges(project => SetGlobalTrimMode(project, trimMode));
+
+ var publishCommand = new PublishCommand(testAsset);
+ publishCommand.Execute($"/p:RuntimeIdentifier={rid}", "-bl").Should().Pass();
+
+ var publishDirectory = publishCommand.GetOutputDirectory(targetFramework: targetFramework, runtimeIdentifier: rid).FullName;
+
+ var trimmableDll = Path.Combine(publishDirectory, "TrimmableAssembly.dll");
+ var nonTrimmableDll = Path.Combine(publishDirectory, "NonTrimmableAssembly.dll");
+ var unusedTrimmableDll = Path.Combine(publishDirectory, "UnusedTrimmableAssembly.dll");
+ var unusedNonTrimmableDll = Path.Combine(publishDirectory, "UnusedNonTrimmableAssembly.dll");
+
+ // Trimmable assemblies are trimmed at member level
+ DoesImageHaveMethod(trimmableDll, "UnusedMethod").Should().BeFalse();
+ DoesImageHaveMethod(trimmableDll, "UsedMethod").Should().BeTrue();
+ File.Exists(unusedTrimmableDll).Should().BeFalse();
+ if (trimMode is "full")
+ {
+ DoesImageHaveMethod(nonTrimmableDll, "UnusedMethod").Should().BeFalse();
+ File.Exists(unusedNonTrimmableDll).Should().BeFalse();
+ }
+ else if (trimMode is "partial")
+ {
+ DoesImageHaveMethod(nonTrimmableDll, "UnusedMethod").Should().BeTrue();
+ DoesImageHaveMethod(unusedNonTrimmableDll, "UnusedMethod").Should().BeTrue();
+ }
+ else
+ {
+ Assert.True(false, "unexpected value");
+ }
+ }
+
[RequiresMSBuildVersionTheory("17.0.0.32901")]
[InlineData(ToolsetInfo.CurrentTargetFramework)]
public void ILLink_can_set_TrimmerDefaultAction(string targetFramework)
@@ -868,8 +925,10 @@ public void ILLink_runs_incrementally(string targetFramework)
}
[RequiresMSBuildVersionTheory("17.0.0.32901")]
- [MemberData(nameof(SupportedTfms), MemberType = typeof(PublishTestUtils))]
- public void ILLink_defaults_keep_nonframework(string targetFramework)
+ [InlineData("netcoreapp3.1")]
+ [InlineData("net5.0")]
+ [InlineData("net6.0")]
+ public void ILLink_old_defaults_keep_nonframework(string targetFramework)
{
var projectName = "HelloWorld";
var referenceProjectName = "ClassLibForILLink";
@@ -903,6 +962,42 @@ public void ILLink_defaults_keep_nonframework(string targetFramework)
DoesDepsFileHaveAssembly(depsFile, unusedFrameworkAssembly).Should().BeFalse();
}
+ [RequiresMSBuildVersionFact("17.0.0.32901")]
+ public void ILLink_net7_defaults_trim_nonframework()
+ {
+ string targetFramework = "net7.0";
+ var projectName = "HelloWorld";
+ var referenceProjectName = "ClassLibForILLink";
+ var rid = EnvironmentInfo.GetCompatibleRid(targetFramework);
+
+ var testProject = CreateTestProjectForILLinkTesting(targetFramework, projectName, referenceProjectName);
+ var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework);
+
+ var publishCommand = new PublishCommand(testAsset);
+ publishCommand.Execute("/v:n", $"/p:RuntimeIdentifier={rid}", "/p:PublishTrimmed=true").Should().Pass();
+
+ var publishDirectory = publishCommand.GetOutputDirectory(targetFramework: targetFramework, runtimeIdentifier: rid).FullName;
+ var intermediateDirectory = publishCommand.GetIntermediateDirectory(targetFramework: targetFramework, runtimeIdentifier: rid).FullName;
+ var linkedDirectory = Path.Combine(intermediateDirectory, "linked");
+
+ Directory.Exists(linkedDirectory).Should().BeTrue();
+
+ var linkedDll = Path.Combine(linkedDirectory, $"{projectName}.dll");
+ var publishedDll = Path.Combine(publishDirectory, $"{projectName}.dll");
+ var unusedDll = Path.Combine(publishDirectory, $"{referenceProjectName}.dll");
+ var unusedFrameworkDll = Path.Combine(publishDirectory, $"{unusedFrameworkAssembly}.dll");
+
+ File.Exists(linkedDll).Should().BeTrue();
+ File.Exists(publishedDll).Should().BeTrue();
+ File.Exists(unusedDll).Should().BeFalse();
+ File.Exists(unusedFrameworkDll).Should().BeFalse();
+
+ var depsFile = Path.Combine(publishDirectory, $"{projectName}.deps.json");
+ DoesDepsFileHaveAssembly(depsFile, projectName).Should().BeTrue();
+ DoesDepsFileHaveAssembly(depsFile, referenceProjectName).Should().BeFalse();
+ DoesDepsFileHaveAssembly(depsFile, unusedFrameworkAssembly).Should().BeFalse();
+ }
+
[RequiresMSBuildVersionTheory("17.0.0.32901")]
[MemberData(nameof(SupportedTfms), MemberType = typeof(PublishTestUtils))]
public void ILLink_does_not_include_leftover_artifacts_on_second_run(string targetFramework)
diff --git a/src/WebSdk/Publish/Targets/Microsoft.NET.Sdk.Publish.targets b/src/WebSdk/Publish/Targets/Microsoft.NET.Sdk.Publish.targets
index b0fab989cdd4..beab531cc3f0 100644
--- a/src/WebSdk/Publish/Targets/Microsoft.NET.Sdk.Publish.targets
+++ b/src/WebSdk/Publish/Targets/Microsoft.NET.Sdk.Publish.targets
@@ -85,6 +85,9 @@ Copyright (C) Microsoft Corporation. All rights reserved.
obj/Docker/publish/
EFSQLScripts
+
+
+ partial