Generate built-in format registration for Native AOT - #77
Merged
Olof-Lagerkvist merged 4 commits intoSep 7, 2026
Merged
Conversation
Compose providers explicitly in the existing setup helpers, preserve and test the assembly guard's failure semantics, and cover direct and setup-helper registration under Native AOT. Document the supported transport and logical-volume extension points.
Derive valid C# namespace segments from assembly names while preserving the runtime assembly identity. Cover identifier characters, keywords, deterministic output and C# 7.3 compilation, and document the mapping.
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.
Registration is explicit and local to each format assembly. This refinement removes registration inferred from assembly references: an implementation dependency no longer changes which providers
Formats.Register()activates. Existing setup helpers compose the appropriate libraries explicitly, preserving their original provider selection and assembly order.Applications can register individual libraries:
Or use the existing
SetupComplete(),SetupContainers(),SetupFileSystems(),SetupTransports()or ExFAT setup helper. Helpers register Core first. Individual generated entry points contain no dependency calls; no dependency exception was necessary. Core's existing lazy partition/volume defaults and the reflection helper's Core initialization remain.Generated namespaces are now derived from the assembly name using identifier-safe sanitization of each dot-separated segment. Invalid identifier characters become
_; leading digits and reserved C# keywords receive an_prefix, and empty segments become_. Valid identifier characters and contextual keywords usable as namespace identifiers are preserved. For example,Acme.DiscUtils-PluginexposesAcme.DiscUtils_Plugin.Formats.Register()and123.Toolsexposes_123.Tools.Formats.Register(). Only the generated C# namespace/type name changes:typeof(Formats).Assemblystill passes the actual runtime assembly to the guard. No assembly/package rename, hashing or collision detection is introduced.The incremental generator keeps the five existing discovery attributes as its source of truth. Generated methods contain the common assembly guard and deterministic direct constructors/delegates for local providers. There is no reflection,
Activator, module initializer or separate generated initialization cache. The generator no longer inspects referenced assemblies for registration entry points.The library-wide opt-in remains for low maintenance. Projects without discovery attributes, including meta-packages, emit no registration code. Meta-packages expose their existing setup helpers. Core ships no registration analyzer or
buildTransitivemachinery. Applications need no DiscUtils generator, registration-related Roslyn version or C# 9 features;DUAOT002and consumer/module-initializer generation remain removed.Both third-party paths remain supported: normal JIT applications can discover attributed plugins with
DiscUtils.Setup.SetupHelper.RegisterAssembly(assembly), while external libraries can expose handwritten registration or build their ownMyLibrary.Formats.Register(). Applications explicitly call the compiled entry point. Reflection discovery retainsRequiresUnreferencedCodeannotations and uses the same extensible registries.DiskImageBuildersharesVirtualDiskManager's registry.The public transport base/attribute/delegate registration and logical-volume factory base/attribute/instance registration are intentional supported extension points. Documentation now says so explicitly, including the public
LogicalVolumeInfoconstructor for external mappings. Partition-table factory APIs remain internal.The once-per-assembly guard retains legacy failure semantics: it marks the assembly before invoking the callback. Repeated and recursive calls are ignored. If a callback throws, its exception propagates, partial registrations remain, and subsequent explicit or assembly-level reflection calls do not retry it. Focused tests now cover repeated/concurrent success, callback reentrance, generated-then-reflection, reflection-then-explicit, partial failure and attempts after failure.
Disk types, extensions and transport schemes remain case insensitive; conflict handling and file-system/volume registry ordering are unchanged. Third-party providers can still be added after built-in setup. See the updated registration documentation for initialization, extension and ordering details.
Validation on Ubuntu 24.04 x64, .NET SDK 10.0.100 and GCC 13.3. The full solution build and generator suite were rerun for the final namespace-only refinement; runtime and Native AOT results below are from the preceding registration revision:
SetupContainers()smoke paths passed in separate processes under both JIT and Native AOT. Native publish produced no trimming/AOT warnings.net46andnetstandard2.0using the optional generator. Its DLL-only consumer verified explicit, once-only registration under JIT and Native AOT. A C# 7.3/.NET Framework 4.6 consumer compiled with warnings treated as errors. Consumer builds explicitly reject a DiscUtils analyzer.git diff --checkpassed.Build/test commands:
The standalone package smoke was published with
-c Release -r linux-x64 -p:UsePackageReferences=true -p:DiscUtilsPackageVersion=1.0.88 -p:CppCompilerAndLinker=gcc, then run both without arguments and with--containers. The existing scratch-only workaround ran SDKComputeManagedAssembliesandILLinktasks in-process viaUsingTask Override="true"; no SDK or repository workaround changes are committed.Native execution covers representative VHD/FAT/partition/volume operations and registration of the container providers; it does not exercise every container format or actual LVM/dynamic-disk layouts. .NET Framework targets were compiled, not executed on this Linux host. Unrelated protocol reflection and implementation-specific trimming/native interop remain outside this registration change.
Existing package IDs, versions, target frameworks, CI/release workflows and repository metadata are unchanged. Target remains
LTRData.DiscUtils-initial. This updates PR #77 for manual review and further edits; it is not merged.