Skip to content

Support for WDK - #177

Open
IridiumXOR wants to merge 3 commits into
Jake-Shadle:mainfrom
IridiumXOR:main
Open

Support for WDK#177
IridiumXOR wants to merge 3 commits into
Jake-Shadle:mainfrom
IridiumXOR:main

Conversation

@IridiumXOR

Copy link
Copy Markdown

Hi
I have added the support for WDK using an AI tool. I have tested it and seems to work. Here a more detailed resume on changes. I hope that you will take into consideration the contribution :)

New options:

  --include-wdk            acquire the WDK alongside the CRT and SDK
  --wdk-version <ver>      pin the WDK version
  --kmdf-version <ver>     pin the KMDF version splatted from it
  --umdf-version <ver>     pin the UMDF version splatted from it
  xwin list --wdk-versions list every WDK version published, marking the one
                           that would be used and the ones matching your SDK

The WDK is splatted to its own root next to crt/ and sdk/:

  splat/wdk
  |-- include
  |   |-- km  |-- shared  |-- um
  |   `-- wdf/{kmdf,umdf}/<ver>
  `-- lib
      |-- km/<arch>  |-- um/<arch>
      `-- wdf/{kmdf,umdf}/<arch>/<ver>

src/nuget.rs (new)
WDK discovery. Version list from the nuget flat container index.json,
deterministic .nupkg URL, and the SHA-512 + size from the registration ->
catalog entry. Version selection and the payload list live here.

Note these small JSON documents are fetched with ctx.client directly rather
than Ctx::get_and_validate, because that helper returns any cached file as-is
when there is no checksum to validate against, which would have pinned the WDK
to whatever version was newest the first time xwin ran.

src/util.rs
nuget publishes base64 SHA-512 while the VS manifests use hex SHA-256, so
Payload.sha256 became Payload.checksum: Checksum, an enum over the two. Base64
decoding is ~15 lines by hand rather than a new dependency; sha2 was already
there.

src/download.rs, src/unpack.rs
.nupkg dispatches to a new zip unpack arm. It keeps only c/Include and c/Lib
and normalises them to the lowercase include/ and lib/ shape that the MSI path
already produces, dropping the interstitial SDK version directory the same way
the MSI Directory table walk does. Everything else in the package (bin, build,
tools, certificates) is discarded.

src/splat.rs
New PayloadKind::Wdk and a wdk root in SplatRoots, following the VcrDebug
precedent. The mapping arm emits several mappings per payload, like the Ucrt
one does.

src/main.rs
The new flags, plus the WDK payloads are appended after prune_pkg_list rather
than inside it, so prune_pkg_list stays a pure function over a manifest and
the hermetic deterministic test is unaffected.

src/minimize.rs
Only the two SectionKind arms needed to compile. minimize drives a regular
cargo build, which never compiles a driver, so it does not minimize WDK
content. This is stated in the README.

Test units:

  • tests/driver.rs (new): runs the whole pipeline from a cold cache and then
    compiles AND links a minimal KMDF driver with clang-cl/lld-link, producing a
    real PE32+ native x86-64 image. It also asserts the canonical-casing symlinks
    exist and that bin/build/tools were pruned. Deliberately linked using the
    Microsoft casing (WdfLdr.lib etc.) so a regression in (c) fails the test.

  • Added a dedicated CI job for it. It is named verify_driver_compiles rather than
    verify_compiles_* so the existing job's test filter does not pull it in.

  • verify_deterministic, cli_help and the library unit tests all pass. New unit
    tests cover checksum round-tripping, base64 SHA-512, prerelease filtering and
    SDK/WDK pairing.

  • cargo fmt --check and cargo clippy --all-targets --all-features -- -D warnings
    are both clean.

Notes:

  • Separate wdk/ root rather than merging into sdk/.
    The WDK's km, shared and um headers are not interchangeable with the SDK's.
    Both kits ship a d3dkmddi.h, and the WDK itself ships km/ucm/1.0/UcmManager.h
    and um/ucm/1.0/UcmManager.h as different files. Merging produced a real
    collision on the first run.

  • Header casing fixups are namespaced per include directory.
    finalize_splat previously had one namespace keyed by lowercased relative
    path, with a hard error when two entries differ. That is correct for the SDK,
    where um/shared/winrt share one include path, but wrong for the WDK. The scan
    is now grouped by root: one namespace per include directory, while the set of
    referenced includes stays global across them, so km -> shared references are
    still fixed up.

  • Library casing is scraped from the kit's own msbuild props.
    Every WDK library is lowercase on disk, but Microsoft's props link them as
    WdfLdr.lib, WdfDriverEntry.lib, BufferOverflowFastFailK.lib and 13 others -
    casing that neither lowercasing nor uppercasing can produce, and which a
    hardcoded table would have to chase forever. The unpack step scrapes the
    .props/.targets shipped inside the package for .lib references, records the
    ones that need it, and splat turns them into symlinks. Self-updating with the
    kit. Without this a driver compiles but does not link.

  • The default WDK pairs with the SDK, not "newest".
    The WDK nuspec declares a dependency on the exact SDK build (eg WDK 26100 ->
    Microsoft.Windows.SDK.cpp.x64 [10.0.26100, 10.0.26101)). The default is
    therefore the newest WDK whose build matches the resolved SDK, falling back to
    the newest overall with a warning. list --wdk-versions calls the same
    resolution function used for acquisition, so the marker cannot drift from what
    you would actually get.

  • Second license prompt.
    The WDK ships under its own terms (Microsoft pre-release terms for the WDK and
    Hardware Lab Kit). Those terms exist only as a LICENSE.txt embedded in the
    package - the nuspec's licenseUrl is nuget's "this field is deprecated" page,
    and Microsoft's WDK download page has no EULA link. So the prompt points at
    nuget's copy of that exact file for the resolved version, which means it
    always describes precisely the bytes being downloaded. It appears only with
    --include-wdk, and --accept-license / XWIN_ACCEPT_LICENSE covers both prompts.

  • x86_64 and aarch64 only. There are no x86 or arm WDK packages. Requesting
    those logs a warning and produces no WDK output for them.

  • Kits from 10.0.26100 onwards only. Older ones exist only behind wdksetup.exe.

  • Each requested architecture is a separate ~110 MB download that contains a full
    duplicate of the (architecture independent) headers. Only the first
    architecture's headers are splatted; libraries come from all of them.

  • Only one KMDF and one UMDF version is splatted (newest by default). The package
    ships ~10 of each side by side.

  • The architecture macros normally set by the WDK's msbuild props (AMD64 etc.)
    are not set by the compiler, so a kernel compile needs them passed explicitly.
    Documented in the README with a worked example.

@IridiumXOR
IridiumXOR requested a review from Jake-Shadle as a code owner July 27, 2026 22:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant