Skip to content

feat: add linker directive for VHF lib + move static linker directives from wdk-build to wdk-sys - #685

Open
Alan632 wants to merge 41 commits into
microsoft:mainfrom
Alan632:vhf_lib_linker_args-v2
Open

feat: add linker directive for VHF lib + move static linker directives from wdk-build to wdk-sys#685
Alan632 wants to merge 41 commits into
microsoft:mainfrom
Alan632:vhf_lib_linker_args-v2

Conversation

@Alan632

@Alan632 Alan632 commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds conditionally compiled linker directives for the VHF library tied to the "hid" feature.

Moves build script emitted static linker directives (cargo::rustc-link-lib=static=*) from wdk-build/src/lib.rs into bindgen generated files as conditionally compiled attributes. The Rust source insertion happens in wdk-sys/build.rs while the backend logic and Rust source string build lives in wdk-build/src/lib.rs (closely following the pattern the bindgen generated headers use). This allows conditional compilation of linker directives (and eventually link args) without having to rely on cross crate feature signaling, and guards against issues from version drift (in case multiple versions of wdk-build are used in one project).

This PR is a redesign of and supersedes PR!653.

Verification

Verified both kmdf and umdf drivers built with "hid" and Vhf functions linked against VhfKm.lib and VhfUm.lib respectively. Additionally, inspected each driver's linker .map file for evidence of the respective Vhf symbols.

Bindgen generated files are also inspected post build for the presence of the link attributes.

… directives from wdk-build/src/lib.rs into wdk-sys/build.rs
Copilot AI lite review requested due to automatic review settings June 18, 2026 18:48
@Alan632 Alan632 self-assigned this Jun 18, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates how native WDK libraries are linked by moving static rustc-link-lib directives out of wdk-build’s configure_binary_build prints and into wdk-sys’s generated bindings via #[link(...)] attributes. It also adds conditional linker directives for the VHF library when the hid feature is enabled, selecting VhfKm vs VhfUm based on driver model.

Changes:

  • Emit base driver-model-specific native library link directives into bindgen output (ntddk.rs/windows.rs) from wdk-sys/build.rs.
  • Add hid-gated #[link] directives for VhfKm (KMDF/WDM) and VhfUm (UMDF).
  • Remove the corresponding cargo::rustc-link-lib=static=* emissions from wdk-build::Config::configure_binary_build (leaving link-arg prints in place).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
crates/wdk-sys/build.rs Adds a reusable #[link] directive helper and injects conditional link directives into generated bindings (including VHF for hid).
crates/wdk-build/src/lib.rs Stops emitting static rustc-link-lib lines (now handled by wdk-sys), retaining cdylib link-args and documenting future move.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread crates/wdk-sys/build.rs Outdated
Comment thread crates/wdk-build/src/lib.rs Outdated
Comment thread crates/wdk-sys/build.rs Outdated
@codecov-commenter

Codecov Comments Bot (codecov-commenter) commented Jun 18, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 81.06%. Comparing base (f11b762) to head (f26ffc6).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #685      +/-   ##
==========================================
+ Coverage   80.47%   81.06%   +0.59%     
==========================================
  Files          26       26              
  Lines        5720     5899     +179     
  Branches     5720     5899     +179     
==========================================
+ Hits         4603     4782     +179     
  Misses        989      989              
  Partials      128      128              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI review requested due to automatic review settings June 18, 2026 23:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

Comment thread crates/wdk-build/src/lib.rs Outdated
Comment thread crates/wdk-build/src/lib.rs
Comment thread crates/wdk-build/src/lib.rs
Comment thread crates/wdk-build/src/lib.rs Outdated
Comment thread crates/wdk-build/src/lib.rs Outdated
Comment thread crates/wdk-sys/build.rs Outdated
Comment thread crates/wdk-build/src/lib.rs Outdated
Comment thread crates/wdk-build/src/lib.rs Outdated
Comment thread crates/wdk-build/src/lib.rs Outdated
Alan Ngo added 2 commits June 19, 2026 11:29
…utes out when building non-driver test wdk-sys-tests (wdk-sys-tests does not call configure_binary_build thus no search paths are emitted and ungated link attributes fail the build/test)
…on, library selection, and link directive string creation)

