Skip to content

Commit b6f1fb4

Browse files
authored
Add more trimming options to TrimMode and change defaults (#2856)
The new default for trimming is equivalent to TrimmerDefaultAction=link. Since we're trying to stay away from the term link and TrimmerDefaultAction isn't a very clear name, this change repurposes TrimMode. The two new TrimModes are 'full' and 'partial'. The new default is equivalent to 'TrimMode=full'. These new modes are also recognized for earlier TFMs, but the defaults are only changed for net7.0+.
1 parent 2898eba commit b6f1fb4

4 files changed

Lines changed: 98 additions & 34 deletions

File tree

src/ILLink.Tasks/ILLink.Tasks.csproj

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,17 @@
3333
</ItemGroup>
3434

3535
<ItemGroup>
36-
<Content Include="sdk/Sdk.props" PackagePath="Sdk/" />
37-
<Content Include="build/$(PackageId).props" PackagePath="build/" />
36+
<Content Include="sdk/Sdk.props" PackagePath="Sdk/">
37+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
38+
</Content>
39+
<Content Include="build/$(PackageId).props" PackagePath="build/">
40+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
41+
</Content>
3842
<!-- Note: this should not match the package name, because we don't want the targets
3943
to be imported by nuget. The SDK will import them in the right order. -->
40-
<Content Include="build/Microsoft.NET.ILLink.targets" PackagePath="build/" />
44+
<Content Include="build/Microsoft.NET.ILLink.targets" PackagePath="build/">
45+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
46+
</Content>
4147
</ItemGroup>
4248

4349
<ItemGroup>

src/ILLink.Tasks/LinkTask.cs

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public class ILLink : ToolTask
6060
public ITaskItem OutputDirectory { get; set; }
6161

6262
/// <summary>
63-
/// The subset of warnings that have to be turned off.
63+
/// The subset of warnings that have to be turned off.
6464
/// Maps to '--nowarn'.
6565
/// </summary>
6666
public string NoWarn { get; set; }
@@ -206,6 +206,7 @@ public class ILLink : ToolTask
206206
/// <summary>
207207
/// Sets the default action for assemblies which have not opted into trimming.
208208
/// Maps to '--action'
209+
/// </summary>
209210
public string DefaultAction { get; set; }
210211

211212
/// <summary>
@@ -318,6 +319,23 @@ protected override string GenerateResponseFileCommands ()
318319
args.AppendLine ("--singlewarn-");
319320
}
320321

