Fixed IL Trimming warnings on DesktopGL/WindowsDX by Lucasharskamp · Pull Request #8915 · MonoGame/MonoGame
added 4 commits
July 20, 2025 22:15sepcnt pushed a commit to sepcnt/MonoGame that referenced this pull request
Jul 26, 2025Fixes # The goal is simple: Publish builds that are AOT/Trimmed will not break randomly anymore at build/trim/publish time. All IL Warnings in DesktopGL/WindowsDX are resolved. (Not Android/iOS) They are gone from the build and resolved by either tackling the problem or applying a "good enough" bandaid. ### Description of Change Fixing IL trimmer warnings boils down to the API Contract; if we know at the time trimming happens (during AOT compilation) what shouldn't be trimmed from a specific type, we're golden. However, if a type's elements are needed because it gets dynamically invoked during runtime, and the trimmer doesn't know the type will be utilized for that, it can break. And yes, I am aware `[DynamicallyAccessedMembers(..)]` isn't magic; it doesn't check if X is in a type, it only ensures X won't be trimmed. (if it knows which type it shouldn't perform that action on). So, this PR can be broken down into several sections where different trimming problems get resolved: **1) "Pass the parcel" (VertexBuffer.cs, VertexDeclaration.cs,)** These are simple; just send up the callstack what we need from the generic type `T` or `Type type` that is being utilized; it usually becomes the problem of the assembly that is consuming the project now (e.g. through the NuGet Package). In most cases, the compiler of the consumer will take the hint and not trim the required bits of the type the user puts in there. In other cases, the compiler will throw a warning the user can resolve themselves. This should resolve any problem anyone may have regarding VertexBuffers. **2) ContentReaders** These are a bit trickier, but basically boil down to "anyone writing custom readers must ensure nothing gets trimmed from these readers". Unfortunately, we can't really throw warnings like "if you use `ContentTypeReader<T>`, please ensure nothing gets trimmed". So that's just a warning to put in the manual. I recommend adding a section to the following document to reflect that: https://docs.monogame.net/articles/getting_started/preparing_for_consoles.html **3) TypeConverters** The problem with `TypeConverter`s is that they were designed to be utilized during runtime by default, not set up during compile time. Which creates issues like: `TypeConverter conv = TypeDescriptor.GetConverter(typeof(Foo));` Of course the trimmer won't have a clue that it's not supposed to trim `FooConverter` (hence why all converters have a "retain everything" sticker on them), but _also_ that it shouldn't trim the bits and pieces of `Foo` the converter needs. In the case of MonoGame, this problem emerges because the converters try to convert from/to types that are derived from `IPackedVector`. Meaning: types derived from `IPackedVector` must still retain their interfaces and their public parameterless constructors. To resolve this, I've placed ''retain interfaces/public parameterless constructor'' on the types that derive from `IPackedVector` to ensure it wouldn't break that function. (But only if XNADESIGNPROVIDED is set, given that the type converters won't be used otherwise anyway) _(But so many of the types derived from `IPackedVector` don't even have public parameterless constructors for use by `Activator.CreateInstance(typeof(T))` in VectorConversions.cs->ConvertToFromVector4? But, naturally, anyone who wants to produce AOT/Trimmed versions of their product in MonoGame wouldn't likely even touch TypeConverters, but here we are, just in case)_ **4) Obsolete methods** A few method calls are obsolete, stating they shouldn't be used, in part because of the trimming problem of the actions inside the method. I just put a "disable the warning" on there - it's not a problem, it'll get dealt with anyway. Given that the `[Obsolete(...)]` throws a warning anyway, we can blindfold the compiler for the IL warnings without issue. ### Not changed **Android** Android has 2 unique IL warnings which boil down to the fact it has to utilize .NET Framework 4.5 methods and not their cleaner, better alternatives which were introduced in 4.5.1. Better to leave them there. There is nothing gained by blindfolding the compiler. **iOS** iOS has the same issue as Android; 2 unique IL warnings, but ''More modern alternatives exist, but .NET Framework 4.5 requirements''. (`AppContext.BaseDirectory` was introduced in .NET Framework 4.6, `Marshal.GetDelegateForFunctionPointer` has a better alternative in 4.5.1, as a comment above the method call laments this fact)
SimonDarksideJ pushed a commit that referenced this pull request
Jul 28, 2025Both Android and iOS using old .net 4.5 methods for `Enum.GetValues` and `Marshal.GetFunctionPointerForDelegate`. This commit updates them to use the modern `Enum.GetValues<T>()` and `Marshal.GetFunctionPointerForDelegate<T>()` methods. We also update iOS to use `AppContext.BaseDirectory` instead of `typeof(AL).Assembly.Location`, which is the correct property to use in .NET 6+. Context #8915
viniciusjarina pushed a commit to codefoco/MonoGame that referenced this pull request
Nov 7, 2025Fixes # The goal is simple: Publish builds that are AOT/Trimmed will not break randomly anymore at build/trim/publish time. All IL Warnings in DesktopGL/WindowsDX are resolved. (Not Android/iOS) They are gone from the build and resolved by either tackling the problem or applying a "good enough" bandaid. Fixing IL trimmer warnings boils down to the API Contract; if we know at the time trimming happens (during AOT compilation) what shouldn't be trimmed from a specific type, we're golden. However, if a type's elements are needed because it gets dynamically invoked during runtime, and the trimmer doesn't know the type will be utilized for that, it can break. And yes, I am aware `[DynamicallyAccessedMembers(..)]` isn't magic; it doesn't check if X is in a type, it only ensures X won't be trimmed. (if it knows which type it shouldn't perform that action on). So, this PR can be broken down into several sections where different trimming problems get resolved: **1) "Pass the parcel" (VertexBuffer.cs, VertexDeclaration.cs,)** These are simple; just send up the callstack what we need from the generic type `T` or `Type type` that is being utilized; it usually becomes the problem of the assembly that is consuming the project now (e.g. through the NuGet Package). In most cases, the compiler of the consumer will take the hint and not trim the required bits of the type the user puts in there. In other cases, the compiler will throw a warning the user can resolve themselves. This should resolve any problem anyone may have regarding VertexBuffers. **2) ContentReaders** These are a bit trickier, but basically boil down to "anyone writing custom readers must ensure nothing gets trimmed from these readers". Unfortunately, we can't really throw warnings like "if you use `ContentTypeReader<T>`, please ensure nothing gets trimmed". So that's just a warning to put in the manual. I recommend adding a section to the following document to reflect that: https://docs.monogame.net/articles/getting_started/preparing_for_consoles.html **3) TypeConverters** The problem with `TypeConverter`s is that they were designed to be utilized during runtime by default, not set up during compile time. Which creates issues like: `TypeConverter conv = TypeDescriptor.GetConverter(typeof(Foo));` Of course the trimmer won't have a clue that it's not supposed to trim `FooConverter` (hence why all converters have a "retain everything" sticker on them), but _also_ that it shouldn't trim the bits and pieces of `Foo` the converter needs. In the case of MonoGame, this problem emerges because the converters try to convert from/to types that are derived from `IPackedVector`. Meaning: types derived from `IPackedVector` must still retain their interfaces and their public parameterless constructors. To resolve this, I've placed ''retain interfaces/public parameterless constructor'' on the types that derive from `IPackedVector` to ensure it wouldn't break that function. (But only if XNADESIGNPROVIDED is set, given that the type converters won't be used otherwise anyway) _(But so many of the types derived from `IPackedVector` don't even have public parameterless constructors for use by `Activator.CreateInstance(typeof(T))` in VectorConversions.cs->ConvertToFromVector4? But, naturally, anyone who wants to produce AOT/Trimmed versions of their product in MonoGame wouldn't likely even touch TypeConverters, but here we are, just in case)_ **4) Obsolete methods** A few method calls are obsolete, stating they shouldn't be used, in part because of the trimming problem of the actions inside the method. I just put a "disable the warning" on there - it's not a problem, it'll get dealt with anyway. Given that the `[Obsolete(...)]` throws a warning anyway, we can blindfold the compiler for the IL warnings without issue. **Android** Android has 2 unique IL warnings which boil down to the fact it has to utilize .NET Framework 4.5 methods and not their cleaner, better alternatives which were introduced in 4.5.1. Better to leave them there. There is nothing gained by blindfolding the compiler. **iOS** iOS has the same issue as Android; 2 unique IL warnings, but ''More modern alternatives exist, but .NET Framework 4.5 requirements''. (`AppContext.BaseDirectory` was introduced in .NET Framework 4.6, `Marshal.GetDelegateForFunctionPointer` has a better alternative in 4.5.1, as a comment above the method call laments this fact)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters