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

Introducing .NET IL Linker #915

Closed
richlander opened this issue Aug 30, 2017 · 22 comments
Closed

Introducing .NET IL Linker #915

richlander opened this issue Aug 30, 2017 · 22 comments

Comments

@richlander
Copy link
Member

Introducing .NET IL Linker

The .NET Core team has been working on a linker in collaboration with the Mono team. It is based on the Mono Linker project, and by extension, on the Cecil project.

The goal of the .NET IL Linker project is two part:

  • Provide a capable linker for .NET Core to make it easy to significantly reduce .NET Core application sizes.
  • Establish the Mono Linker as the primary linker for the .NET ecosystem.

You can start using the linker today, using the following instructions:

Details

In trivial cases, the linker can reduce the size of applications by 50%. The size wins may be more favorable or more moderate for larger applications. The linker removes code in your application and dependent libraries that are not reached by any code paths. It is effectively an application-specific dead code analysis.

The IL Linker currently only supports .NET Core Self Contained Applications with this first preview version. You can try using the linker with an example self-contained .NET Core application sample. The primary difference with this application is that it has a reference to the ILLink.Tasks package in its cspoj project file.

The Linker provides an option to print a size improvement chart that describes binaries that have been removed from an application or that have been reduced in size. It also provides the total % size reduction for the application. You can see an example of one of these charts in the following example.

.NET IL Linker Size Improvement Chart

Please provide feedback on your use of the linker. We are actively looking for feedback to improve the linker. In particular, we are looking for feedback on the following topics:

  • Linker throughput.
  • Cases where the linker can be more aggressive.
  • Cases where the link is too aggressive and causes applications to fail at runtime.
  • The linker provided an excellent result for a large application.

Please create issue with your feedback at either mono/linker or dotnet/core. Also feel free to contact the team at clrlinker@microsoft.com.

And, it wouldn't be right to announce this linker without a hat tip to Joel Spolsky who we can give the honorary and historical distinction of feature requestor.

@AlgorithmsAreCool
Copy link

Is the end goal here smaller deployments or does this get us closer to being able to ship single file self contained applications executable?

@Petermarcu
Copy link
Member

@AlgorithmsAreCool The primary goal is smaller deployments that only have the code you need in them (better pay-for-play). The self contained executable scenario will definitely benefit from this but I don't think they are neccessarily tied.

@galvesribeiro
Copy link
Member

Is the end goal here smaller deployments or does this get us closer to being able to ship single file self contained applications executable?

I wonder if after linting we could leverage something like ILMerge as a secondary (and optional) build step for a single executable scenario.

@richlander
Copy link
Member Author

richlander commented Aug 30, 2017

@galvesribeiro Yes. ILMerge (or something like it, like mkbundle), would be step 2.

We will probably build a single file toolchain at some point, but it is a ways off right now.

As @Petermarcu suggests, the primary goal is smaller deployments.

@masonwheeler
Copy link
Contributor

And, it wouldn't be right to announce this linker without a hat tip to Joel Spolsky who we can give the honorary and historical distinction of feature requestor.

13 years. Better late than never, I suppose...

@phrohdoh
Copy link

The IL Linker currently only supports .NET Core Self Contained Applications with this first preview version.

Does this mean the linker will eventually support .NET Framework / Mono, or is it planned to be Core-only?

@hjc4869
Copy link

hjc4869 commented Aug 31, 2017

My project has references to some (large) libraries but only a small part of them are actually used. (No reflection is used)

According to the docs, non-framework assemblies are all root assemblies by default. Can I remove some of them from LinkerRootAssemblies without adding the ILLink to the csproj?

@russellhadley
Copy link

russellhadley commented Aug 31, 2017

The IL Linker currently only supports .NET Core Self Contained Applications with this first preview version.

Does this mean the linker will eventually support .NET Framework / Mono, or is it planned to be Core-only?

@phrohdoh The Core linker shares the same base linking tool with Mono (so good news, that already works). We've started to think about bringing ILLinker to .NET Framework but we don't have a concrete plan yet - so stay tuned.

@sbomer
Copy link
Member

sbomer commented Aug 31, 2017

@hjc4869, if you don't want to specify all of the inputs to ILLink by using the task in your .csproj, you should be able to do this by inserting your own target that removes these assemblies from LinkerRootAssemblies, like this:

<Target Name="UnrootAssemblies" AfterTargets="_ComputeLinkerRootAssemblies">
  <ItemGroup>
    <LinkerRootAssemblies Remove="Assembly.Name.Without.Dll.Extension" />
  </ItemGroup>
</Target>

This relies on the private target _ComputeLinkerRootAssemblies, so consider this unsupported. :) We should probably make the default behavior more configurable to make this easier in the future.

@markrendle
Copy link

Will this be chainable with the /t:LinkNative target from CoreRT? So I can trim down my assemblies before AOT compilation?

@mikedn
Copy link

mikedn commented Sep 4, 2017