-removed raw strings in lieu of types to tightly constrain LinkDirective creation w/o needing assert checks
-removed and compacted unneeded functions from original implementation
Copilot AI review requested due to automatic review settings June 19, 2026 23:42

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

… attributes to ensure wdk-sys builds correctly when compiled for test

- add unit tests
- add PartialEq and Eq traits to LinkKind, LinkModifier, and LinkDirective
@Alan632
Alan632 marked this pull request as ready for review June 23, 2026 00:45
Copilot AI review requested due to automatic review settings June 23, 2026 00:45

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work. Few changes here and there but the overall shape is very solid!

Comment thread tests/wdk-sys-tests/Cargo.toml
Comment thread crates/wdk-build/src/lib.rs Outdated
Comment thread crates/wdk-build/src/lib.rs Outdated
Comment thread crates/wdk-build/src/lib.rs Outdated
Comment thread crates/wdk-build/src/lib.rs Outdated
Comment thread crates/wdk-build/src/lib.rs Outdated
Comment thread crates/wdk-build/src/lib.rs
Comment thread crates/wdk-build/src/lib.rs Outdated
Comment thread crates/wdk-build/src/lib.rs Outdated
Comment thread tests/wdk-sys-tests/Cargo.toml
Copilot AI review requested due to automatic review settings July 2, 2026 16:45

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated no new comments.

Suppressed comments (4)

examples/sample-wdm-driver/src/lib.rs:82

  • The new unit test calls driver_exit(), which uses wdk::println!. In WDM/KMDF, that routes through wdk_sys::ntddk::DbgPrint, but this PR also cfg-suppresses the #[link] directives during tests (cfg(test) / omit-wdk-libs). That combination is likely to produce an unresolved external for DbgPrint when running cargo test on this example. Prefer a test that only references bindgen types/consts (compile+link proof) without calling into WDK APIs.
    fn test_driver_exit() {
        use super::*;

        driver_exit(core::ptr::null_mut())
    }

