Skip to content

Latest commit

Β 

History

History
86 lines (66 loc) Β· 4.14 KB

File metadata and controls

86 lines (66 loc) Β· 4.14 KB

windows-metadata

A low-level reader and writer for the ECMA-335 metadata format.

windows-metadata reads and writes the ECMA-335 metadata format used by .NET, WinRT, and the Win32 metadata. It is the foundation windows-bindgen builds on. The reader::Index type loads one or more .winmd files and lets you query namespaces, type definitions, and their members.


Internal documentation

The remainder of this page covers how the crate is built and maintained. It is for contributors and is not needed to use windows-metadata.

How it's built

Consumed by windows-bindgen. src/bindings.rs is generated by tool_bindings from crates/tools/bindings/src/metadata.txt; the ECMA-335 tables and readers are hand-written.

Multi-arch merge

windows-metadata's merge module coalesces the per-architecture winmds that tool_win32 scrapes (x64, arm64, x86) into a single winmd. A type identical across every arch is emitted once as arch-neutral; a type that diverges is split into per-arch copies, each tagged with a SupportedArchitectureAttribute (spelled #[arch(X86|X64|Arm64)] in RDL).

The collapse-or-split decision is structural, driven by type_sig() β€” a hash of everything that can legitimately differ between architectures:

  • fields β€” name, type, and constant value (so an enum whose members hold different per-arch values splits instead of silently dropping the divergent values);
  • method signatures β€” Win32 callbacks and WinRT delegates have no fields and diverge only in their Invoke signature, so a fields-only signature would wrongly collapse arch-divergent callbacks into one untagged copy;
  • layout β€” #pragma pack and ClassLayout;
  • AlignmentAttribute β€” __declspec(align(N)) raised alignment is encoded only by that attribute (ClassLayout can only lower alignment), so a type that differs solely in forced over-alignment must fold the attribute into the signature or the divergent copy is lost;
  • flags β€” the type's attribute flags.

Types present on only a subset of arches still go through the same structural split, so a type that is present on x64+arm64 (but not x86) and diverges between those two is split per arch rather than collapsing to whichever copy happened to be first. A group is emitted arch-neutral only when its signature spans every arch in the run.

The merge is deterministic: it stages through BTreeMaps and insertion-ordered Vecs, with no HashMap reaching the output.

Determinism and the winmd writer

The writer is the foundation of the pipeline's reproducible builds. It stages Constant / Attribute / GenericParam (and the bindgen TypeTree) in BTreeMaps / BTreeSets, and the module MVID is a fixed zero GUID, so regenerating a winmd is byte-for-byte identical across platforms (CI validates the committed winmds on Linux).

Notable invariants in the ECMA-335 tables:

  • The HasSemantics coded index and the Property/Event/MethodSemantics tables are emitted only when non-empty, and MethodSemantics rows are sorted by Association β€” strict readers reject an unsorted table.
  • write_index asserts on the run-list one-past-end sentinel rather than silently wrapping to 0 for a target table with exactly 65535 rows (the guard lives on the write side so the reader's width threshold stays ECMA-conformant for external winmds).
  • Value::Bool constants round-trip symmetrically (the reader maps ELEMENT_TYPE_BOOLEAN); the CLR element-type vocabulary (ELEMENT_TYPE_*) is hand-authored in src/clr.rs because its defining header (corhdr.h) ships only in the .NET SDK and cannot be scraped.

Testing

Run cargo test -p windows-metadata; see also the workspace test crates. The arch-merge collapse/split rules are pinned by arch_roundtrip.rs (divergent fields, callbacks, forced alignment, enum constant values, subset-present divergence).