322+
string trimMode = TrimMode switch {
323+
"full" => "link",
324+
"partial" => "link",
325+
var x => x
326+
};
327+
if (trimMode != null)
328+
args.Append ("--trim-mode ").AppendLine (trimMode);
329+
330+
string defaultAction = TrimMode switch {
331+
"full" => "link",
332+
"partial" => "copy",
333+
_ => DefaultAction
334+
};
335+
if (defaultAction != null)
336+
args.Append ("--action ").AppendLine (defaultAction);
337+
338+
321339
HashSet<string> assemblyNames = new HashSet<string> (StringComparer.OrdinalIgnoreCase);
322340
foreach (var assembly in AssemblyPaths) {
323341
var assemblyPath = assembly.ItemSpec;
@@ -329,10 +347,20 @@ protected override string GenerateResponseFileCommands ()
329347

330348
args.Append ("-reference ").AppendLine (Quote (assemblyPath));
331349

332-
string trimMode = assembly.GetMetadata ("TrimMode");
333-
if (!String.IsNullOrEmpty (trimMode)) {
350+
string assemblyTrimMode = assembly.GetMetadata ("TrimMode");
351+
string isTrimmable = assembly.GetMetadata ("IsTrimmable");
352+
if (string.IsNullOrEmpty (assemblyTrimMode)) {
353+
if (isTrimmable.Equals ("true", StringComparison.OrdinalIgnoreCase)) {
354+
// isTrimmable ~= true
355+
assemblyTrimMode = trimMode;
356+
} else if (isTrimmable.Equals ("false", StringComparison.OrdinalIgnoreCase)) {
357+
// isTrimmable ~= false
358+
assemblyTrimMode = "copy";
359+
}
360+
}
361+
if (!string.IsNullOrEmpty (assemblyTrimMode)) {
334362
args.Append ("--action ");
335-
args.Append (trimMode);
363+
args.Append (assemblyTrimMode);
336364
args.Append (' ').AppendLine (Quote (assemblyName));
337365
}
338366

@@ -447,12 +475,6 @@ protected override string GenerateResponseFileCommands ()
447475
if (_removeSymbols == false)
448476
args.AppendLine ("-b");
449477

450-
if (TrimMode != null)
451-
args.Append ("--trim-mode ").AppendLine (TrimMode);
452-
453-
if (DefaultAction != null)
454-
args.Append ("--action ").AppendLine (DefaultAction);
455-
456478
if (CustomSteps != null) {
457479
foreach (var customStep in CustomSteps) {
458480
args.Append ("--custom-step ");

src/ILLink.Tasks/build/Microsoft.NET.ILLink.targets

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ Copyright (c) .NET Foundation. All rights reserved.
5151
<PropertyGroup Condition="'$(SuppressTrimAnalysisWarnings)' == '' And '$(PublishTrimmed)' == 'true' And '$(EnableTrimAnalyzer)' != 'true'">
5252
<!-- Trim analysis warnings are suppressed for .NET < 6. -->
5353
<SuppressTrimAnalysisWarnings Condition="$([MSBuild]::VersionLessThan('$(TargetFrameworkVersion)', '6.0'))">true</SuppressTrimAnalysisWarnings>
54-
<!-- Suppress for WPF/WinForms (unless linking everything) -->
55-
<SuppressTrimAnalysisWarnings Condition="'$(TrimmerDefaultAction)' != 'link' And ('$(UseWpf)' == 'true' Or '$(UseWindowsForms)' == 'true')">true</SuppressTrimAnalysisWarnings>
54+
<!-- Suppress for WPF/WinForms -->
55+
<SuppressTrimAnalysisWarnings Condition="'$(UseWpf)' == 'true' Or '$(UseWindowsForms)' == 'true'">true</SuppressTrimAnalysisWarnings>
5656
<!-- Otherwise, for .NET 6+, warnings are on by default -->
5757
<SuppressTrimAnalysisWarnings Condition="'$(SuppressTrimAnalysisWarnings)' == ''">false</SuppressTrimAnalysisWarnings>
5858
</PropertyGroup>
@@ -159,7 +159,7 @@ Copyright (c) .NET Foundation. All rights reserved.
159159
ReferenceAssemblyPaths="@(ReferencePath)"
160160
RootAssemblyNames="@(TrimmerRootAssembly)"
161161
TrimMode="$(TrimMode)"
162-
DefaultAction="$(TrimmerDefaultAction)"
162+
DefaultAction="$(_TrimmerDefaultAction)"
163163
RemoveSymbols="$(TrimmerRemoveSymbols)"
164164
FeatureSettings="@(_TrimmerFeatureSettings)"
165165
CustomData="@(_TrimmerCustomData)"
@@ -226,16 +226,23 @@ Copyright (c) .NET Foundation. All rights reserved.
226226
<ILLinkWarningLevel Condition=" '$(ILLinkWarningLevel)' == '' ">0</ILLinkWarningLevel>
227227
</PropertyGroup>
228228

229-
<!-- Defaults for .NET < 6 -->
230-
<PropertyGroup Condition=" $([MSBuild]::VersionLessThan('$(TargetFrameworkVersion)', '6.0')) ">
231-
<TrimMode Condition=" '$(TrimMode)' == '' ">copyused</TrimMode>
232-
<!-- Action is the same regardless of whether the assembly has an IsTrimmable attribute. (The attribute didn't exist until .NET 6.) -->
233-
<TrimmerDefaultAction>$(TrimMode)</TrimmerDefaultAction>
229+
<!-- In .NET 7, TrimmerDefaultAction is deprecated. TrimMode can be used for the supported configurations. -->
230+
<Warning Condition="'$(TrimmerDefaultAction)' != '' And $([MSBuild]::VersionGreaterThan('$(TargetFrameworkVersion)', '6.0'))"
231+
Text="Property 'TrimmerDefaultAction' is deprecated in .NET 7 and will be ignored. Use TrimMode instead." />
232+
233+
<!-- Set up TrimMode and TrimmerDefaultAction. -->
234+
<PropertyGroup>
235+
<TrimMode Condition="'$(TrimMode)' == '' And $([MSBuild]::VersionLessThan($(TargetFrameworkVersion), '6.0'))">copyused</TrimMode>
236+
<TrimMode Condition="'$(TrimMode)' == '' And $([MSBuild]::VersionEquals($(TargetFrameworkVersion), '6.0'))">partial</TrimMode>
237+
<TrimMode Condition="'$(TrimMode)' == ''">full</TrimMode>
238+
239+
<!-- Set TrimmerDefaultAction for compat in < 7.0 -->
240+
<_TrimmerDefaultAction Condition="$([MSBuild]::VersionLessThan($(TargetFrameworkVersion), '7.0'))">$(TrimmerDefaultAction)</_TrimmerDefaultAction>
241+
<_TrimmerDefaultAction Condition="'$(_TrimmerDefaultAction)' == '' And $([MSBuild]::VersionLessThan($(TargetFrameworkVersion), '6.0'))">$(TrimMode)</_TrimmerDefaultAction>
242+
<_TrimmerDefaultAction Condition="'$(_TrimmerDefaultAction)' == '' And $([MSBuild]::VersionEquals($(TargetFrameworkVersion), '6.0'))">copy</_TrimmerDefaultAction>
234243
</PropertyGroup>
244+
235245
<PropertyGroup>
236-
<TrimMode Condition=" '$(TrimMode)' == '' ">link</TrimMode>
237-
<!-- For .NET 6+, assemblies without IsTrimmable attribute get the "copy" action. -->
238-
<TrimmerDefaultAction Condition=" '$(TrimmerDefaultAction)' == '' ">copy</TrimmerDefaultAction>
239246
<ILLinkTreatWarningsAsErrors Condition=" '$(ILLinkTreatWarningsAsErrors)' == '' ">$(TreatWarningsAsErrors)</ILLinkTreatWarningsAsErrors>
240247
<_ExtraTrimmerArgs>--skip-unresolved true $(_ExtraTrimmerArgs)</_ExtraTrimmerArgs>
241248
<TrimmerSingleWarn Condition=" '$(TrimmerSingleWarn)' == '' ">true</TrimmerSingleWarn>
@@ -296,16 +303,6 @@ Copyright (c) .NET Foundation. All rights reserved.
296303
</ManagedAssemblyToLink>
297304
</ItemGroup>
298305

299-
<!-- In .NET6+, set the action explicitly for any with IsTrimmable MSBuild metadata -->
300-
<ItemGroup Condition=" $([MSBuild]::VersionGreaterThanOrEquals('$(TargetFrameworkVersion)', '6.0')) ">
301-
<ManagedAssemblyToLink Condition=" '%(ManagedAssemblyToLink.IsTrimmable)' == 'true' And '%(ManagedAssemblyToLink.TrimMode)' == '' ">
302-
<TrimMode>$(TrimMode)</TrimMode>
303-
</ManagedAssemblyToLink>
304-
<ManagedAssemblyToLink Condition=" '%(ManagedAssemblyToLink.IsTrimmable)' == 'false' And '%(ManagedAssemblyToLink.TrimMode)' == '' ">
305-
<TrimMode>$(TrimmerDefaultAction)</TrimMode>
306-
</ManagedAssemblyToLink>
307-
</ItemGroup>
308-
309306
<ItemGroup>
310307
<!-- Don't collapse to a single warning for the intermediate assembly.
311308
This just sets metadata on the items in ManagedAssemblyToLink that came from IntermediateAssembly. -->

test/ILLink.Tasks.Tests/ILLink.Tasks.Tests.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,45 @@ public class TaskArgumentTests
5656
}
5757
};
5858

59+
[Theory]
60+
[InlineData ("full", AssemblyAction.Link)]
61+
[InlineData ("partial", AssemblyAction.Copy)]
62+
public void TrimModeFullAndPartial (string trimMode, AssemblyAction expectedDefaultAction)
63+
{
64+
var task = new MockTask () {
65+
TrimMode = trimMode
66+
};
67+
using (var driver = task.CreateDriver ()) {
68+
Assert.Equal (AssemblyAction.Link, driver.Context.TrimAction);
69+
Assert.Equal (expectedDefaultAction, driver.Context.DefaultAction);
70+
}
71+
}
72+
73+
[Theory]
74+
[InlineData ("full")]
75+
[InlineData ("partial")]
76+
public void TrimModeAssemblyPaths (string trimMode)
77+
{
78+
var assemblyPaths = new ITaskItem[] {
79+
new TaskItem("Assembly1.dll", new Dictionary<string, string> {{ "IsTrimmable", "true" }}),
80+
new TaskItem("Assembly2.dll", new Dictionary<string, string> ()),
81+
new TaskItem("Assembly3.dll", new Dictionary<string, string> {{ "IsTrimmable", "false" }}),
82+
};
83+
var task = new MockTask () {
84+
TrimMode = trimMode,
85+
AssemblyPaths = assemblyPaths
86+
};
87+
using var driver = task.CreateDriver ();
88+
var context = driver.Context;
89+
var references = driver.GetReferenceAssemblies ();
90+
Assert.Equal ("", assemblyPaths[0].GetMetadata ("TrimMode"));
91+
Assert.Equal (AssemblyAction.Link, context.Actions["Assembly1"]);
92+
Assert.Equal ("", assemblyPaths[1].GetMetadata ("TrimMode"));
93+
Assert.False (context.Actions.ContainsKey ("Assembly2"));
94+
Assert.Equal ("", assemblyPaths[2].GetMetadata ("TrimMode"));
95+
Assert.Equal (AssemblyAction.Copy, context.Actions["Assembly3"]);
96+
}
97+
5998
[Theory]
6099
[MemberData (nameof (AssemblyPathsCases))]
61100
public void TestAssemblyPaths (ITaskItem[] assemblyPaths)

0 commit comments

Comments
 (0)