feat: add linker directive for VHF lib + move static linker directives from wdk-build to wdk-sys - #685
feat: add linker directive for VHF lib + move static linker directives from wdk-build to wdk-sys#685Alan632 wants to merge 37 commits into
Conversation
… directives from wdk-build/src/lib.rs into wdk-sys/build.rs
There was a problem hiding this comment.
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) fromwdk-sys/build.rs. - Add
hid-gated#[link]directives forVhfKm(KMDF/WDM) andVhfUm(UMDF). - Remove the corresponding
cargo::rustc-link-lib=static=*emissions fromwdk-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.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #685 +/- ##
==========================================
+ Coverage 80.47% 81.07% +0.59%
==========================================
Files 26 26
Lines 5722 5901 +179
Branches 5722 5901 +179
==========================================
+ Hits 4605 4784 +179
Misses 989 989
Partials 128 128 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
…ts by utilizing ApiSubset similar to the headers
…indows-drivers-rs into vhf_lib_linker_args-v2
…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
… attributes to ensure wdk-sys builds correctly when compiled for test - add unit tests - add PartialEq and Eq traits to LinkKind, LinkModifier, and LinkDirective
leon-xd
left a comment
There was a problem hiding this comment.
Great work. Few changes here and there but the overall shape is very solid!
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 14 out of 14 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
tests/mixed-package-kmdf-workspace/crates/driver/Cargo.toml:25
- This comment is inaccurate: gating the
DriverEntryexport name does not stopdriver_entryfrom being codegen’d; it only avoids exporting/renaming the symbol for the driver entry point. The function can still be compiled, so the rationale for not needingtest-stubsshould be stated in terms of not requiring WDF link symbols during unit tests (or keeping tests from reaching WDF call sites).
# 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.
| fn render(&self) -> String { | ||
| format!( | ||
| r#"#[cfg({cfg})] | ||
| #[link(name = "{name}", kind = "static", modifiers = "-bundle")] | ||
| unsafe extern "C" {{}} | ||
| "#, | ||
| cfg = NOT_TEST_CFG, | ||
| name = self.name, | ||
| ) | ||
| } | ||
| } |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 15 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
tests/mixed-package-kmdf-workspace/crates/driver/Cargo.toml:26
- The dev-dependency comment is misleading: gating the
DriverEntryexport_namedoes not preventdriver_entryfrom being codegen’d; it only avoids exporting the symbol asDriverEntryincargo testbuilds. The test-friendly behavior here mainly comes from enablingwdk-sys/no-linkto suppress generated#[link]directives, plus not referencing WDF functions in tests. Consider rewriting the comment to reflect what’s actually happening so future changes don’t rely on a false assumption.
# 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 = ["no-link"], workspace = true }
…e to `-D clippy::negative-feature-names` - formatting test_stubs.rs doc comment
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 15 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
tests/mixed-package-kmdf-workspace/crates/driver/Cargo.toml:26
- The dev-dependency comment is misleading: gating
export_name = "DriverEntry"does not preventdriver_entryfrom being codegen’d, and this crate still contains WDF call sites (e.g.call_unsafe_wdf_function_binding!(WdfDriverCreate, ...)) that could get pulled into the test binary depending on codegen-unit/LTO behavior. The comment should describe the real purpose (avoiding exportingDriverEntryduring tests to prevent symbol conflicts) and when to switch totest-stubs.
# 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 = ["omit-wdk-libs"], workspace = true }
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 15 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (2)
tests/mixed-package-kmdf-workspace/crates/driver/Cargo.toml:25
- The dev-dependency enables the
test-stubsfeature, but the accompanying comment saystest-stubs“isn't needed” and suggests switching to it later. This is internally inconsistent and makes it unclear 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 }
tests/wdk-sys-tests/src/lib.rs:10
- Doctests compile in a separate crate, so
wdk-sysis built as a normal dependency (withoutcfg(test)). The current docs imply the#[link]directives are suppressed just because it’s a doctest, but in practice suppression relies on enablingomit-wdk-libs(here via thetest-stubsfeature).
//! The crate-level example below doubles as a doctest.
//! `cargo test` compiles and links each doctest as its own binary.
//! The generated `#[link]` directives are cfg-suppressed, so the
//! doctest links and runs without pulling libraries into it.
| fn render(&self) -> String { | ||
| format!( | ||
| r#"#[cfg({cfg})] | ||
| #[link(name = "{name}", kind = "static", modifiers = "-bundle")] | ||
| unsafe extern "C" {{}} | ||
| "#, | ||
| cfg = NOT_TEST_CFG, | ||
| name = self.name, | ||
| ) | ||
| } |
…vers in `examples/` - add unit test place holder in sample driver crates in `examples/`
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 19 out of 19 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (4)
examples/sample-wdm-driver/src/lib.rs:78
- This unit test calls
driver_exit, which routes throughwdk::printlnand ultimatelywdk_sys::ntddk::DbgPrintfor WDM/KMDF. With linker directives now disabled undercfg(test), this makes the example’scargo testprone to link failures on the host. Prefer a pure Rust invariant test that only references bindgen-generated types and does not call into kernel APIs.
mod tests {
#[test]
fn test_driver_exit() {
use super::*;
examples/sample-kmdf-driver/src/lib.rs:197
- This unit test calls
driver_exit, which routes throughwdk::printlnand ultimatelywdk_sys::ntddk::DbgPrintfor WDM/KMDF. With linker directives now disabled undercfg(test), this makes the example’scargo testprone to link failures on the host. Prefer a pure Rust invariant test that only references bindgen-generated types and does not call into kernel APIs.
mod tests {
#[test]
fn test_driver_exit() {
use super::*;
tests/mixed-package-kmdf-workspace/crates/driver/Cargo.toml:26
- The comment says
test-stubs“isn't needed” and that gatingexport_namepreventsdriver_entryfrom being codegen’d, but this dependency is explicitly enablingtest-stubs. Please update the comment to reflect the actual reason the feature is enabled so future maintainers don’t remove it based on incorrect assumptions.
# 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-umdf-driver/src/lib.rs:182
- This
mod testsis currently compiled into non-test builds as well. It’s better to gate it with#[cfg(test)], and keep the test itself independent of driver runtime behavior (e.g., a type-size invariant) so it can run in CI without requiring a driver environment.
mod tests {
#[test]
fn test_driver_exit() {
use super::*;
| #![cfg_attr(not(test), no_std)] | ||
|
|
||
| extern crate alloc; |
| #![cfg_attr(not(test), no_std)] | ||
|
|
||
| extern crate alloc; |
- formatting - enable test-stubs in sample drivers and cfg gate DriverEntry export_name - forgot cfg(test) for tests modules
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 19 out of 19 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (3)
examples/sample-wdm-driver/src/lib.rs:81
- The unit test calls
driver_exit, which useswdk::println!(DbgPrint). In test buildswdk-sysis enabled withomit-wdk-libsviatest-stubs, so the generated#[link]directives that would pull inntoskrnl/halare suppressed; this makesDbgPrintunresolved at link time.
#[test]
fn test_driver_exit() {
use super::*;
driver_exit(core::ptr::null_mut())
examples/sample-kmdf-driver/src/lib.rs:200
- The unit test calls
driver_exit, which useswdk::println!(DbgPrint). Withwdk-sysbuilt for tests usingomit-wdk-libsviatest-stubs, the generated#[link]directives are suppressed andDbgPrintwon't be linked, causing test builds to fail at link time.
#[test]
fn test_driver_exit() {
use super::*;
driver_exit(core::ptr::null_mut())
tests/mixed-package-kmdf-workspace/crates/driver/Cargo.toml:26
- The comment says
test-stubsisn't needed, but the dependency is still declared withfeatures = ["test-stubs"]. This is misleading for future maintenance (andtest-stubsnow also enablesomit-wdk-libs, which is likely the real reason this is enabled).
# 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 }
- change the `DRIVER_OBJECT` type to `PDRIVER_OBJECT` in driver_entry_stub - formatting
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 19 out of 19 changed files in this pull request and generated no new comments.
Suppressed comments (3)
crates/wdk-sys/src/test_stubs.rs:36
- The module docs still say
WdfDriverGlobalsis intentionally not stubbed (and that missing it is expected), but the module now defines aWdfDriverGlobalsstub below. This comment is now misleading for users diagnosing linker failures undertest-stubs.
Update the note to reflect the current behavior (it is stubbed, but calling into real WDF APIs in tests still requires 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.
crates/wdk-sys/src/test_stubs.rs:84
- There is trailing whitespace in the doc comment line (
///) which can cause formatting/style checks to fail and is also inconsistent with the surrounding doc comment style. Prefer an empty doc line written as///.
/// Stubbed version of `WdfDriverGlobals` Symbol so that test targets will
/// link.
///
tests/mixed-package-kmdf-workspace/crates/driver/Cargo.toml:25
- This comment contradicts the dependency configuration and is also technically inaccurate: gating only the
export_nameattribute does not preventdriver_entryfrom being codegen'd, andtest-stubsis enabled unconditionally right below.
Please update the comment to reflect why test-stubs is enabled for dev/test builds (e.g., suppress generated #[link] directives via omit-wdk-libs and provide stubbed driver/WDF globals for linking).
# 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.
There was a problem hiding this comment.
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 useswdk::println!. In WDM/KMDF, that routes throughwdk_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 forDbgPrintwhen runningcargo teston 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 useswdk::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 breakcargo testfor 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
WdfDriverGlobalsis intentionally not stubbed and that enablingtest-stubsmay fail to link because it’s missing, but this file now defines aWdfDriverGlobalsstub. 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 }
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
.mapfile for evidence of the respective Vhf symbols.Bindgen generated files are also inspected post build for the presence of the link attributes.