From 294c27e61f69ca34c71f34da683df34765d3342a Mon Sep 17 00:00:00 2001 From: Alan Ngo Date: Thu, 30 Apr 2026 15:08:36 -0700 Subject: [PATCH 01/12] initial commit - add vhf lib link emission to wdk-build --- crates/wdk-build/Cargo.toml | 1 + crates/wdk-build/src/lib.rs | 9 +++++++++ crates/wdk-sys/Cargo.toml | 1 + 3 files changed, 11 insertions(+) diff --git a/crates/wdk-build/Cargo.toml b/crates/wdk-build/Cargo.toml index 221d74b34..45bdd62f7 100644 --- a/crates/wdk-build/Cargo.toml +++ b/crates/wdk-build/Cargo.toml @@ -17,6 +17,7 @@ ignored = [ [features] nightly = [] +vhf = [] [dependencies] anyhow.workspace = true diff --git a/crates/wdk-build/src/lib.rs b/crates/wdk-build/src/lib.rs index 710708e5b..b147e1228 100644 --- a/crates/wdk-build/src/lib.rs +++ b/crates/wdk-build/src/lib.rs @@ -1157,6 +1157,9 @@ impl Config { // provides no way to set a symbol's name without also exporting the symbol: // https://github.com/rust-lang/rust/issues/67399 println!("cargo::rustc-cdylib-link-arg=/IGNORE:4216"); + + #[cfg(feature = "vhf")] + println!("cargo::rustc-cdylib-link-arg=VhfKm.lib"); } DriverConfig::Kmdf(_) => { // Emit KMDF-specific libraries to link to @@ -1186,6 +1189,9 @@ impl Config { // Ignore `LNK4257: object file was not compiled for kernel mode; the image // might not run` since `rustc` has no support for `/KERNEL` println!("cargo::rustc-cdylib-link-arg=/IGNORE:4257"); + + #[cfg(feature = "vhf")] + println!("cargo::rustc-cdylib-link-arg=VhfKm.lib"); } DriverConfig::Umdf(umdf_config) => { // Emit UMDF-specific libraries to link to @@ -1200,6 +1206,9 @@ impl Config { // Linker arguments derived from WindowsDriver.UserMode.props in Ni(22H2) WDK println!("cargo::rustc-cdylib-link-arg=/SUBSYSTEM:WINDOWS"); + + #[cfg(feature = "vhf")] + println!("cargo::rustc-cdylib-link-arg=VhfUm.lib"); } } diff --git a/crates/wdk-sys/Cargo.toml b/crates/wdk-sys/Cargo.toml index 097b04b0b..24f9cef1c 100644 --- a/crates/wdk-sys/Cargo.toml +++ b/crates/wdk-sys/Cargo.toml @@ -21,6 +21,7 @@ default = [] gpio = [] hid = [] +vhf = ["wdk-build/vhf"] parallel-ports = ["gpio"] spb = [] storage = [] From b194380db9f02cee6af19f09d16a45adfed2645c Mon Sep 17 00:00:00 2001 From: Alan Ngo Date: Thu, 30 Apr 2026 17:41:06 -0700 Subject: [PATCH 02/12] remove wdk-sys feature flag forward --- crates/wdk-sys/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/wdk-sys/Cargo.toml b/crates/wdk-sys/Cargo.toml index 24f9cef1c..097b04b0b 100644 --- a/crates/wdk-sys/Cargo.toml +++ b/crates/wdk-sys/Cargo.toml @@ -21,7 +21,6 @@ default = [] gpio = [] hid = [] -vhf = ["wdk-build/vhf"] parallel-ports = ["gpio"] spb = [] storage = [] From cfae425d8f36d578f308d066c16ddde8d6a6af77 Mon Sep 17 00:00:00 2001 From: Alan Ngo Date: Fri, 1 May 2026 10:59:30 -0700 Subject: [PATCH 03/12] add comments to linker emissions for vhf lib --- crates/wdk-build/src/lib.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/crates/wdk-build/src/lib.rs b/crates/wdk-build/src/lib.rs index b147e1228..c9db7fb50 100644 --- a/crates/wdk-build/src/lib.rs +++ b/crates/wdk-build/src/lib.rs @@ -1158,6 +1158,9 @@ impl Config { // https://github.com/rust-lang/rust/issues/67399 println!("cargo::rustc-cdylib-link-arg=/IGNORE:4216"); + // Link against VhfKm.lib (Virtual HID Framework, kernel-mode) when + // the "vhf" feature is enabled. Required by drivers that create + // virtual HID devices. #[cfg(feature = "vhf")] println!("cargo::rustc-cdylib-link-arg=VhfKm.lib"); } @@ -1190,6 +1193,9 @@ impl Config { // might not run` since `rustc` has no support for `/KERNEL` println!("cargo::rustc-cdylib-link-arg=/IGNORE:4257"); + // Link against VhfKm.lib (Virtual HID Framework, kernel-mode) when + // the "vhf" feature is enabled. Required by drivers that create + // virtual HID devices. #[cfg(feature = "vhf")] println!("cargo::rustc-cdylib-link-arg=VhfKm.lib"); } @@ -1207,6 +1213,9 @@ impl Config { // Linker arguments derived from WindowsDriver.UserMode.props in Ni(22H2) WDK println!("cargo::rustc-cdylib-link-arg=/SUBSYSTEM:WINDOWS"); + // Link against VhfUm.lib (Virtual HID Framework, user-mode) when + // the "vhf" feature is enabled. Required by drivers that create + // virtual HID devices. #[cfg(feature = "vhf")] println!("cargo::rustc-cdylib-link-arg=VhfUm.lib"); } From 4427c85e773f5f519f57cc5d39d554a8b550d677 Mon Sep 17 00:00:00 2001 From: Alan Ngo Date: Tue, 5 May 2026 21:50:10 -0700 Subject: [PATCH 04/12] redesigned wdk-build build script output linking vhf to use cargo metadata inspection (automatic) rather than crate features, removed vhf feature from Cargo.toml --- crates/wdk-build/Cargo.toml | 1 - crates/wdk-build/src/lib.rs | 55 +++++++++++++++++++++++++++++-------- 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/crates/wdk-build/Cargo.toml b/crates/wdk-build/Cargo.toml index 45bdd62f7..221d74b34 100644 --- a/crates/wdk-build/Cargo.toml +++ b/crates/wdk-build/Cargo.toml @@ -17,7 +17,6 @@ ignored = [ [features] nightly = [] -vhf = [] [dependencies] anyhow.workspace = true diff --git a/crates/wdk-build/src/lib.rs b/crates/wdk-build/src/lib.rs index c9db7fb50..8f720b0dd 100644 --- a/crates/wdk-build/src/lib.rs +++ b/crates/wdk-build/src/lib.rs @@ -45,6 +45,8 @@ pub struct Config { cpu_architecture: CpuArchitecture, /// Build configuration of driver pub driver_config: DriverConfig, + /// List of features enabled for `wdk-sys` in resolved dependency graph + enabled: Vec, } /// The driver type with its associated configuration parameters @@ -397,6 +399,7 @@ impl Default for Config { ), driver_config: DriverConfig::Wdm, cpu_architecture: utils::detect_cpu_architecture_in_build_script(), + enabled: Vec::new(), } } } @@ -447,6 +450,30 @@ impl Config { .exec()?; let wdk_metadata = metadata::Wdk::try_from(&cargo_metadata)?; + // Find the `wdk-sys` package's PackageId in `cargo_metadata` + let wdk_sys_package_id = cargo_metadata + .packages + .iter() + .find(|pkg| pkg.name == "wdk-sys") + .map(|pkg| &pkg.id); + // Extract the features enabled for `wdk-sys` + // Produces an empty Vec if `wdk-sys` is not found in the dependency graph + let wdk_sys_enabled_features = wdk_sys_package_id + .and_then(|id| { + cargo_metadata + .resolve + .as_ref() + .and_then(|resolve| resolve.nodes.iter().find(|node| node.id == *id)) + }) + .map(|node| node.features.clone()) + .unwrap_or_else(|| { + tracing::warn!( + "Could not detect wdk-sys features from cargo metadata resolve. \ + Feature-dependent libraries will not be linked automatically." + ); + Vec::new() + }); + // Force rebuilds if any of the manifest files change (ex. if wdk metadata // section is modified) for manifest_path in metadata::iter_manifest_paths(cargo_metadata) @@ -462,6 +489,7 @@ impl Config { Ok(Self { driver_config: wdk_metadata.driver_model, + enabled: wdk_sys_enabled_features, ..Default::default() }) } @@ -1159,10 +1187,11 @@ impl Config { println!("cargo::rustc-cdylib-link-arg=/IGNORE:4216"); // Link against VhfKm.lib (Virtual HID Framework, kernel-mode) when - // the "vhf" feature is enabled. Required by drivers that create - // virtual HID devices. - #[cfg(feature = "vhf")] - println!("cargo::rustc-cdylib-link-arg=VhfKm.lib"); + // the "hid" feature is enabled in wdk-sys. Required by drivers that + // create virtual HID devices. + if self.enabled.contains(&"hid".to_string()) { + println!("cargo::rustc-cdylib-link-arg=VhfKm.lib"); + } } DriverConfig::Kmdf(_) => { // Emit KMDF-specific libraries to link to @@ -1194,10 +1223,11 @@ impl Config { println!("cargo::rustc-cdylib-link-arg=/IGNORE:4257"); // Link against VhfKm.lib (Virtual HID Framework, kernel-mode) when - // the "vhf" feature is enabled. Required by drivers that create - // virtual HID devices. - #[cfg(feature = "vhf")] - println!("cargo::rustc-cdylib-link-arg=VhfKm.lib"); + // the "hid" feature is enabled in wdk-sys. Required by drivers that + // create virtual HID devices. + if self.enabled.contains(&"hid".to_string()) { + println!("cargo::rustc-cdylib-link-arg=VhfKm.lib"); + } } DriverConfig::Umdf(umdf_config) => { // Emit UMDF-specific libraries to link to @@ -1214,10 +1244,11 @@ impl Config { println!("cargo::rustc-cdylib-link-arg=/SUBSYSTEM:WINDOWS"); // Link against VhfUm.lib (Virtual HID Framework, user-mode) when - // the "vhf" feature is enabled. Required by drivers that create - // virtual HID devices. - #[cfg(feature = "vhf")] - println!("cargo::rustc-cdylib-link-arg=VhfUm.lib"); + // the "hid" feature is enabled in wdk-sys. Required by drivers that + // create virtual HID devices. + if self.enabled.contains(&"hid".to_string()) { + println!("cargo::rustc-cdylib-link-arg=VhfUm.lib"); + } } } From 7fc834ac32a52bcc5bd919e9dd1f18c108010cf7 Mon Sep 17 00:00:00 2001 From: Alan Ngo Date: Tue, 5 May 2026 22:05:38 -0700 Subject: [PATCH 05/12] formatting --- crates/wdk-build/src/lib.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/crates/wdk-build/src/lib.rs b/crates/wdk-build/src/lib.rs index 8f720b0dd..17dc9b6e5 100644 --- a/crates/wdk-build/src/lib.rs +++ b/crates/wdk-build/src/lib.rs @@ -465,14 +465,16 @@ impl Config { .as_ref() .and_then(|resolve| resolve.nodes.iter().find(|node| node.id == *id)) }) - .map(|node| node.features.clone()) - .unwrap_or_else(|| { - tracing::warn!( - "Could not detect wdk-sys features from cargo metadata resolve. \ - Feature-dependent libraries will not be linked automatically." - ); - Vec::new() - }); + .map_or_else( + || { + tracing::warn!( + "Could not detect wdk-sys features from cargo metadata resolve. \ + Feature-dependent libraries will not be linked automatically." + ); + Vec::new() + }, + |node| node.features.clone(), + ); // Force rebuilds if any of the manifest files change (ex. if wdk metadata // section is modified) From 74ebe7ca730fb780b4cde3c4519e2fa5007eca63 Mon Sep 17 00:00:00 2001 From: Alan Ngo Date: Wed, 6 May 2026 10:50:03 -0700 Subject: [PATCH 06/12] changed how the "hid" feature is checked in configure_binary_build --- crates/wdk-build/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/wdk-build/src/lib.rs b/crates/wdk-build/src/lib.rs index 17dc9b6e5..e67379eac 100644 --- a/crates/wdk-build/src/lib.rs +++ b/crates/wdk-build/src/lib.rs @@ -469,7 +469,7 @@ impl Config { || { tracing::warn!( "Could not detect wdk-sys features from cargo metadata resolve. \ - Feature-dependent libraries will not be linked automatically." + Feature-dependent libraries will not be linked automatically." ); Vec::new() }, @@ -1191,7 +1191,7 @@ impl Config { // Link against VhfKm.lib (Virtual HID Framework, kernel-mode) when // the "hid" feature is enabled in wdk-sys. Required by drivers that // create virtual HID devices. - if self.enabled.contains(&"hid".to_string()) { + if self.enabled.iter().any(|f| f == "hid") { println!("cargo::rustc-cdylib-link-arg=VhfKm.lib"); } } @@ -1227,7 +1227,7 @@ impl Config { // Link against VhfKm.lib (Virtual HID Framework, kernel-mode) when // the "hid" feature is enabled in wdk-sys. Required by drivers that // create virtual HID devices. - if self.enabled.contains(&"hid".to_string()) { + if self.enabled.iter().any(|f| f == "hid") { println!("cargo::rustc-cdylib-link-arg=VhfKm.lib"); } } @@ -1248,7 +1248,7 @@ impl Config { // Link against VhfUm.lib (Virtual HID Framework, user-mode) when // the "hid" feature is enabled in wdk-sys. Required by drivers that // create virtual HID devices. - if self.enabled.contains(&"hid".to_string()) { + if self.enabled.iter().any(|f| f == "hid") { println!("cargo::rustc-cdylib-link-arg=VhfUm.lib"); } } From 6bdb8e3accff500fbaad688c6cb762da8beaa428 Mon Sep 17 00:00:00 2001 From: Alan Ngo Date: Wed, 6 May 2026 21:08:33 -0700 Subject: [PATCH 07/12] changed Config's enabled_api_subsets member to utilize the type safe ApiSubset enum --- crates/wdk-build/src/lib.rs | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/crates/wdk-build/src/lib.rs b/crates/wdk-build/src/lib.rs index e67379eac..9c629f73a 100644 --- a/crates/wdk-build/src/lib.rs +++ b/crates/wdk-build/src/lib.rs @@ -31,6 +31,7 @@ mod bindgen; use cargo_metadata::MetadataCommand; use serde::{Deserialize, Serialize}; +use serde_json::{Value, from_value}; use thiserror::Error; use crate::utils::detect_windows_sdk_version; @@ -46,7 +47,7 @@ pub struct Config { /// Build configuration of driver pub driver_config: DriverConfig, /// List of features enabled for `wdk-sys` in resolved dependency graph - enabled: Vec, + enabled_api_subsets: Vec, } /// The driver type with its associated configuration parameters @@ -318,7 +319,8 @@ rustflags = [\"-C\", \"target-feature=+crt-static\"] } /// Subset of APIs in the Windows Driver Kit -#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] pub enum ApiSubset { /// API subset typically required for all Windows drivers Base, @@ -399,7 +401,7 @@ impl Default for Config { ), driver_config: DriverConfig::Wdm, cpu_architecture: utils::detect_cpu_architecture_in_build_script(), - enabled: Vec::new(), + enabled_api_subsets: Vec::new(), } } } @@ -473,7 +475,12 @@ impl Config { ); Vec::new() }, - |node| node.features.clone(), + |node| { + node.features + .iter() + .filter_map(|f| from_value::(Value::String(f.clone())).ok()) + .collect() + }, ); // Force rebuilds if any of the manifest files change (ex. if wdk metadata @@ -491,7 +498,7 @@ impl Config { Ok(Self { driver_config: wdk_metadata.driver_model, - enabled: wdk_sys_enabled_features, + enabled_api_subsets: wdk_sys_enabled_features, ..Default::default() }) } @@ -1191,7 +1198,11 @@ impl Config { // Link against VhfKm.lib (Virtual HID Framework, kernel-mode) when // the "hid" feature is enabled in wdk-sys. Required by drivers that // create virtual HID devices. - if self.enabled.iter().any(|f| f == "hid") { + if self + .enabled_api_subsets + .iter() + .any(|f| f == &ApiSubset::Hid) + { println!("cargo::rustc-cdylib-link-arg=VhfKm.lib"); } } @@ -1227,7 +1238,11 @@ impl Config { // Link against VhfKm.lib (Virtual HID Framework, kernel-mode) when // the "hid" feature is enabled in wdk-sys. Required by drivers that // create virtual HID devices. - if self.enabled.iter().any(|f| f == "hid") { + if self + .enabled_api_subsets + .iter() + .any(|f| f == &ApiSubset::Hid) + { println!("cargo::rustc-cdylib-link-arg=VhfKm.lib"); } } @@ -1248,7 +1263,11 @@ impl Config { // Link against VhfUm.lib (Virtual HID Framework, user-mode) when // the "hid" feature is enabled in wdk-sys. Required by drivers that // create virtual HID devices. - if self.enabled.iter().any(|f| f == "hid") { + if self + .enabled_api_subsets + .iter() + .any(|f| f == &ApiSubset::Hid) + { println!("cargo::rustc-cdylib-link-arg=VhfUm.lib"); } } From 8ff9e5bd64a80ef0b79cd8715735a94aa93211b0 Mon Sep 17 00:00:00 2001 From: Alan Ngo Date: Wed, 6 May 2026 21:27:45 -0700 Subject: [PATCH 08/12] added serde attribute to Config member for deserialize compatibility --- crates/wdk-build/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/wdk-build/src/lib.rs b/crates/wdk-build/src/lib.rs index 9c629f73a..09913d7cd 100644 --- a/crates/wdk-build/src/lib.rs +++ b/crates/wdk-build/src/lib.rs @@ -47,6 +47,7 @@ pub struct Config { /// Build configuration of driver pub driver_config: DriverConfig, /// List of features enabled for `wdk-sys` in resolved dependency graph + #[serde(default)] enabled_api_subsets: Vec, } From 0d8fe7f5f4e2e1d97b0862ab70f3e9347f07c6f4 Mon Sep 17 00:00:00 2001 From: Alan Ngo Date: Thu, 7 May 2026 18:19:23 -0700 Subject: [PATCH 09/12] extended config unit tests to include new member --- crates/wdk-build/src/lib.rs | 40 +++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/crates/wdk-build/src/lib.rs b/crates/wdk-build/src/lib.rs index 09913d7cd..5b3b49801 100644 --- a/crates/wdk-build/src/lib.rs +++ b/crates/wdk-build/src/lib.rs @@ -1897,18 +1897,32 @@ mod tests { #[cfg(assert_matches_stabilized)] assert_matches!(config.driver_config, DriverConfig::Wdm); assert_eq!(config.cpu_architecture, CpuArchitecture::Amd64); + assert!(config.enabled_api_subsets.is_empty()); } #[test] fn wdm_config() { let config = with_env(&[("CARGO_CFG_TARGET_ARCH", Some("x86_64"))], || Config { driver_config: DriverConfig::Wdm, + enabled_api_subsets: vec![ApiSubset::Hid], ..Config::default() }); #[cfg(assert_matches_stabilized)] assert_matches!(config.driver_config, DriverConfig::Wdm); assert_eq!(config.cpu_architecture, CpuArchitecture::Amd64); + assert!( + config + .enabled_api_subsets + .iter() + .any(|f| f == &ApiSubset::Hid) + ); + assert!( + !config + .enabled_api_subsets + .iter() + .any(|f| f == &ApiSubset::Gpio) + ); } #[test] @@ -1938,6 +1952,7 @@ mod tests { target_kmdf_version_minor: 15, minimum_kmdf_version_minor: None, }), + enabled_api_subsets: vec![ApiSubset::Hid, ApiSubset::Gpio], ..Config::default() }); @@ -1951,6 +1966,18 @@ mod tests { }) ); assert_eq!(config.cpu_architecture, CpuArchitecture::Amd64); + assert!( + config + .enabled_api_subsets + .iter() + .any(|f| f == &ApiSubset::Hid) + ); + assert!( + config + .enabled_api_subsets + .iter() + .any(|f| f == &ApiSubset::Gpio) + ); } #[test] @@ -1980,6 +2007,7 @@ mod tests { target_umdf_version_minor: 15, minimum_umdf_version_minor: None, }), + enabled_api_subsets: vec![ApiSubset::Usb], ..Config::default() }); @@ -1993,6 +2021,18 @@ mod tests { }) ); assert_eq!(config.cpu_architecture, CpuArchitecture::Arm64); + assert!( + !config + .enabled_api_subsets + .iter() + .any(|f| f == &ApiSubset::Hid) + ); + assert!( + config + .enabled_api_subsets + .iter() + .any(|f| f == &ApiSubset::Usb) + ); } #[test] From 18d42f3fca2effd899145092ab51a26a972880f1 Mon Sep 17 00:00:00 2001 From: Alan Ngo Date: Fri, 8 May 2026 09:44:45 -0700 Subject: [PATCH 10/12] refactor api_subsets search to use match, refactor hid api check to use contains --- crates/wdk-build/src/lib.rs | 108 ++++++++++++------------------------ 1 file changed, 35 insertions(+), 73 deletions(-) diff --git a/crates/wdk-build/src/lib.rs b/crates/wdk-build/src/lib.rs index 5b3b49801..36f839af8 100644 --- a/crates/wdk-build/src/lib.rs +++ b/crates/wdk-build/src/lib.rs @@ -461,28 +461,32 @@ impl Config { .map(|pkg| &pkg.id); // Extract the features enabled for `wdk-sys` // Produces an empty Vec if `wdk-sys` is not found in the dependency graph - let wdk_sys_enabled_features = wdk_sys_package_id - .and_then(|id| { - cargo_metadata - .resolve - .as_ref() - .and_then(|resolve| resolve.nodes.iter().find(|node| node.id == *id)) - }) - .map_or_else( - || { - tracing::warn!( - "Could not detect wdk-sys features from cargo metadata resolve. \ - Feature-dependent libraries will not be linked automatically." - ); - Vec::new() - }, - |node| { - node.features - .iter() - .filter_map(|f| from_value::(Value::String(f.clone())).ok()) - .collect() - }, - ); + let wdk_sys_enabled_features = match wdk_sys_package_id { + None => { + // wdk-sys not in dependency graph + Vec::new() + } + Some(id) => cargo_metadata + .resolve + .as_ref() + .and_then(|resolve| resolve.nodes.iter().find(|node| node.id == *id)) + .map_or_else( + || { + tracing::warn!( + "wdk-sys was found in packages but its features could not be \ + determined from cargo metadata resolve. Feature-dependent libraries \ + will not be linked automatically." + ); + Vec::new() + }, + |node| { + node.features + .iter() + .filter_map(|f| from_value::(Value::String(f.clone())).ok()) + .collect() + }, + ), + }; // Force rebuilds if any of the manifest files change (ex. if wdk metadata // section is modified) @@ -1199,11 +1203,7 @@ impl Config { // Link against VhfKm.lib (Virtual HID Framework, kernel-mode) when // the "hid" feature is enabled in wdk-sys. Required by drivers that // create virtual HID devices. - if self - .enabled_api_subsets - .iter() - .any(|f| f == &ApiSubset::Hid) - { + if self.enabled_api_subsets.contains(&ApiSubset::Hid) { println!("cargo::rustc-cdylib-link-arg=VhfKm.lib"); } } @@ -1239,11 +1239,7 @@ impl Config { // Link against VhfKm.lib (Virtual HID Framework, kernel-mode) when // the "hid" feature is enabled in wdk-sys. Required by drivers that // create virtual HID devices. - if self - .enabled_api_subsets - .iter() - .any(|f| f == &ApiSubset::Hid) - { + if self.enabled_api_subsets.contains(&ApiSubset::Hid) { println!("cargo::rustc-cdylib-link-arg=VhfKm.lib"); } } @@ -1264,11 +1260,7 @@ impl Config { // Link against VhfUm.lib (Virtual HID Framework, user-mode) when // the "hid" feature is enabled in wdk-sys. Required by drivers that // create virtual HID devices. - if self - .enabled_api_subsets - .iter() - .any(|f| f == &ApiSubset::Hid) - { + if self.enabled_api_subsets.contains(&ApiSubset::Hid) { println!("cargo::rustc-cdylib-link-arg=VhfUm.lib"); } } @@ -1911,18 +1903,8 @@ mod tests { #[cfg(assert_matches_stabilized)] assert_matches!(config.driver_config, DriverConfig::Wdm); assert_eq!(config.cpu_architecture, CpuArchitecture::Amd64); - assert!( - config - .enabled_api_subsets - .iter() - .any(|f| f == &ApiSubset::Hid) - ); - assert!( - !config - .enabled_api_subsets - .iter() - .any(|f| f == &ApiSubset::Gpio) - ); + assert!(config.enabled_api_subsets.contains(&ApiSubset::Hid)); + assert!(!config.enabled_api_subsets.contains(&ApiSubset::Gpio)); } #[test] @@ -1966,18 +1948,8 @@ mod tests { }) ); assert_eq!(config.cpu_architecture, CpuArchitecture::Amd64); - assert!( - config - .enabled_api_subsets - .iter() - .any(|f| f == &ApiSubset::Hid) - ); - assert!( - config - .enabled_api_subsets - .iter() - .any(|f| f == &ApiSubset::Gpio) - ); + assert!(config.enabled_api_subsets.contains(&ApiSubset::Hid)); + assert!(config.enabled_api_subsets.contains(&ApiSubset::Gpio)); } #[test] @@ -2021,18 +1993,8 @@ mod tests { }) ); assert_eq!(config.cpu_architecture, CpuArchitecture::Arm64); - assert!( - !config - .enabled_api_subsets - .iter() - .any(|f| f == &ApiSubset::Hid) - ); - assert!( - config - .enabled_api_subsets - .iter() - .any(|f| f == &ApiSubset::Usb) - ); + assert!(!config.enabled_api_subsets.contains(&ApiSubset::Hid)); + assert!(config.enabled_api_subsets.contains(&ApiSubset::Usb)); } #[test] From 55a63a10fecb012458fe90dbfc4c3b880527fa52 Mon Sep 17 00:00:00 2001 From: Alan Ngo Date: Fri, 8 May 2026 18:01:28 -0700 Subject: [PATCH 11/12] refactored feature filter to skip json and use ApiSubset deserializer, changed enabled_api_subsets type to a BTreeSet, updated tests --- crates/wdk-build/src/lib.rs | 89 ++++++++++++++++++++++++------------- 1 file changed, 59 insertions(+), 30 deletions(-) diff --git a/crates/wdk-build/src/lib.rs b/crates/wdk-build/src/lib.rs index 36f839af8..8cfc4f5e8 100644 --- a/crates/wdk-build/src/lib.rs +++ b/crates/wdk-build/src/lib.rs @@ -11,6 +11,7 @@ //! models (WDM, KMDF, UMDF). use std::{ + collections::BTreeSet, env, fmt, path::{Path, PathBuf, absolute}, @@ -30,8 +31,7 @@ mod utils; mod bindgen; use cargo_metadata::MetadataCommand; -use serde::{Deserialize, Serialize}; -use serde_json::{Value, from_value}; +use serde::{Deserialize, Serialize, de::IntoDeserializer}; use thiserror::Error; use crate::utils::detect_windows_sdk_version; @@ -47,8 +47,7 @@ pub struct Config { /// Build configuration of driver pub driver_config: DriverConfig, /// List of features enabled for `wdk-sys` in resolved dependency graph - #[serde(default)] - enabled_api_subsets: Vec, + enabled_api_subsets: BTreeSet, } /// The driver type with its associated configuration parameters @@ -320,7 +319,7 @@ rustflags = [\"-C\", \"target-feature=+crt-static\"] } /// Subset of APIs in the Windows Driver Kit -#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Ord, PartialOrd)] #[serde(rename_all = "kebab-case")] pub enum ApiSubset { /// API subset typically required for all Windows drivers @@ -341,6 +340,11 @@ pub enum ApiSubset { Usb, } +/// Known `wdk-sys` cargo features that are not API subsets and should be +/// skipped during feature detection. Any `wdk-sys` feature not in this list +/// and not deserializable as an [`ApiSubset`] will cause a hard error. +const NON_API_SUBSET_FEATURES: &[&str] = &["default", "nightly", "test-stubs"]; + #[derive(Debug, Error, PartialEq, Eq)] /// Error when parsing a [`TwoPartVersion`]. pub enum TwoPartVersionError { @@ -402,7 +406,7 @@ impl Default for Config { ), driver_config: DriverConfig::Wdm, cpu_architecture: utils::detect_cpu_architecture_in_build_script(), - enabled_api_subsets: Vec::new(), + enabled_api_subsets: BTreeSet::new(), } } } @@ -466,26 +470,41 @@ impl Config { // wdk-sys not in dependency graph Vec::new() } - Some(id) => cargo_metadata - .resolve - .as_ref() - .and_then(|resolve| resolve.nodes.iter().find(|node| node.id == *id)) - .map_or_else( - || { - tracing::warn!( - "wdk-sys was found in packages but its features could not be \ - determined from cargo metadata resolve. Feature-dependent libraries \ - will not be linked automatically." - ); - Vec::new() - }, - |node| { - node.features - .iter() - .filter_map(|f| from_value::(Value::String(f.clone())).ok()) - .collect() - }, - ), + Some(id) => { + let node = cargo_metadata + .resolve + .as_ref() + .and_then(|resolve| resolve.nodes.iter().find(|node| node.id == *id)) + .expect( + "wdk-sys was found in packages but has no matching entry in the cargo \ + metadata resolve graph. This indicates a broken build setup.", + ); + + let mut api_subsets = Vec::new(); + for feature in &node.features { + if NON_API_SUBSET_FEATURES.contains(&feature.as_str()) { + continue; + } + match ApiSubset::deserialize(<&str as IntoDeserializer< + '_, + serde::de::value::Error, + >>::into_deserializer( + feature.as_str() + )) { + Ok(subset) => api_subsets.push(subset), + Err(_) => { + panic!( + "Unknown wdk-sys feature '{feature}' is not a recognized \ + ApiSubset and not in the known non-API-subset feature list. If \ + this is a new API subset, add a variant to ApiSubset. If it is \ + not an API subset, add it to NON_API_SUBSET_FEATURES in \ + wdk-build." + ); + } + } + } + api_subsets + } }; // Force rebuilds if any of the manifest files change (ex. if wdk metadata @@ -503,7 +522,7 @@ impl Config { Ok(Self { driver_config: wdk_metadata.driver_model, - enabled_api_subsets: wdk_sys_enabled_features, + enabled_api_subsets: wdk_sys_enabled_features.into_iter().collect(), ..Default::default() }) } @@ -1894,9 +1913,12 @@ mod tests { #[test] fn wdm_config() { + let mut test_api_subset = BTreeSet::::new(); + test_api_subset.insert(ApiSubset::Hid); + let config = with_env(&[("CARGO_CFG_TARGET_ARCH", Some("x86_64"))], || Config { driver_config: DriverConfig::Wdm, - enabled_api_subsets: vec![ApiSubset::Hid], + enabled_api_subsets: test_api_subset, ..Config::default() }); @@ -1928,13 +1950,17 @@ mod tests { #[test] fn kmdf_config() { + let mut test_api_subset = BTreeSet::::new(); + test_api_subset.insert(ApiSubset::Hid); + test_api_subset.insert(ApiSubset::Gpio); + let config = with_env(&[("CARGO_CFG_TARGET_ARCH", Some("x86_64"))], || Config { driver_config: DriverConfig::Kmdf(KmdfConfig { kmdf_version_major: 1, target_kmdf_version_minor: 15, minimum_kmdf_version_minor: None, }), - enabled_api_subsets: vec![ApiSubset::Hid, ApiSubset::Gpio], + enabled_api_subsets: test_api_subset, ..Config::default() }); @@ -1973,13 +1999,16 @@ mod tests { #[test] fn umdf_config() { + let mut test_api_subset = BTreeSet::::new(); + test_api_subset.insert(ApiSubset::Usb); + let config = with_env(&[("CARGO_CFG_TARGET_ARCH", Some("aarch64"))], || Config { driver_config: DriverConfig::Umdf(UmdfConfig { umdf_version_major: 2, target_umdf_version_minor: 15, minimum_umdf_version_minor: None, }), - enabled_api_subsets: vec![ApiSubset::Usb], + enabled_api_subsets: test_api_subset, ..Config::default() }); From d22d9dbe2cb408db0314b3ea10042f44ade76795 Mon Sep 17 00:00:00 2001 From: Alan Ngo Date: Fri, 8 May 2026 18:19:49 -0700 Subject: [PATCH 12/12] add error to panic message --- crates/wdk-build/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/wdk-build/src/lib.rs b/crates/wdk-build/src/lib.rs index 8cfc4f5e8..cf647e8e0 100644 --- a/crates/wdk-build/src/lib.rs +++ b/crates/wdk-build/src/lib.rs @@ -492,12 +492,12 @@ impl Config { feature.as_str() )) { Ok(subset) => api_subsets.push(subset), - Err(_) => { + Err(err) => { panic!( "Unknown wdk-sys feature '{feature}' is not a recognized \ - ApiSubset and not in the known non-API-subset feature list. If \ - this is a new API subset, add a variant to ApiSubset. If it is \ - not an API subset, add it to NON_API_SUBSET_FEATURES in \ + ApiSubset and not in the known non-API-subset feature list: \ + {err}. If this is a new API subset, add a variant to ApiSubset. \ + If it is not an API subset, add it to NON_API_SUBSET_FEATURES in \ wdk-build." ); }