@markrendle Why would you do that? AOT compilation does this by default.

@gregkalapos
Copy link

gregkalapos commented Sep 6, 2017

Great idea, but unfortunately it can potentially break our product, so I’d like to describe our scenario:

My team works on an APM product which is basically a Profiler with IL Rewriting. We use the profiler API to inject our code with AssemblytRefs and TypeRefs to existing types into the customers application. Now these references can be trimmed, which leads to crashes.

Until this point our approach for .NET Core was that we only used references to Types that are part of Netstandard. We thought with that we are on the safe side, now it turns out this is not the case.

I looked at this and I understand that we can exclude dlls from trimming, but we do our injection runtime, so our customers with this approach have to recompile their applications and we have to extra maintain the list of Types we use. This is extremely hard in our case -I’d say this is not feasible at all. (I can go into more details, but I guess you can imagine the situation…e.g.: what if we update our stuff, etc. ).

Did you consider this scenario? The problem itself is similar to the problem with reflection I guess. Our goal would be that we don’t have to say that “this is an unsupported scenario”. Furthermore, crashes caused by this are I think very problematic and we should figure out a solution to at least prevent TypeLoad-crashes caused by this.

Maybe one option that comes to my mind:

Would it be an option to implement a flag within the Linker that ensures that e.g. Netstandard types won't be removed? That way we can at least have a fix set of APIs that we can use and customers then compile the application with this single flag. Of course, we also should somehow handle scenarios where the application is not built with this flag.

Thanks!
cc @richlander @terrajobst @karelz

@Petermarcu
Copy link
Member

It seems like providing a convenient way to root .NET Standard types would be pretty straight forward.

@gregkalapos
Copy link

@Petermarcu thanks for the feedback. That's good news. Of course the question is: does mono linker make sense with that setup? I mean, if with that setup the application only gets a few percent smaller, then the idea isn't so good. Anyway, this was just my first suggestion... Maybe somone comes up with another solution.

And please don't forget the other part: it would still be nice if a profiler could somehow figure out that important dlls (Like System.Runtime, System.Threading.*, System.Collections) were trimmed, so we can prevent crashes.

@Petermarcu
Copy link
Member

It definitely takes away some of the value. The only other way I can think of is to come up with a good way to be explicit about the dependencies that could be added by your rewriter. You said that wasn't feasible but it may be worth digging into that a little more.

@Ethereal77
Copy link

What about something like anotations? Maybe some kind of attribute that specifies to the linker which types to consider as roots. The linker then would mark those types as roots and combine that information with the other channels (like creating your own target).
Finally, the linker would remove from the final assembly the references to the attributes used to annotate.

I think that would be a very easy way of protecting a type you know you are going to use with reflection or whatever.

What do you think?

@Petermarcu
Copy link
Member

Closing as we plan on keeping these announcements open for about 30 days.

@ghost
Copy link

ghost commented Feb 10, 2018

@Petermarcu, I hope this wasn't intentional that the announcement failed to answer one basic question: is ILLink an open source tech? If so where can I find the EXACT sources of package we are using?

The first line in announcement does note:

The .NET Core team has been working on a linker in collaboration with the Mono team. It is based on the Mono Linker project, and by extension, on the Cecil project.

But where are the sources of https://dotnet.myget.org/feed/dotnet-core/package/nuget/Illink.Tasks package that the end consumer is using?

@sandorfr
Copy link

sandorfr commented Feb 10, 2018

@kasper3 I’m pretty sure the source are going to appear at some level of maturity. I don’t think that was a good reason to open an issue on announcements which as a result will spam us all ;)

@erozenfeld
Copy link
Member

erozenfeld commented Feb 12, 2018

@kasper3

But where are the sources of https://dotnet.myget.org/feed/dotnet-core/package/nuget/Illink.Tasks package that the end consumer is using?

Here they are:
https://github.com/mono/linker/tree/master/corebuild/integration/ILLink.Tasks

@RehanSaeed
Copy link

RehanSaeed commented Apr 11, 2019

Is this project dead? The latest NuGet package was from 2018 and there has been no recent news (that I can find).

There is also the Microsoft.Packaging.Tools.Trimming tool which does something very similar. What is the difference?

Finally, can this be used with UWP apps?

@sbomer
Copy link
Member

sbomer commented Apr 11, 2019

@RehanSaeed the current package has many issues because the extension points it uses to hook into the SDK have drifted (see dotnet/sdk#2583). We are reworking the experience with what will hopefully be a longer-term solution, and the plan is for it to be a part of the SDK. You can follow the work going on at https://github.com/mono/linker if you're interested. Stay tuned for updates from the .NET team! :)

The trimming tool is indeed similar. The linker is potentially able to do a more fine-grained analysis (based on code it thinks will be executed), depending on the settings. This also has the potential to break code that uses reflection.

UWP apps aren't supported - I'm no expert, but my understanding is that UWP release builds use the .NET Native toolchain, which has its own dependency reducer, similar in spirit to the linker.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests