Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 17 additions & 55 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ lto = true

[workspace.package]
edition = "2021"
rust-version = "1.82.0"
repository = "https://github.com/microsoft/windows-drivers-rs"
readme = "README.md"
license = "MIT OR Apache-2.0"
Expand All @@ -37,9 +38,9 @@ wdk-sys = { path = "crates/wdk-sys", version = "0.3.0" }

# External Crates
anyhow = "1.0.97"
bindgen = "0.69.5"
bindgen = "0.71.0"
camino = "1.1.9"
cargo_metadata = "0.18.1"
cargo_metadata = "0.19.2"
cc = "1.2.16"
cfg-if = "1.0.0"
clap = "4.5.13"
Expand All @@ -54,8 +55,9 @@ rustversion = "1.0.19"
scratch = "1.0"
serde = "1.0"
serde_json = "1.0"
semver = "1.0.26"
syn = "2.0.100"
thiserror = "1.0.69"
thiserror = "2.0.12"
tracing = "0.1.40"
tracing-subscriber = "0.3.18"
windows = "0.58.0"
Expand Down
5 changes: 5 additions & 0 deletions crates/wdk-build/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[package]
edition.workspace = true
rust-version.workspace = true
name = "wdk-build"
version = "0.3.0"
description = "A library to configure a Cargo build script for binding generation and downstream linking of the WDK (Windows Driver Kit)"
Expand All @@ -22,6 +23,7 @@ clap = { workspace = true, features = ["derive"] }
clap-cargo.workspace = true
paste.workspace = true
rustversion.workspace = true
semver.workspace = true
serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true
thiserror.workspace = true
Expand Down Expand Up @@ -72,3 +74,6 @@ missing_crate_level_docs = "warn"
private_intra_doc_links = "warn"
redundant_explicit_links = "warn"
unescaped_backticks = "warn"

[features]
nightly = []
100 changes: 99 additions & 1 deletion crates/wdk-build/src/bindgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use bindgen::{
callbacks::{ItemInfo, ItemKind, ParseCallbacks},
Builder,
};
use cargo_metadata::MetadataCommand;

use crate::{Config, ConfigError};

Expand All @@ -28,6 +29,32 @@ struct WdkCallbacks {
wdf_function_table_symbol_name: Option<String>,
}

struct BindgenRustEditionWrapper(bindgen::RustEdition);

impl TryFrom<cargo_metadata::Edition> for BindgenRustEditionWrapper {
type Error = ConfigError;

fn try_from(edition: cargo_metadata::Edition) -> Result<Self, Self::Error> {
match edition {
cargo_metadata::Edition::E2015 => Err(ConfigError::UnsupportedRustEdition {
edition: "2015".to_string(),
}),
cargo_metadata::Edition::E2018 => Ok(Self(bindgen::RustEdition::Edition2018)),
cargo_metadata::Edition::E2021 => Ok(Self(bindgen::RustEdition::Edition2021)),
cargo_metadata::Edition::E2024 => Ok(Self(bindgen::RustEdition::Edition2024)),
cargo_metadata::Edition::_E2027 => Err(ConfigError::UnsupportedRustEdition {
edition: "2027".to_string(),
}),
cargo_metadata::Edition::_E2030 => Err(ConfigError::UnsupportedRustEdition {
edition: "2030".to_string(),
}),
_ => Err(ConfigError::UnsupportedRustEdition {
edition: "unknown".to_string(),
}),
}
}
}

