-
Notifications
You must be signed in to change notification settings - Fork 124
feat: add linker args for VHF lib to wdk-build #653
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 11 commits
294c27e
b194380
cfae425
70305e3
4427c85
7fc834a
74ebe7c
6bdb8e3
8ff9e5b
0d8fe7f
18d42f3
55a63a1
d22d9db
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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; | ||
|
|
@@ -45,6 +46,9 @@ 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 | ||
|
|
||
| #[serde(default)] | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Drop
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sounds good and done! I didn't think about what could be implied (the backwards-compat invariant) by adding that attribute. |
||
| enabled_api_subsets: Vec<ApiSubset>, | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be a
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done! |
||
| } | ||
|
|
||
| /// The driver type with its associated configuration parameters | ||
|
|
@@ -316,7 +320,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, | ||
|
|
@@ -397,6 +402,7 @@ impl Default for Config { | |
| ), | ||
| driver_config: DriverConfig::Wdm, | ||
| cpu_architecture: utils::detect_cpu_architecture_in_build_script(), | ||
| enabled_api_subsets: Vec::new(), | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -447,6 +453,41 @@ 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 = 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( | ||
|
wmmc88 marked this conversation as resolved.
Outdated
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This shouldn't be a warning. Two coherent options: (1) if (2) is the right call.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That makes sense, we now use |
||
| || { | ||
| 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() | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the per-feature use serde::de::{IntoDeserializer, value::{Error as ValueError, StrDeserializer}};
node.features
.iter()
.filter_map(|f| {
ApiSubset::deserialize(f.as_str().into_deserializer()).ok()
})
.collect()
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. actually, this should go further and actually filter some known set of cargo features that aren't APISubsets (ie. default, nightly), instead of relying on a deserialization failure
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To clarify the second point - is the desire to have a set of known features (aka all wdk-sys features) and warn the user if something not in that set is found in the metadata? If we have a set of known "non ApiSubset" features that we filter out without notifying the user about it, then that sounds similar to silently filtering out via deserialization failure?
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we'd have a set of known non-api-subset features, and if we encounter one of those, it should hard error. anything thats not an api-subset feature and not in the known list should be treated as an unknown feature and we should bail. this is to help make sure at compile time that when there are new api subsets added, they map cleanly to the enum
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. wait, we should hard error on encountering non-api-subset features? (aka default, nightly, test-stubs) Shouldn't we just filter those out and only hard error on anything that isn't listed in the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I went ahead and changed the implementation to hard error on found features that are neither in the non-api-subset-features list and the ApiSubset enum (eg. an unknown 'new' feature from wdk-sys), which I think is what we're both trying to express 😅 let's discuss offline if needed! |
||
| }, | ||
| |node| { | ||
| node.features | ||
| .iter() | ||
| .filter_map(|f| from_value::<ApiSubset>(Value::String(f.clone())).ok()) | ||
| .collect() | ||
| }, | ||
| ), | ||
| }; | ||
|
|
||
| // 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 +503,7 @@ impl Config { | |
|
|
||
| Ok(Self { | ||
| driver_config: wdk_metadata.driver_model, | ||
| enabled_api_subsets: wdk_sys_enabled_features, | ||
| ..Default::default() | ||
| }) | ||
| } | ||
|
|
@@ -1157,6 +1199,13 @@ 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"); | ||
|
|
||
| // 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.contains(&ApiSubset::Hid) { | ||
| println!("cargo::rustc-cdylib-link-arg=VhfKm.lib"); | ||
|
Comment on lines
+1222
to
+1226
|
||
| } | ||
| } | ||
| DriverConfig::Kmdf(_) => { | ||
| // Emit KMDF-specific libraries to link to | ||
|
|
@@ -1186,6 +1235,13 @@ 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"); | ||
|
|
||
| // 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.contains(&ApiSubset::Hid) { | ||
| println!("cargo::rustc-cdylib-link-arg=VhfKm.lib"); | ||
|
Comment on lines
+1258
to
+1262
|
||
| } | ||
|
Alan632 marked this conversation as resolved.
|
||
| } | ||
| DriverConfig::Umdf(umdf_config) => { | ||
| // Emit UMDF-specific libraries to link to | ||
|
|
@@ -1200,6 +1256,13 @@ 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 "hid" feature is enabled in wdk-sys. Required by drivers that | ||
| // create virtual HID devices. | ||
| if self.enabled_api_subsets.contains(&ApiSubset::Hid) { | ||
| println!("cargo::rustc-cdylib-link-arg=VhfUm.lib"); | ||
|
Comment on lines
+1279
to
+1283
|
||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -1826,18 +1889,22 @@ 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.contains(&ApiSubset::Hid)); | ||
| assert!(!config.enabled_api_subsets.contains(&ApiSubset::Gpio)); | ||
| } | ||
|
|
||
| #[test] | ||
|
|
@@ -1867,6 +1934,7 @@ mod tests { | |
| target_kmdf_version_minor: 15, | ||
| minimum_kmdf_version_minor: None, | ||
| }), | ||
| enabled_api_subsets: vec![ApiSubset::Hid, ApiSubset::Gpio], | ||
| ..Config::default() | ||
| }); | ||
|
|
||
|
|
@@ -1880,6 +1948,8 @@ mod tests { | |
| }) | ||
| ); | ||
| assert_eq!(config.cpu_architecture, CpuArchitecture::Amd64); | ||
| assert!(config.enabled_api_subsets.contains(&ApiSubset::Hid)); | ||
| assert!(config.enabled_api_subsets.contains(&ApiSubset::Gpio)); | ||
| } | ||
|
|
||
| #[test] | ||
|
|
@@ -1909,6 +1979,7 @@ mod tests { | |
| target_umdf_version_minor: 15, | ||
| minimum_umdf_version_minor: None, | ||
| }), | ||
| enabled_api_subsets: vec![ApiSubset::Usb], | ||
| ..Config::default() | ||
| }); | ||
|
|
||
|
|
@@ -1922,6 +1993,8 @@ mod tests { | |
| }) | ||
| ); | ||
| assert_eq!(config.cpu_architecture, CpuArchitecture::Arm64); | ||
| assert!(!config.enabled_api_subsets.contains(&ApiSubset::Hid)); | ||
| assert!(config.enabled_api_subsets.contains(&ApiSubset::Usb)); | ||
| } | ||
|
|
||
| #[test] | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.