examples/sample-kmdf-driver/src/lib.rs:195

  • The new unit test calls driver_exit(), which uses wdk::println! and will ultimately reference WDK symbols (e.g., DbgPrint) that are no longer linked in test builds due to cfg-suppressed #[link] directives. This is likely to break cargo test for this example. Consider switching the test to a pure type/const assertion that still proves the cdylib can host tests without requiring WDK libs.
    #[test]
    fn test_driver_exit() {
        use super::*;

        driver_exit(core::ptr::null_mut())

crates/wdk-sys/src/test_stubs.rs:36

  • The module docs still say WdfDriverGlobals is intentionally not stubbed and that enabling test-stubs may fail to link because it’s missing, but this file now defines a WdfDriverGlobals stub. Update the docs to reflect the current behavior and clarify that calling real WDF APIs is still unsupported under stubs.
//!   - If "test-stubs" is enabled the Linker may complain that
//!     `WdfDriverGlobals` is missing, it is intentionally not stubbed here
//!     because it is needed when a WDF function is called, landing it outside
//!     the intent of test-stubs.

tests/mixed-package-kmdf-workspace/crates/driver/Cargo.toml:26

  • This comment contradicts the dependency directly below it: it says the "test-stubs" feature isn’t needed and should be switched on later, but the dev-dependency already enables it. Please update/remove the comment so it matches the actual configuration and intent for tests.
# The feature "test-stubs" isn't needed since gating the DriverEntry export_name keeps
# driver_entry from being codegen'd, so nothing references WDF functions. Switch to "test-stubs"
# if a test ever reaches a call_unsafe_wdf_function_binding! call site.
wdk-sys = { features = ["test-stubs"], workspace = true }

Copilot AI review requested due to automatic review settings August 4, 2026 17:11

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated no new comments.

Suppressed comments (2)

crates/wdk-sys/src/test_stubs.rs:36

  • The doc comment says WdfDriverGlobals is "intentionally not stubbed", but the module now defines a WdfDriverGlobals stub below. This is misleading for users enabling test-stubs and should be updated to match the current behavior (and ideally clarify that calling real WDF functions still requires proper mocks).
//!   - If "test-stubs" is enabled the Linker may complain that
//!     `WdfDriverGlobals` is missing, it is intentionally not stubbed here
//!     because it is needed when a WDF function is called, landing it outside
//!     the intent of test-stubs.

tests/mixed-package-kmdf-workspace/crates/driver/Cargo.toml:25

  • This comment states that the "test-stubs" feature isn't needed, but the dependency below explicitly enables it. That contradiction makes it unclear whether this dev-dependency is intentional. Either remove the feature flag or update the comment to explain why test-stubs is enabled for tests.
# The feature "test-stubs" isn't needed since gating the DriverEntry export_name keeps
# driver_entry from being codegen'd, so nothing references WDF functions. Switch to "test-stubs"
# if a test ever reaches a call_unsafe_wdf_function_binding! call site.

@wmmc88 Melvin Wang (wmmc88) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor nits, but otherwise good to go. Also create a bug documenting the all-targets of cdylib defect, and assign it to me

Comment thread examples/sample-kmdf-driver/src/lib.rs
Comment thread examples/sample-kmdf-driver/src/lib.rs
Comment thread examples/sample-umdf-driver/src/lib.rs
Comment thread examples/sample-wdm-driver/src/lib.rs
Comment thread crates/wdk-sys/Cargo.toml Outdated
…k-linking" for clarity

- add documentation for the cfg gate on driver_entry export_name for the sample drivers
- add documentation for the dummy sample driver unit tests
Copilot AI review requested due to automatic review settings August 5, 2026 22:55

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated no new comments.

Suppressed comments (5)

examples/sample-wdm-driver/src/lib.rs:86

  • This unit test calls driver_exit, which uses wdk::println! (routes through wdk_sys::ntddk::DbgPrint). When wdk-sys is built with test-stubs/suppress-wdk-linking, the generated #[link] directives are suppressed, so tests may fail to link because DbgPrint isn't provided. Prefer a test that only references bindgen-generated types/constants (no calls into WDK).
    fn test_driver_exit() {
        use super::*;

        driver_exit(core::ptr::null_mut())
    }

examples/sample-kmdf-driver/src/lib.rs:200

  • This unit test calls driver_exit, which uses wdk::println! (routes through wdk_sys::ntddk::DbgPrint). With wdk-sys built using test-stubs/suppress-wdk-linking, the generated #[link] directives are suppressed, so tests may fail to link due to missing DbgPrint. Prefer a test that only references bindgen-generated types/constants (no calls into WDK/WDF).
    fn test_driver_exit() {
        use super::*;

        driver_exit(core::ptr::null_mut())
    }

crates/wdk-sys/src/test_stubs.rs:36

  • The doc comment still says WdfDriverGlobals is intentionally not stubbed, but the module now defines a stub WdfDriverGlobals. This is misleading for users trying to understand what test-stubs guarantees and what remains unsafe to call in tests.
//!   - If "test-stubs" is enabled the Linker may complain that
//!     `WdfDriverGlobals` is missing, it is intentionally not stubbed here
//!     because it is needed when a WDF function is called, landing it outside
//!     the intent of test-stubs.

examples/sample-umdf-driver/src/lib.rs:187

  • This unit test calls evt_driver_unload, which uses wdk::println! (routes through wdk_sys::windows::OutputDebugStringA in UMDF). With wdk-sys built using test-stubs/suppress-wdk-linking, the generated #[link] directives are suppressed, so tests may fail to link if the required system libs aren't linked. Prefer a test that only references bindgen-generated types/constants (no calls into UMDF/WDF).
    fn test_driver_exit() {
        use super::*;

        evt_driver_unload(core::ptr::null_mut())
    }

tests/mixed-package-kmdf-workspace/crates/driver/Cargo.toml:26

  • The comment says test-stubs isn't needed and suggests switching to it later, but the dependency below already enables features = ["test-stubs"]. This is confusing for readers trying to understand why the feature is enabled for tests.
# The feature "test-stubs" isn't needed since gating the DriverEntry export_name keeps
# driver_entry from being codegen'd, so nothing references WDF functions. Switch to "test-stubs"
# if a test ever reaches a call_unsafe_wdf_function_binding! call site.
wdk-sys = { features = ["test-stubs"], workspace = true }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great work :)

