Repository navigation
TypeMapLazyDictionary expects a single entrypoint assembly, which isn't a valid assumption on iOS and Android #120271
Description
Activity
dotnet-policy-service commented
on Sep 30, 2025 ContributorMore actionsTagging subscribers to this area: @dotnet/interop-contrib
See info in area-owners.md if you want to be subscribed.@jtschuster Those applications should call
Assembly.SetEntryAssembly()with the expected entry assembly. All should be able to determine the "main" on the .NET side. Please let us know if that is not the case.We should use this issue to also update the documentation.
@jtschuster @AaronRobinsonMSFT for clarification -
TypeMapLazyDictionaryis the dynamic implementation that's intended for Debug builds? I ran into this issue with Release builds where I expected ILLink to produce the type map at build-time. That makes me believe there are two problems: the first is at build time looking up the assembly attributes that define the typemap and the other one is at runtime locating the pre-built typemap. As far as I can tell we currently don't call theSetEntryAssemblymethod in dotnet/android, dotnet/macios, or dotnet/maui, but I'm sure we can add it a nd fix the runtime problem. Now since the managed code in Android and iOS apps are just a bunch of managed libraries and not executable assemblies, I believe there is no "entry point assembly" and so theTypeMapHandlerwon't find any of the associations:runtime/src/tools/illink/src/linker/Linker/TypeMapHandler.cs
Lines 42 to 68 in 2c3b2a6
public TypeMapHandler(AssemblyDefinition entryPointAssembly) { HashSet<AssemblyNameReference> assemblies = [AssemblyNameReference.Parse(entryPointAssembly.FullName)]; foreach (var attr in entryPointAssembly.CustomAttributes) { if (attr.AttributeType is not GenericInstanceType { Namespace: "System.Runtime.InteropServices", GenericArguments: [_] }) { continue; // Only interested in System.Runtime.InteropServices attributes } if (attr.AttributeType.Name != "TypeMapAssemblyTarget`1" || attr.ConstructorArguments[0].Value is not string str) { // Invalid attribute, skip it. // Let the runtime handle the failure. continue; } assemblies.Add(AssemblyNameReference.Parse(str)); } _lazyTypeMapResolver = new TypeMapResolver(assemblies); } I wonder if it might be simpler to add the option to explicitly pass a list of type map assemblies to illink/ilc and only fall back to the entry-point assembly if none are provided. We could then easily set the path(s) to the relevant assemblies through MSBuild.
I believe there is no "entry point assembly" and so the TypeMapHandler won't find any of the associations
I'd defer to @jkoritzinsky for the native AOT scenario - I understand your query. The counter to this though is the trimmer logic starts from somewhere. It can be an implicit "main" or the classic explciit
Main, but it starts from what is determines to be a root and then walks the method execution tree. There must be some root, implicit or explicit, in those scenarios so the trimmer knows where to start. We simply need to also set that in the above manner so the TypeMap can also know where to start.TypeMapLazyDictionary is the dynamic implementation that's intended for Debug builds?
The dynamic implementation of TypeMapLazyDictionary is meant to be used for both Debug and Release, except Native AOT.
it starts from what is determines to be a root and then walks the method execution tree.
Yes, it happens here in the linker:
runtime/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs
Lines 258 to 261 in a7d6c95
if (Annotations.GetEntryPointAssembly() is AssemblyDefinition entryPoint) { _typeMapHandler = new TypeMapHandler(entryPoint); } The entrypoint assembly is required to have Main method
var ep = assembly.MainModule.EntryPoint; if (ep == null) { Context.LogError(null, DiagnosticId.RootAssemblyDoesNotHaveEntryPoint, assembly.Name.ToString()); return; } Annotations.Mark(ep.DeclaringType, di, origin); Annotations.AddPreservedMethod(ep.DeclaringType, ep); Annotations.SetEntryPointAssembly(assembly); The question is whether we relax the requirement for entrypoint assembly to have the Main method so that it works for library-based applications too, or whether to we build a parallel scheme to pass around arbitrary typemap root assembly all the way from msbuild build targets. I think we can start with relaxing the requirement to see whether it works well.
the native AOT scenario
This mirrors the IL linker flow. For reference:
typeMapManager = new UsageBasedTypeMapManager(TypeMapMetadata.CreateFromAssembly(assembly, typeSystemContext)); It looks like the Android SDK sets the
TrimmerRootAssemblys (which ends up being the IntermediateAssembly) to have RootMode=All, which would have very different semantics from EntryPoint.case AssemblyRootMode.AllMembers: Annotations.SetRootAssembly(assembly); Annotations.Mark(assembly.MainModule, di, origin); return; We could treat all
TrimmerRootAssemblys as the roots for the TypeMap without having to add a new option. It doesn't look like it would be too complex to extend the implementation to handle this.If we want to enforce a single EntryPoint assembly as the TypeMap root, we'll likely need to support using different RootMode trimming semantics for the EntryPoint assembly (like
Library,Visible,All).It looks like the Android SDK sets the TrimmerRootAssembly
AFAIK this is something we would like to remove as soon as we can use the type map API.
Closing this and using #121138 to track the trimming work to enable TypeMap on library apps.
- locked and limited conversation to collaborators
on Nov 28, 2025
Metadata
Metadata
Assignees
Type
Projects
- StatusShow more project fieldsNo status
The TypeMap API expects that there is a single entrypoint assembly from which TypeMapAssemblyTargetAttributes can point to other assemblies to create the entire typemap. This assumption isn't valid on iOS or Android where .NET is called into from native code. See below
runtime/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/TypeMapLazyDictionary.cs
Line 192 in 2c9fdf0
cc. @AaronRobinsonMSFT @simonrozsival
#113362 to link the issues