Skip to content

Skip entry-point trim roots for library outputs#125673

Draft
Copilot wants to merge 2 commits intomainfrom
copilot/fix-net-8-android-error
Draft

Skip entry-point trim roots for library outputs#125673
Copilot wants to merge 2 commits intomainfrom
copilot/fix-net-8-android-error

Conversation

Copy link
Contributor

Copilot AI commented Mar 17, 2026

Trimmed self-contained library-style app publishes can fail with IL1034 because the SDK always roots the intermediate assembly as RootMode="EntryPoint", even when OutputType=Library. This updates the trimming target so library projects are not given an entry-point root.

  • SDK target change

    • In Microsoft.NET.ILLink.targets, make the intermediate assembly TrimmerRootAssembly item conditional on $(OutputType) != 'Library'.
    • Preserve existing behavior for executable outputs.
  • Regression coverage

    • Add a focused ILLink.Tasks test that inspects the shipped target file and asserts the entry-point root is conditioned away for library projects.
  • Behavioral effect

    • Exe projects continue to root the main assembly by entry point.
    • Library projects no longer request an entry-point root from the trimmer, avoiding the invalid root configuration that triggers IL1034.
<ItemGroup>
  <TrimmerRootAssembly
      Include="@(IntermediateAssembly->'%(Filename)')"
      RootMode="EntryPoint"
      Condition="'$(OutputType)' != 'Library'" />
</ItemGroup>
Original prompt

This section details on the original issue you should resolve

<issue_title>New error in .NET 8 Android projects</issue_title>
<issue_description>Starting in this Maestro bump: dotnet/android#7630

We started seeing:

ILLink error IL1034: Root assembly 'MyAndroidApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' does not have entry point.

Might be caused by: dotnet/linker#3124 (comment)

Android apps are class libraries, because there is no static void Main() method.

To work around this I did:

  <Target Name="_FixRootAssembly" AfterTargets="PrepareForILLink">
    <ItemGroup>
      <TrimmerRootAssembly Update="@(TrimmerRootAssembly)" Condition=" '%(RootMode)' == 'EntryPoint' " RootMode="Library" />
    </ItemGroup>
  </Target>

Filing an issue here, to see if this is what we should actually do -- or something else.</issue_description>

<agent_instructions>Don't set a trimmer root assembly for library projects.</agent_instructions>

Comments on the Issue (you are @copilot in this section)

@vitek-karas @sbomer please take a look. @sbomer I think the workaround ~is doing the right thing~ (edit: see my next comment), and I think it would make sense to put the fix for this into the SDK. In https://github.com/dotnet/linker/pull/3131 we decided against it, but I think this issue shows that we really do already have non-exe projects as a supported scenario - I just didn't know it.

I think we should fix this by using RootMode="library" RootMode="visible" when the OutputType is Library. From dotnet/android#4604, I think this will work for the Android scenario. Does that sound right to you @jonathanpeppers?

Note @vitek-karas @marek-safar @MichalStrehovsky this will make "library" "visible" root mode an officially supported feature for the first time - are we OK with this? If not, the alternative would be to use "all" to get the behavior from before dotnet/linker#3124.</comment_new>
<comment_new>@sbomer
Sorry, I just remembered that "library" has extra behavior which disables optimizations for when we are only trimming a single library against reference assemblies. I think what we actually want is "visible". @jonathanpeppers you might want to use RootMode="Visible" (or "All", to get the previous behavior) in your workaround instead, until we resolve this issue.</comment_new>
<comment_new>@sbomer
Another option, instead of using the assembly RootMode, would be to let the Android SDK tell the linker via XML descriptor which entry points to keep. Presumably there is an effective entry point (or multiple) for Android apps that is statically known, even if it's not encoded as such in the PE file. This option has slightly cleaner trimming behavior, but I don't like that it relies on the XML.</comment_new>
<comment_new>@MichalStrehovsky

Note @vitek-karas @marek-safar @MichalStrehovsky this will make "library" "visible" root mode an officially supported feature for the first time - are we OK with this? If not, the alternative would be to use "all" to get the behavior from before dotnet/linker#3124.

It's not clear to me what "publishing a self-contained library" actually means. (We only support trimming for selfcontained deployments.)

E.g. if we want to support #79377 with IL Linker, we would actually only want to root things with [UnmanagedCallersOnly(EntryPoint = "Foo")]. This is a definition for "publishing a self-contained library" that makes sense.

@jonathanpeppers what are the trimming roots in an Android application?</comment_new>
<comment_new>@marek-safar

Note @vitek-karas @marek-safar @MichalStrehovsky this will make "library" "visible" root mode an officially supported feature for the first time - are we OK with this? If not, the alternative would be to use "all" to get the behavior from before dotnet/linker#3124.

I'm not sure that's what we really want. My understanding of the scenario is that this is not library mode trimming but trimming with a custom entry point name that is hardcoded somewhere in XA interop. I think the expectation is that all public methods in such library will be trimmed. </comment_new>
<comment_new>@jonathanpeppers
Android has many roots, where Android/Java will call into managed code, such as:

  • Android.App.Application
  • Android.App.Activity's
  • Services
  • Broadcast receivers
  • Content providers
  • Views created from Android .xml
  • Probably more, I'm not thinking of

I think Android tried really hard to be "decoupled"...


💬 Send tasks to Copilot coding agent from Slack and Teams to turn conversations into code. Copilot posts an update in your thread when it's finished.

Co-authored-by: sbomer <787361+sbomer@users.noreply.github.com>
@dotnet-policy-service dotnet-policy-service bot added the linkable-framework Issues associated with delivering a linker friendly framework label Mar 17, 2026
Copilot AI changed the title [WIP] Fix new error in .NET 8 Android projects Skip entry-point trim roots for library outputs Mar 17, 2026
Copilot AI requested a review from sbomer March 17, 2026 20:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-Infrastructure-libraries linkable-framework Issues associated with delivering a linker friendly framework

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

New error in .NET 8 Android projects

2 participants