Comment thread crates/wdk-build/src/lib.rs Outdated
Copilot AI review requested due to automatic review settings August 6, 2026 22:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated no new comments.

Suppressed comments (5)

crates/wdk-sys/src/test_stubs.rs:36

  • The module docs explicitly say WdfDriverGlobals is intentionally not stubbed, but the code now stubs it (to a null pointer). Please update the NOTE to match the new behavior and clearly warn that any call into WDF using this stub will likely crash/UB unless tests provide a real mock for WdfDriverGlobals.
//! NOTE: Enabling fat LTO in your dev profile may lead to Linker errors
//! even if you sufficiently cfg gate WDF function usage. This is because
//! the dev profile defaults to `opt-level = 0`, and in combination with fat
//! LTO may cause dead code to not be optimized out (fat LTO merges all upstream
//! crates' code into the final binary rather than letting the linker pull in
//! only what's needed, so WDF wrappers from an ungated `use wdk::` get
//! included even if you never call them).
//!   - If "test-stubs" is enabled the Linker may complain that
//!     `WdfDriverGlobals` is missing, it is intentionally not stubbed here
//!     because it is needed when a WDF function is called, landing it outside
//!     the intent of test-stubs.

crates/wdk-sys/src/test_stubs.rs:87

  • The module docs explicitly say WdfDriverGlobals is intentionally not stubbed, but the code now stubs it (to a null pointer). Please update the NOTE to match the new behavior and clearly warn that any call into WDF using this stub will likely crash/UB unless tests provide a real mock for WdfDriverGlobals.
    /// Stubbed version of `WdfDriverGlobals` Symbol so that test targets will
    /// link.
    // SAFETY: WdfDriverGlobals is a required WDF symbol for test compilation.
    // No other symbols in this crate export this name, preventing linker conflicts.
    #[unsafe(no_mangle)]
    pub static mut WdfDriverGlobals: PWDF_DRIVER_GLOBALS = core::ptr::null_mut();

tests/mixed-package-kmdf-workspace/crates/driver/Cargo.toml:26

  • This comment contradicts the dependency declaration: it says test-stubs isn't needed and should only be enabled if tests reach a WDF call site, but test-stubs is enabled unconditionally here. Either remove/adjust the comment to reflect why test-stubs is always enabled for tests, or drop the feature until it’s actually required.
# The feature "test-stubs" isn't needed since gating the DriverEntry export_name keeps
# driver_entry from being codegen'd, so nothing references WDF functions. Switch to "test-stubs"
# if a test ever reaches a call_unsafe_wdf_function_binding! call site.
wdk-sys = { features = ["test-stubs"], workspace = true }

examples/sample-kmdf-driver/src/lib.rs:200

  • This test calls driver_exit, which (per its definition) executes wdk::println!. That can pull in WDK-dependent symbols even when #[link] directives are suppressed, undermining the goal of 'without linking WDK libs' and potentially causing link failures (or runtime issues) in test builds. Prefer a test that only references bindgen-generated types/constants (like the WDF_DRIVER_CONFIG size test in the mixed-package driver), or gate the printing path behind #[cfg(not(test))] so the test doesn't exercise WDK print paths.
    /// Dummy test to ensure `test` targets compile correctly 
    /// without linking WDK libs
    #[test]
    fn test_driver_exit() {
        use super::*;

        driver_exit(core::ptr::null_mut())
    }

examples/sample-umdf-driver/src/lib.rs:186

  • Same issue as the KMDF sample: evt_driver_unload prints via wdk::println!, which can introduce WDK symbol dependencies in a test build that is intended to avoid linking WDK libs. Consider changing this to a non-WDK-symbol-requiring assertion (e.g., type size/invariants) or ensuring the print path is #[cfg(not(test))].
    /// Dummy test to ensure `test` targets compile correctly 
    /// without linking WDK libs
    #[test]
    fn test_driver_exit() {
        use super::*;

        evt_driver_unload(core::ptr::null_mut())
    }

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

Suppressed comments (4)

