Fixes #5069. ConfigurationManager is trim-safe without TrimmerRootAssembly#5071
Merged
tig merged 6 commits intogui-cs:developfrom Apr 26, 2026
Merged
Conversation
…ootAssembly
ConfigProperty.Initialize() previously relied on a reflection scan of
AppDomain.CurrentDomain.GetAssemblies() to locate [ConfigurationProperty]
host types. Under PublishTrimmed=true, types not otherwise referenced by
the consumer were stripped and Scope<T>.GetUninitializedProperty("Theme")
would throw at startup - forcing AOT apps to carry
<TrimmerRootAssembly Include="Terminal.Gui" />, adding ~1.5 MB per binary.
Terminal.Gui's own host types are now declared statically in a new
internal ConfigPropertyHostTypes registry and rooted via
[DynamicDependency(PublicProperties, typeof(X))] so the trimmer preserves
the properties the initializer depends on. The AppDomain scan is retained
as a JIT-only supplement (gated on RuntimeFeature.IsDynamicCodeSupported)
so test suites and external consumers with their own [ConfigurationProperty]
properties continue to be discovered automatically in non-AOT builds.
Examples/NativeAot drops the TrimmerRootAssembly workaround.
A new parallelizable unit test asserts the static registry matches the set
of types reflected at runtime, so drift between the list and new
[ConfigurationProperty] additions is caught at build time.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Makes ConfigurationManager initialization trim-/AOT-safe by avoiding a reflection scan of all loaded assemblies in AOT scenarios, eliminating the need for TrimmerRootAssembly in NativeAOT consumers.
Changes:
- Added a static, trimmer-rooted registry of Terminal.Gui types that host
[ConfigurationProperty]properties. - Updated
ConfigProperty.Initialize()to register the static list first and only perform the AppDomain assembly scan when dynamic code is supported. - Removed the NativeAOT example’s
TrimmerRootAssemblyworkaround and added a guard-rail unit test to prevent registry drift.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| Tests/UnitTestsParallelizable/Configuration/ConfigPropertyHostTypesTests.cs | Adds a drift-detection test to ensure the static host-type registry stays in sync with attribute usage. |
| Terminal.Gui/Configuration/ConfigPropertyHostTypes.cs | Introduces the static registry of [ConfigurationProperty] host types with DynamicDependency rooting for trimming. |
| Terminal.Gui/Configuration/ConfigProperty.cs | Registers the static host list unconditionally; performs reflection scanning only when RuntimeFeature.IsDynamicCodeSupported is true. |
| Examples/NativeAot/NativeAot.csproj | Drops TrimmerRootAssembly Include="Terminal.Gui" now that config init is intended to be trim-safe. |
tig
approved these changes
Apr 26, 2026
This was referenced Apr 30, 2026
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ConfigProperty.Initialize()previously relied on a reflection scan ofAppDomain.CurrentDomain.GetAssemblies()to locate[ConfigurationProperty]host types. UnderPublishTrimmed=true, types not otherwise referenced by the consumer were stripped andScope<T>.GetUninitializedProperty(\"Theme\")would throw at startup — forcing AOT apps to carry<TrimmerRootAssembly Include=\"Terminal.Gui\" />, adding ~1.5 MB per binary.Changes
Terminal.Gui/Configuration/ConfigPropertyHostTypes.cs— internal static registry listing the 29 types in Terminal.Gui that own[ConfigurationProperty]properties. Each entry is rooted with[DynamicDependency(PublicProperties, typeof(X))]so the trimmer preserves the properties the initializer depends on.Terminal.Gui/Configuration/ConfigProperty.cs—Initialize()unconditionally registers the static list first, then falls back to the originalAppDomainscan only whenRuntimeFeature.IsDynamicCodeSupportedis true (i.e., JIT, not AOT). External consumers and tests that define their own[ConfigurationProperty]properties continue to be auto-discovered in non-AOT builds.Examples/NativeAot/NativeAot.csproj— drops the<TrimmerRootAssembly Include=\"Terminal.Gui\" />workaround.Tests/UnitTestsParallelizable/Configuration/ConfigPropertyHostTypesTests.cs— asserts that the static registry matches the set of types reflected from the Terminal.Gui assembly at runtime, so any new[ConfigurationProperty]added to a previously-unlisted type fails the build.Scope
Intentionally minimal. The
[RequiresUnreferencedCode]/[RequiresDynamicCode]annotations onConfigurationManagerandApplication.Initare left in place — removing those propagates through a large public API surface and is out of scope for this fix. This PR addresses the core bug: AOT apps no longer needTrimmerRootAssemblyand won't crash at startup.Referenced issues / prior art
Test plan
dotnet build Terminal.Gui/Terminal.Gui.csproj— 0 warnings, 0 errorsdotnet build Tests/UnitTestsParallelizable— 0 warnings, 0 errorsUnitTests.Parallelizablefull run: 16395 passed / 0 failed / 17 skipped (all pre-existing skips)ConfigPropertyHostTypesTestspasses and will catch drift if a future type adds[ConfigurationProperty]without being listedExamples/NativeAotpublish for linux-x64 — ILC trim analysis completes with no type-stripped errors. The NativeAot's gcc link step fails in the local WSL environment (gcc: error: unrecognized command-line option '--target=x86_64-linux-gnu'), but the managed/trim analysis step — the only part this PR changes — succeeds. Full native-link verification is appropriate for the repo's CI matrix.To pull down this PR locally:
🤖 Generated with Claude Code