Skip to content

Conversation

agocke
Copy link
Member

@agocke agocke commented Apr 9, 2021

No description provided.

@agocke agocke requested review from sbomer and vitek-karas April 9, 2021 01:00
@agocke agocke requested a review from marek-safar as a code owner April 9, 2021 01:00
agocke and others added 3 commits April 9, 2021 01:29
void MethodWithAssemblyLoad() { ... }

[UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2026:RequiresUnreferencedCode",
Justification = "Everything referenced in the loaded assembly is manually preserved, so it's safe")]
Copy link
Contributor

@tlakollo tlakollo Apr 9, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we explain/link to how to preserve things manually? If I were to read this blog post looking for answers on how to solve my current broken app I would see that I can:

  • Use other function that is trim compatible (which is not always possible)
  • Mark my method with RequiresUnreferencedCode which changes the warning location but my app would still be broken
  • Preserve manually and Suppress the warning, the blog explains how to suppress the warning, but not how to preserve manually.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A good question, but not really a post I'm prepared to write.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well just in case someone reads these comments, an XML descriptor file or DynamicDependencyAttribute could help to preserve stuff on the app

Copy link
Contributor

@tlakollo tlakollo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me


In .NET Core 3.1 and 5.0 we introduced trimming as a new preview feature for self-contained .NET
core applications. Conceptually the feature is very simple: when publishing the application the
.NET SDK analyzes the entire application, including the .NET framework, and removes all unused
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what "including the .NET framework" is intended to explain

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant to emphasize that we're trimming away the core framework, but it's probably not necessary.

difficulties in safely trimming applications.

The most difficult question in trimming is what is unused, or more precisely, what is used. For
most standard C# code this is trivial -- the trimmer can easily walk method calls, field and
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is "the trimmer" ? We have not been using that term and most developers are familiar with linker term. Do we really have to confuse the community with another new name?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In all locations other than mono/linker we've been trying to avoid the term "linker" because most people understand it as the "platform linker". We use "trim tool" or sometimes "trimmer" (I would prefer "trim tool" if possible).
For the same reason we use "trimming" and not "linking" everywhere.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm intentionally "ignoring" the mono/Xamarin side of things - those will likely use "linker" a lot. Most of our docs and blog posts use "Trimming" - we also use it everywhere in the messages (RUC) in the framework. I don't see us going back to "linking".

That said - I understand the confusion for Xamarin users - we might want to mention this on the first use of the term.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was not referring to trimming but to "trimmer". Even .NET Core MSDN documentation is written in the way that it uses the term since 3.1.

.NET Core 3+ ships with an IL Linker which allows you to reduce the size of the self-contained application. It automatically determines which assemblies are needed and copies only them.

I'm really not sure we have to rename everything to cause more confusion.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would probably just not give it a name here. We can update the sentence to say "For most standard C# code this is trivial -- the trimmerwe can easily walk method calls, field and"

That said,

https://en.wikipedia.org/wiki/Linker_(computing)

This is the definition of the term used in computer engineering. It's not what IL Linker is doing. It's confusing to anyone who has ever used a linker in the past.

Reusing this term in .NET was a mistake. We should have gone with something like Remover 8000. Now Xamarin often needs to qualify the word "linker" with the word "native" when referring to what everyone outside .NET calls "linker". It's a pretty sad place to be in and puts us (the authors of .NET) into a bad light (trying to steal a well-established term).

I've seen this cause confusion in the past. "Linker failed. Oh, not that one, the other one."

We should phase this name out before it moves out of the niche parts of .NET (both Xamarin and Blazor-WASM are still niches).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My use of the term "trimmer" here is in its most generic sense -- it is the thing which "trims." The other documentation about a specific tool which is responsible for trimming is incorrect in this case because the only supported method of trimming applications in .NET 6 will be passing PublishTrimmed=true to the SDK. Rather than talk specifically about the SDK, I wanted to just use a generic term.