examples/sample-wdm-driver/src/lib.rs:85

  • This test calls driver_exit, whose println! expansion reaches wdk_sys::ntddk::DbgPrint. The enabled test-stubs feature suppresses the new ntoskrnl link directive and does not define DbgPrint, so this test binary has an unresolved external instead of demonstrating library-free linking. Keep this as a compile/link smoke test by asserting on a generated type (as the mixed-package test does), or add a real DbgPrint mock.
        driver_exit(core::ptr::null_mut())

examples/sample-kmdf-driver/src/lib.rs:199

  • This invokes driver_exit, and its println! calls ultimately reference DbgPrint. test-stubs suppresses the ntoskrnl link directive but does not stub DbgPrint, leaving this test executable with an unresolved symbol. Use a generated-type assertion for the intended compile/link smoke test, or provide a functional DbgPrint mock.
        driver_exit(core::ptr::null_mut())

crates/wdk-sys/src/test_stubs.rs:36

  • This newly added note says WdfDriverGlobals is intentionally not stubbed, but this same change defines it at line 87. That contradiction obscures the actual limitation: the null stub permits linking but cannot support calls through the WDF function table.
//!   - If "test-stubs" is enabled the Linker may complain that
//!     `WdfDriverGlobals` is missing, it is intentionally not stubbed here
//!     because it is needed when a WDF function is called, landing it outside
//!     the intent of test-stubs.

tests/mixed-package-kmdf-workspace/crates/driver/Cargo.toml:25

  • The comment says test-stubs is not needed and suggests switching to it later, while the dependency immediately below already enables it. It also incorrectly states that removing export_name prevents driver_entry from being code-generated; cfg_attr only removes the export attribute. Document the actual reasons for the feature and gate instead.
# The feature "test-stubs" isn't needed since gating the DriverEntry export_name keeps
# driver_entry from being codegen'd, so nothing references WDF functions. Switch to "test-stubs"
# if a test ever reaches a call_unsafe_wdf_function_binding! call site.
  • Files reviewed: 19/19 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

@Alan632
Alan632 enabled auto-merge August 7, 2026 18:16
@Alan632
Alan632 disabled auto-merge August 10, 2026 21:41
@Alan632
Alan632 enabled auto-merge August 10, 2026 21:41

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated no new comments.

Suppressed comments (4)

examples/sample-wdm-driver/src/lib.rs:85

  • This test calls driver_exit, whose wdk::println! expansion calls wdk_sys::ntddk::DbgPrint for WDM. Because test-stubs now suppresses the ntoskrnl link directive and does not define DbgPrint, the test executable has an unresolved external instead of proving that it links without WDK libraries. Keep this as a compile/link test by asserting on a generated type without invoking driver code.
        driver_exit(core::ptr::null_mut())

examples/sample-kmdf-driver/src/lib.rs:199

  • This call reaches wdk::println!, which calls the kernel-only DbgPrint symbol for KMDF. The test-stubs feature suppresses the ntoskrnl link directive but does not stub DbgPrint, so this newly enabled test target cannot link. Use a generated-type invariant here, as the mixed-package test does, rather than executing driver code that invokes WDK APIs.
        driver_exit(core::ptr::null_mut())

crates/wdk-sys/src/test_stubs.rs:36

  • This note now contradicts the implementation immediately below: WdfDriverGlobals is stubbed at line 87. Update it to warn that the WDF globals/function table are null and therefore cannot be exercised, rather than claiming the symbol remains intentionally undefined.
//!   - If "test-stubs" is enabled the Linker may complain that
//!     `WdfDriverGlobals` is missing, it is intentionally not stubbed here
//!     because it is needed when a WDF function is called, landing it outside
//!     the intent of test-stubs.

tests/mixed-package-kmdf-workspace/crates/driver/Cargo.toml:25

  • The comment says test-stubs is not needed and recommends switching to it later, but the dependency immediately below already enables it. It is needed here to suppress the generated native-link directives and supply test-target symbols; document that reason and the separate DriverEntry collision instead.
# The feature "test-stubs" isn't needed since gating the DriverEntry export_name keeps
# driver_entry from being codegen'd, so nothing references WDF functions. Switch to "test-stubs"
# if a test ever reaches a call_unsafe_wdf_function_binding! call site.

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.

5 participants