impl BuilderExt for Builder {
/// Returns a `bindgen::Builder` with the default configuration for
/// generation of bindings to the WDK
Expand Down Expand Up @@ -96,6 +123,11 @@ impl BuilderExt for Builder {
.blocklist_item(".*WHEA_ARM_BUS_ERROR(?:__bindgen.*)?")
.blocklist_item(".*WHEA_ARM_PROCESSOR_ERROR")
.blocklist_item(".*WHEA_ARM_CACHE_ERROR")
// FIXME: bindgen unable to generate for anonymous structs
.blocklist_item("ADDRESS0_OWNERSHIP_ACQUIRE")
.blocklist_item("USBDEVICE_ABORTIO")
.blocklist_item("USBDEVICE_STARTIO")
.blocklist_item("USBDEVICE_TREE_PURGEIO")
// FIXME: arrays with more than 32 entries currently fail to generate a `Default`` impl: https://github.com/rust-lang/rust-bindgen/issues/2803
.no_default(".*tagMONITORINFOEXA")
.must_use_type("NTSTATUS")
Expand All @@ -105,7 +137,9 @@ impl BuilderExt for Builder {
.default_enum_style(bindgen::EnumVariation::ModuleConsts)
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
.parse_callbacks(Box::new(WdkCallbacks::new(config)))
.formatter(bindgen::Formatter::Prettyplease);
.formatter(bindgen::Formatter::Prettyplease)
.rust_target(get_rust_target()?)
.rust_edition(get_rust_edition()?);

Ok(builder)
}
Expand Down Expand Up @@ -137,3 +171,67 @@ impl WdkCallbacks {
}
}
}

// Retrieves the Rust version as a `bindgen::RustTarget` for the current build
// configuration.
//
// If the `nightly` feature is enabled and the current toolchain is `nightly`,
// returns a value allowing `bindgen` to generate code with supported `nightly`
// features. Otherwise, queries the MSRV from the `CARGO_PKG_RUST_VERSION`
// environment variable and uses it to create a `bindgen::RustTarget::stable`
// value.
//
// # Errors
//
// Returns `ConfigError::MsrvNotSupportedByBindgen` if the MSRV is not supported
// by bindgen, or `ConfigError::SemverError` if the MSRV cannot be parsed as a
// semver version.
fn get_rust_target() -> Result<bindgen::RustTarget, ConfigError> {
let nightly_feature = cfg!(feature = "nightly");
let nightly_toolchain = rustversion::cfg!(nightly);
if nightly_feature && nightly_toolchain {
return Ok(bindgen::RustTarget::nightly());
}

// Warn user if only one of these two conditions are enabled.
if (nightly_feature && !nightly_toolchain) || (!nightly_feature && nightly_toolchain) {
eprintln!(
"Nightly bindgen features are only enabled with nightly feature enablement and \
nightly toolchain use."
);
}

let package_msrv = semver::Version::parse(env!("CARGO_PKG_RUST_VERSION"))?;

let bindgen_msrv = bindgen::RustTarget::stable(package_msrv.minor, package_msrv.patch)
.map_err(|e| ConfigError::MsrvNotSupportedByBindgen {
msrv: package_msrv.to_string(),
reason: e.to_string(),
})?;
Ok(bindgen_msrv)
}

// Retrieves the Rust edition from `cargo metadata` and returns the appropriate
// `bindgen::RustEdition` value.
//
// # Errors
//
// Returns `ConfigError::CargoMetadataPackageNotFound` if the `wdk-build`
// package is not found, or `ConfigError::UnsupportedRustEdition` if the edition
// is not supported.
fn get_rust_edition() -> Result<bindgen::RustEdition, ConfigError> {
let wdk_sys_cargo_metadata = MetadataCommand::new().exec()?;

let package_name = "wdk-build";

let wdk_sys_package_metadata = wdk_sys_cargo_metadata
.packages
.iter()
.find(|package| package.name == package_name)
.ok_or_else(|| ConfigError::CargoMetadataPackageNotFound {
package_name: package_name.to_string(),
})?;

let rust_edition: BindgenRustEditionWrapper = wdk_sys_package_metadata.edition.try_into()?;
Ok(rust_edition.0)
}
2 changes: 1 addition & 1 deletion crates/wdk-build/src/cargo_make.rs
Original file line number Diff line number Diff line change
Expand Up @@ -977,7 +977,7 @@ pub fn package_driver_flow_condition_script() -> anyhow::Result<()> {
if !current_package
.targets
.iter()
.any(|target| target.kind.iter().any(|kind| kind == "cdylib"))
.any(|target| target.kind.contains(&cargo_metadata::TargetKind::CDyLib))
{
return Err::<(), anyhow::Error>(
metadata::TryFromCargoMetadataError::NoWdkConfigurationsDetected.into(),
Expand Down
Loading