Skip to content
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
19 changes: 9 additions & 10 deletions docs/illink-tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,20 +53,19 @@ The linker can be invoked as an MSBuild task, `ILLink`. We recommend not using t
ExtraArgs="-t -c link" />
```

## Default Linking Behaviour
## Default Linking Behavior

### .NET 5.0
The default in the .NET Core SDK is to trim framework assemblies only, in a conservative assembly-level mode (`copyused` action). Third-party libraries and the app will be analyzed but not trimmed. Other SDKs may modify these defaults.

By default, the linker will operate in a full linking mode for all framework or
core managed assemblies. The 3rd party libraries or final app will be analyzed but not linked.
This setting can be altered by setting `_TrimmerDefaultAction` property to different
linker action mode.
## Customizing Linking Behavior

### .NET 3.x
`TrimMode` can be used to set the trimming behavior for framework assemblies. Additional assemblies can be given
metadata `IsTrimmable` and they will also be trimmed using this mode, or they can have per-assembly `TrimMode` which
takes precedence over the global `TrimMode`.

By default, the linker will operate in a conservative mode that keeps
all managed assemblies that aren't part of the framework (they are
kept intact, and the linker simply copies them).
## Reflection

Note: this section is out-of-date. New versions of the linker can understand some of these reflection patterns.

Applications or frameworks (including ASP<span />.NET Core and WPF) that use reflection or related dynamic features will often break when trimmed, because the linker does not know about this dynamic behavior, and can not determine in general which framework types will be required for reflection at runtime. To trim such apps, you will need to tell the linker about any types needed by reflection in your code, and in packages or frameworks that you depend on. Be sure to test your apps after trimming.

Expand Down
14 changes: 7 additions & 7 deletions src/ILLink.Tasks/LinkTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class ILLink : ToolTask
/// Paths to the assembly files that should be considered as
/// input to the linker.
/// Optional metadata:
/// Action ("copy", "link", etc...): sets the illink action to take for this assembly.
/// TrimMode ("copy", "link", etc...): sets the illink action to take for this assembly.
/// There is an optional metadata for each optimization that can be set to "True" or "False" to
/// enable or disable it per-assembly:
/// BeforeFieldInit
Expand Down Expand Up @@ -159,7 +159,7 @@ public class ILLink : ToolTask
/// Sets the default action for assemblies.
/// Maps to '-c' and '-u'.
/// </summary>
public string DefaultAction { get; set; }
public string TrimMode { get; set; }

/// <summary>
/// A list of custom steps to insert into the linker pipeline.
Expand Down Expand Up @@ -261,10 +261,10 @@ protected override string GenerateResponseFileCommands ()

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

string action = assembly.GetMetadata ("Action");
if (!String.IsNullOrEmpty (action)) {
string trimMode = assembly.GetMetadata ("TrimMode");
if (!String.IsNullOrEmpty (trimMode)) {
args.Append ("-p ");
args.Append (action);
args.Append (trimMode);
args.Append (" ").AppendLine (Quote (assemblyName));
}

Expand Down Expand Up @@ -349,8 +349,8 @@ protected override string GenerateResponseFileCommands ()
if (LinkSymbols)
args.AppendLine ("-b");

if (DefaultAction != null)
args.Append ("-c ").Append (DefaultAction).Append (" -u ").AppendLine (DefaultAction);
if (TrimMode != null)
args.Append ("-c ").Append (TrimMode).Append (" -u ").AppendLine (TrimMode);

if (CustomSteps != null) {
foreach (var customStep in CustomSteps) {
Expand Down
24 changes: 12 additions & 12 deletions test/ILLink.Tasks.Tests/ILLink.Tasks.Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ public class TaskArgumentTests
public static IEnumerable<object[]> AssemblyPathsCases => new List<object[]> {
new object [] {
new ITaskItem [] {
new TaskItem ("Assembly.dll", new Dictionary<string, string> { { "action", "copy" } })
new TaskItem ("Assembly.dll", new Dictionary<string, string> { { "trimmode", "copy" } })
}
},
new object [] {
new ITaskItem [] {
new TaskItem ("Assembly.dll", new Dictionary<string, string> { { "Action", "Copy" } })
new TaskItem ("Assembly.dll", new Dictionary<string, string> { { "TrimMode", "Copy" } })
}
},
new object [] {
Expand Down Expand Up @@ -75,10 +75,10 @@ public void TestAssemblyPaths (ITaskItem[] assemblyPaths)

foreach (var item in assemblyPaths) {
var assemblyPath = item.ItemSpec;
var action = item.GetMetadata ("action");
if (String.IsNullOrEmpty (action))
var trimMode = item.GetMetadata ("TrimMode");
if (String.IsNullOrEmpty (trimMode))
continue;
AssemblyAction expectedAction = (AssemblyAction) Enum.Parse (typeof (AssemblyAction), action, ignoreCase: true);
AssemblyAction expectedAction = (AssemblyAction) Enum.Parse (typeof (AssemblyAction), trimMode, ignoreCase: true);
AssemblyAction actualAction = (AssemblyAction) context.Actions[Path.GetFileNameWithoutExtension (assemblyPath)];
Assert.Equal (expectedAction, actualAction);
}
Expand All @@ -89,7 +89,7 @@ public void TestAssemblyPaths (ITaskItem[] assemblyPaths)
public void TestAssemblyPathsWithInvalidAction ()
{
var task = new MockTask () {
AssemblyPaths = new ITaskItem[] { new TaskItem ("Assembly.dll", new Dictionary<string, string> { { "action", "invalid" } }) }
AssemblyPaths = new ITaskItem[] { new TaskItem ("Assembly.dll", new Dictionary<string, string> { { "TrimMode", "invalid" } }) }
};
Assert.Throws<ArgumentException> (() => task.CreateDriver ());
}
Expand Down Expand Up @@ -379,12 +379,12 @@ public void TestInvalidFeatureSettings ()
public void TestExtraArgs ()
{
var task = new MockTask () {
DefaultAction = "copy",
TrimMode = "copy",
ExtraArgs = "-c link"
};
using (var driver = task.CreateDriver ()) {
Assert.Equal (AssemblyAction.Copy, driver.Context.UserAction);
// Check that ExtraArgs can override DefaultAction
// Check that ExtraArgs can override TrimMode
Assert.Equal (AssemblyAction.Link, driver.Context.CoreAction);
}
}
Expand Down Expand Up @@ -419,13 +419,13 @@ public void TestLinkSymbols (bool linkSymbols)
[InlineData ("copy")]
[InlineData ("link")]
[InlineData ("copyused")]
public void TestDefaultAction (string defaultAction)
public void TestGlobalTrimMode (string trimMode)
{
var task = new MockTask () {
DefaultAction = defaultAction
TrimMode = trimMode
};
using (var driver = task.CreateDriver ()) {
var expectedAction = (AssemblyAction) Enum.Parse (typeof (AssemblyAction), defaultAction, ignoreCase: true);
var expectedAction = (AssemblyAction) Enum.Parse (typeof (AssemblyAction), trimMode, ignoreCase: true);
Assert.Equal (expectedAction, driver.Context.CoreAction);
Assert.Equal (expectedAction, driver.Context.UserAction);
}
Expand All @@ -435,7 +435,7 @@ public void TestDefaultAction (string defaultAction)
public void TestInvalidDefaultAction ()
{
var task = new MockTask () {
DefaultAction = "invalid"
TrimMode = "invalid"
};
Assert.Throws<ArgumentException> (() => task.CreateDriver ());
}
Expand Down