I don't really see the need to get more specific here and talk about any specific tool. The term "linker" is certainly incorrect for .NET 6 since we do not plan on shipping a separate linker tool for supported scenarios.


### RequiresUnreferencedCode

`RequiresUnreferencedCode` is simple: it's an attribute that can be placed on methods to indicate
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


### DynamicallyAccessedMembers

`DynamicallyAccessedMembers` is usually about reflection. Unlike `RequiresUnreferencedCode`,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a reference to MSDN documentation for DynamicallyAccessedMembers


This description should cover the most common situations you end up in while trimming your
application. Over time we'll continue to improve the diagnostic experience and provide more streamlined
ways to make your code trim-compatible.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Over time we'll continue to improve the diagnostic experience and provide more streamlined
ways to make your code trim-compatible.

Is this claim correct?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup! Better warning messages, analyzers for DynamicallyAccessedMembers, better perf, etc

the method at all when trimming and use something else which is trim-compatible. If you're
writing a library and it's not in your control whether or not to call the method and you just
want to communicate to *your* caller, you can also add `RequiresUnreferencedCode` to your own
method. This silences all trimming warnings in your code, but will produce a warning whenever

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this produce a warning rather than an error? If the method is marked that its not going to work, and is called, then why only warn?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because in almost all cases the method might work in some cases and might not in others. For example XmlSerializer.Serialize(object o) - it's definitely not trim compatible, but if you make sure that the type passed in is preserved enough - it will work just fine.

We use this attribute basically to say "If you ignore this, you're on your own and will have to test at runtime".

There are also cases where the method is sooo close to being trim compatible except for some weird special case - we can't mark it as compatible (since it's not 100%), but it almost always is.

And as with any other trim analysis - the linker plays it super safe, the annotations do that as well. We don't want to block people completely if we are too careful.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty much everything in trimming is a warning, because many things just happen to work. For instance, if you call a method that has RUC does a lot of reflection on its parameter, but the parameter type is in user code (and therefore untrimmed) and nothing important from the framework was removed, it all just works.

Of course, this is just luck, which is why the warning is there.

}
void M2(Type type)
{
// Trim analysis warning IL2070: net6.Program.M2(Type): 'this' argument does not satisfy

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move out the error into a block to show what the compiler would say

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, not sure what you mean by this. You mean extract the comment into a separate code block?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, and you can mark it as console, something like:


void M1()
{
    M2(typeof(System.Tuple));
}
void M2(Type type)
{
    var methods = type.GetMethods();
    ...
}

If you compile, you'll see the following warning:

Trim analysis warning IL2070: net6.Program.M2(Type): 'this' argument does not satisfy
'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethods()'. The
parameter 'type' of method 'net6.Program.M2(Type)' does not have matching annotations. The
source value must declare at least the same requirements as those declared on the target
location it is assigned to.

`DynamicallyAccessMembers` come in? What happens if the reflection is split across methods?

```C#
void M1()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

M1 seems wrong to me, Method1 would read better

@samsp-msft
Copy link

A couple of niggles, but LGTM.

@agocke
Copy link
Member Author

agocke commented Apr 12, 2021

@samsp-msft Any idea where this should go? I'd like to put it somewhere more accessible than the linker docs. Either MS docs or blog post. Thoughts?

@samsp-msft
Copy link

@samsp-msft Sam Spencer FTE Any idea where this should go? I'd like to put it somewhere more accessible than the linker docs. Either MS docs or blog post. Thoughts?

It reads more like a blog post than docs, but doesn't have the preamble of a blog post. I'd suggest either

@agocke agocke merged commit 4ef464a into dotnet:main Apr 16, 2021
@agocke agocke deleted the fixing-warnings branch April 16, 2021 22:15
@agocke
Copy link
Member Author

agocke commented Apr 16, 2021

@samsp-msft I think this is ready. Not sure what kind of preface you would want to add, but can we start moving this to a blog site?

agocke added a commit to dotnet/runtime that referenced this pull request Nov 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants