feat(windows-drivers): vendor wdk 0.5.1 + add ApiSubset::Iddcx (M1 spike)
windows-drivers / probe-and-proto (push) Successful in 24s
apple / swift (push) Successful in 1m8s
windows-drivers / driver-build (push) Failing after 43s
ci / rust (push) Successful in 1m31s
ci / web (push) Successful in 1m5s
ci / docs-site (push) Successful in 52s
apple / screenshots (push) Failing after 2m35s
windows-host / package (push) Successful in 5m23s
ci / bench (push) Successful in 4m48s
android / android (push) Successful in 10m1s
decky / build-publish (push) Successful in 26s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 4s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 4s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 4s
deb / build-publish (push) Successful in 3m29s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 4s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 2m21s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Successful in 8m23s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Successful in 8m18s
docker / deploy-docs (push) Successful in 21s
windows-drivers / probe-and-proto (push) Successful in 24s
apple / swift (push) Successful in 1m8s
windows-drivers / driver-build (push) Failing after 43s
ci / rust (push) Successful in 1m31s
ci / web (push) Successful in 1m5s
ci / docs-site (push) Successful in 52s
apple / screenshots (push) Failing after 2m35s
windows-host / package (push) Successful in 5m23s
ci / bench (push) Successful in 4m48s
android / android (push) Successful in 10m1s
decky / build-publish (push) Successful in 26s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 4s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 4s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 4s
deb / build-publish (push) Successful in 3m29s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 4s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 2m21s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Successful in 8m23s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Successful in 8m18s
docker / deploy-docs (push) Successful in 21s
Vendor the published, self-contained windows-drivers-rs 0.5.1 crates (wdk-build, wdk-sys) under vendor/ and add a first-class ApiSubset::Iddcx that bindgens iddcx/1.10/IddCx.h in an extra pass reusing bindgen::Builder::wdk_default (allowlist_file (?i).*iddcx.* — emits only IddCx items; WDF/DXGI types resolve to the shared base/wdf bindings, type-identity by construction). Mirrors the existing gpio/hid/spb subsets exactly: wdk-build gets the enum variant + iddcx_headers() (UMDF-only), wdk-sys gets generate_iddcx + the iddcx feature + pub mod iddcx. [patch.crates-io] redirects all wdk-sys/wdk-build (incl. wdk 0.4.1 transitive) to the patched copies. wdk-probe enables the iddcx feature. MAKE-OR-BREAK: does IddCx.h bindgen in wdk-sys config without a header conflict (issue #515) + does the generated module compile (type-identity)? CI answers it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Generated
-4
@@ -716,8 +716,6 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "wdk-build"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c150122a579af759770b354064cd2994d29e97525d904f65ff1412ad5122766"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bindgen",
|
||||
@@ -767,8 +765,6 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "wdk-sys"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e13e19ed97609bc1d1236806019309ca2d47aaad6d3217ab374e73c9ff3b8a9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bindgen",
|
||||
|
||||
@@ -21,6 +21,14 @@ wdk-sys = "0.5.1"
|
||||
wdk-build = "0.5.1"
|
||||
pf-vdisplay-proto = { path = "../../../crates/pf-vdisplay-proto" }
|
||||
|
||||
# Vendored windows-drivers-rs 0.5.1 (the published, self-contained crates) + an added `iddcx`
|
||||
# ApiSubset (M1 — bindgens iddcx/1.10/IddCx.h reusing wdk_default for WDF type-identity). Redirect ALL
|
||||
# wdk-sys/wdk-build refs (incl. wdk 0.4.1's transitive deps) to the patched copies so there is exactly
|
||||
# one (iddcx-capable) wdk-sys in the graph. Pinned; do not chase upstream.
|
||||
[patch.crates-io]
|
||||
wdk-build = { path = "vendor/wdk-build" }
|
||||
wdk-sys = { path = "vendor/wdk-sys" }
|
||||
|
||||
# wdk-sys's build script reads the WDK driver-model from the WORKSPACE metadata (a workspace build can't
|
||||
# know which member it's building for). All our drivers are UMDF 2.x (incl. pf-vdisplay's IddCx), so set
|
||||
# it once here; a member needing a different model would get its own [package.metadata.wdk.driver-model].
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
|
||||
## [0.5.1](https://github.com/microsoft/windows-drivers-rs/compare/wdk-build-v0.5.0...wdk-build-v0.5.1) - 2025-11-13
|
||||
|
||||
### Fixed
|
||||
|
||||
- fallback to detection logic when WDK env vars have invalid unicode ([#579](https://github.com/microsoft/windows-drivers-rs/pull/579))
|
||||
- path construction in `wdk-build` `get_wdk_tools_root` and `get_wdk_bin_root` ([#574](https://github.com/microsoft/windows-drivers-rs/pull/574))
|
||||
|
||||
### Other
|
||||
|
||||
- fix wdk-build version in readme ([#568](https://github.com/microsoft/windows-drivers-rs/pull/568))
|
||||
|
||||
## [0.5.0](https://github.com/microsoft/windows-drivers-rs/compare/wdk-build-v0.4.0...wdk-build-v0.5.0) - 2025-11-06
|
||||
|
||||
### Added
|
||||
|
||||
- enhance error handling with IoError and IoErrorMetadata for improved std::io::Error diagnostics for fs errors ([#480](https://github.com/microsoft/windows-drivers-rs/pull/480))
|
||||
- add color to cargo wdk and cargo make argument forwarding ([#519](https://github.com/microsoft/windows-drivers-rs/pull/519))
|
||||
- enhance debug tracing in bindgen and config modules ([#455](https://github.com/microsoft/windows-drivers-rs/pull/455))
|
||||
- enhance cargo metadata parsing to respect config.toml ([#451](https://github.com/microsoft/windows-drivers-rs/pull/451))
|
||||
- *(ci)* install and use `nuget` packages in CI workflows ([#406](https://github.com/microsoft/windows-drivers-rs/pull/406))
|
||||
- make `emit_check_cfg_settings` function public ([#352](https://github.com/microsoft/windows-drivers-rs/pull/352))
|
||||
|
||||
### Fixed
|
||||
|
||||
- use latest version of ucx in the WDKContent as default ([#411](https://github.com/microsoft/windows-drivers-rs/pull/411))
|
||||
- improve error reporting when no wdk-build package is found ([#339](https://github.com/microsoft/windows-drivers-rs/pull/339))
|
||||
|
||||
### Other
|
||||
|
||||
- Prepare cargo-wdk for release ([#560](https://github.com/microsoft/windows-drivers-rs/pull/560))
|
||||
- [**breaking**] bump to Rust 2024 Edition ([#430](https://github.com/microsoft/windows-drivers-rs/pull/430))
|
||||
- use `std::path::absolute` instead of canonicalize + strip_extended_path_prefix ([#462](https://github.com/microsoft/windows-drivers-rs/pull/462))
|
||||
- Bump tracing-subscriber from 0.3.19 to 0.3.20 ([#492](https://github.com/microsoft/windows-drivers-rs/pull/492))
|
||||
- enforce typo checking ([#452](https://github.com/microsoft/windows-drivers-rs/pull/452))
|
||||
- update crate references for consistency in documentation ([#440](https://github.com/microsoft/windows-drivers-rs/pull/440))
|
||||
- improve cargo-wdk tests ([#429](https://github.com/microsoft/windows-drivers-rs/pull/429))
|
||||
|
||||
## [0.4.0](https://github.com/microsoft/windows-drivers-rs/compare/wdk-build-v0.3.0...wdk-build-v0.4.0) - 2025-04-18
|
||||
|
||||
### Added
|
||||
|
||||
- extend coverage in `wdk-sys` to include usb-related headers ([#296](https://github.com/microsoft/windows-drivers-rs/pull/296))
|
||||
- expand wdk-sys coverage to include gpio and parallel ports related headers ([#278](https://github.com/microsoft/windows-drivers-rs/pull/278))
|
||||
- add support for Storage API subset in `wdk-sys` ([#287](https://github.com/microsoft/windows-drivers-rs/pull/287))
|
||||
- expand `wdk-sys` coverage to include spb-related headers ([#263](https://github.com/microsoft/windows-drivers-rs/pull/263))
|
||||
- [**breaking**] expand `wdk-sys` coverage to include hid-related headers ([#260](https://github.com/microsoft/windows-drivers-rs/pull/260))
|
||||
|
||||
### Fixed
|
||||
|
||||
- [**breaking**] specify rust version & edition to wdk-default bindgen::builder ([#314](https://github.com/microsoft/windows-drivers-rs/pull/314))
|
||||
- [**breaking**] explicitly mark `_KGDTENTRY64` and `_KIDTENTRY64` as opaque types in `bindgen` ([#277](https://github.com/microsoft/windows-drivers-rs/pull/277))
|
||||
- suppress linker warnings exposed by nightly rustc change ([#279](https://github.com/microsoft/windows-drivers-rs/pull/279))
|
||||
- add missing arm64rt library to linker flags for arm64 kernel-mode builds ([#261](https://github.com/microsoft/windows-drivers-rs/pull/261))
|
||||
|
||||
### Other
|
||||
|
||||
- update README to clarify community engagement and contact methods ([#312](https://github.com/microsoft/windows-drivers-rs/pull/312))
|
||||
- remove noop `must_use` on trait impl ([#302](https://github.com/microsoft/windows-drivers-rs/pull/302))
|
||||
- [**breaking**] Remove lazy static instances ([#250](https://github.com/microsoft/windows-drivers-rs/pull/250))
|
||||
- fix panic condition docs for `package_driver_flow_condition_script` ([#264](https://github.com/microsoft/windows-drivers-rs/pull/264))
|
||||
- port certificate-generation condition script to Rust ([#259](https://github.com/microsoft/windows-drivers-rs/pull/259))
|
||||
- remove redundant code-path in `detect_wdk_content_root` ([#249](https://github.com/microsoft/windows-drivers-rs/pull/249))
|
||||
- use `next_back` instead of `last` on double-ended iterators (`clippy::double_ended_iterator_last`) ([#262](https://github.com/microsoft/windows-drivers-rs/pull/262))
|
||||
- use `is_none_or` for `clippy::nonminimal_bool` and resolve `clippy::needless_raw_string_hashes` ([#231](https://github.com/microsoft/windows-drivers-rs/pull/231))
|
||||
- fix `clippy::nonminimal_bool` and `clippy::ref_option` issues ([#230](https://github.com/microsoft/windows-drivers-rs/pull/230))
|
||||
|
||||
## [0.3.0](https://github.com/microsoft/windows-drivers-rs/compare/wdk-build-v0.2.0...wdk-build-v0.3.0) - 2024-09-27
|
||||
|
||||
### Added
|
||||
|
||||
- add `skip_umdf_static_crt_check` unstable option to prevent static crt linkage check ([#217](https://github.com/microsoft/windows-drivers-rs/pull/217))
|
||||
- [**breaking**] add 'ExAllocatePool' to blocklist due to deprecation ([#190](https://github.com/microsoft/windows-drivers-rs/pull/190))
|
||||
- configure WDK configuration via parsing Cargo manifest metadata ([#186](https://github.com/microsoft/windows-drivers-rs/pull/186))
|
||||
|
||||
### Fixed
|
||||
|
||||
- typos in Getting Started section of README.md ([#213](https://github.com/microsoft/windows-drivers-rs/pull/213))
|
||||
- skip infverif task for sample drivers built with certain GE WDK versions ([#143](https://github.com/microsoft/windows-drivers-rs/pull/143))
|
||||
- [**breaking**] prevent linking of wdk libraries in tests that depend on `wdk-sys` ([#118](https://github.com/microsoft/windows-drivers-rs/pull/118))
|
||||
|
||||
### Other
|
||||
|
||||
- fix `clippy::empty-line-after-doc-comments` lint issues ([#221](https://github.com/microsoft/windows-drivers-rs/pull/221))
|
||||
- move infverif task's condition script logic to cargo_make.rs ([#216](https://github.com/microsoft/windows-drivers-rs/pull/216))
|
||||
- remove unstable `rustfmt` `version` setting (replaced by auto-detected `edition`) ([#220](https://github.com/microsoft/windows-drivers-rs/pull/220))
|
||||
- replace directory substitution plugin with condition_script_runner_args ([#208](https://github.com/microsoft/windows-drivers-rs/pull/208))
|
||||
- use cargo-make's built-in arg expansion instead of custom plugin support in `nested-cargo-workspace-in-cargo-make-emulated-workspace-support` ([#201](https://github.com/microsoft/windows-drivers-rs/pull/201))
|
||||
- Improve doc comments to comply with `too_long_first_doc_paragraph` clippy lint ([#202](https://github.com/microsoft/windows-drivers-rs/pull/202))
|
||||
- Update README.md ([#180](https://github.com/microsoft/windows-drivers-rs/pull/180))
|
||||
- update readme to call out bugged LLVM 18 versions ([#169](https://github.com/microsoft/windows-drivers-rs/pull/169))
|
||||
- Build perf: Make calls to bindgen run in parallel ([#159](https://github.com/microsoft/windows-drivers-rs/pull/159))
|
||||
- add support for rustc-check-cfg ([#150](https://github.com/microsoft/windows-drivers-rs/pull/150))
|
||||
- Bump windows from 0.52.0 to 0.56.0 ([#144](https://github.com/microsoft/windows-drivers-rs/pull/144))
|
||||
- Bump rustversion from 1.0.14 to 1.0.15 ([#145](https://github.com/microsoft/windows-drivers-rs/pull/145))
|
||||
- use a standardized workspace lint table ([#134](https://github.com/microsoft/windows-drivers-rs/pull/134))
|
||||
- Bump clap from 4.4.18 to 4.5.4 ([#130](https://github.com/microsoft/windows-drivers-rs/pull/130))
|
||||
- Bump thiserror from 1.0.56 to 1.0.59 ([#142](https://github.com/microsoft/windows-drivers-rs/pull/142))
|
||||
- fix `winget` llvm install command option ([#115](https://github.com/microsoft/windows-drivers-rs/pull/115))
|
||||
- fix various pipeline breakages (nightly rustfmt bug, new nightly clippy lints, upstream winget dependency issue) ([#117](https://github.com/microsoft/windows-drivers-rs/pull/117))
|
||||
- add lint exceptions for clippy::manual_c_str_literals and clippy::ref_as_ptr ([#108](https://github.com/microsoft/windows-drivers-rs/pull/108))
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
|
||||
## [0.2.0](https://github/microsoft/windows-drivers-rs/compare/wdk-build-v0.1.0...wdk-build-v0.2.0) - 2024-02-08
|
||||
|
||||
### Added
|
||||
- package rust-driver-makefile.toml with wdk-build package ([#36](https://github/microsoft/windows-drivers-rs/pull/36))
|
||||
- support multiple drivers (of same type) in same cargo workspace
|
||||
- cargo-make argument forwarding
|
||||
- generate CStr for c string constants instead of &[u8] ([#72](https://github/microsoft/windows-drivers-rs/pull/72))
|
||||
|
||||
### Fixed
|
||||
- resolve warnings in rust-script blocks and only fail warnings in CI ([#87](https://github/microsoft/windows-drivers-rs/pull/87))
|
||||
- add missing cpu-arch macro definitions
|
||||
- fix wdk path regkey detection
|
||||
|
||||
### Other
|
||||
- update versions in readme and rust-driver-makefile.toml
|
||||
- update dependencies
|
||||
- allow multiple_crate_versions in wdk-build (build dependency) ([#98](https://github/microsoft/windows-drivers-rs/pull/98))
|
||||
- update cargo-make tasks with arch-specific tools
|
||||
- Bump thiserror from 1.0.48 to 1.0.55 ([#59](https://github/microsoft/windows-drivers-rs/pull/59))
|
||||
- restrict to one unsafe operation per block ([#24](https://github/microsoft/windows-drivers-rs/pull/24))
|
||||
- [**breaking**] enable rustdoc lints and resolve errors
|
||||
- initial open-source check in
|
||||
+918
@@ -0,0 +1,918 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"is_terminal_polyfill",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"once_cell_polyfill",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.97"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f"
|
||||
|
||||
[[package]]
|
||||
name = "assert_fs"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a652f6cb1f516886fcfee5e7a5c078b9ade62cfcb889524efe5a64d682dd27a9"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"doc-comment",
|
||||
"globwalk",
|
||||
"predicates",
|
||||
"predicates-core",
|
||||
"predicates-tree",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.71.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"itertools",
|
||||
"log",
|
||||
"prettyplease",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
"shlex",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
|
||||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
version = "1.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "camino"
|
||||
version = "1.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo-platform"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo_metadata"
|
||||
version = "0.19.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba"
|
||||
dependencies = [
|
||||
"camino",
|
||||
"cargo-platform",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cexpr"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9"
|
||||
|
||||
[[package]]
|
||||
name = "clang-sys"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"libc",
|
||||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap-cargo"
|
||||
version = "0.15.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d546f0e84ff2bfa4da1ce9b54be42285767ba39c688572ca32412a09a73851e5"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"clap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
|
||||
dependencies = [
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||
|
||||
[[package]]
|
||||
name = "difflib"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
|
||||
|
||||
[[package]]
|
||||
name = "doc-comment"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||
|
||||
[[package]]
|
||||
name = "globset"
|
||||
version = "0.4.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54a1028dfc5f5df5da8a56a73e6c153c9a9708ec57232470703592a3f18e49f5"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"bstr",
|
||||
"log",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "globwalk"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0bf760ebf69878d9fd8f110c89703d90ce35095324d1f1edcb595c63945ee757"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"ignore",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "ignore"
|
||||
version = "0.4.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b"
|
||||
dependencies = [
|
||||
"crossbeam-deque",
|
||||
"globset",
|
||||
"log",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"same-file",
|
||||
"walkdir",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.172"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell_polyfill"
|
||||
version = "1.70.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
|
||||
|
||||
[[package]]
|
||||
name = "predicates"
|
||||
version = "3.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5d19ee57562043d37e82899fade9a22ebab7be9cef5026b07fda9cdd4293573"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"difflib",
|
||||
"predicates-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "predicates-core"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "727e462b119fe9c93fd0eb1429a5f7647394014cf3c04ab2c0350eeb09095ffa"
|
||||
|
||||
[[package]]
|
||||
name = "predicates-tree"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72dd2d6d381dfb73a193c7fca536518d7caee39fc8503f74e7dc0be0531b425c"
|
||||
dependencies = [
|
||||
"predicates-core",
|
||||
"termtree",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prettyplease"
|
||||
version = "0.2.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.101"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.219"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.219"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.140"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.23.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"getrandom",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termtree"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
|
||||
dependencies = [
|
||||
"pin-project-lite",
|
||||
"tracing-attributes",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-attributes"
|
||||
version = "0.1.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.13.3+wasi-0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
|
||||
dependencies = [
|
||||
"wit-bindgen-rt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wdk-build"
|
||||
version = "0.5.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"assert_fs",
|
||||
"bindgen",
|
||||
"camino",
|
||||
"cargo_metadata",
|
||||
"cfg-if",
|
||||
"clap",
|
||||
"clap-cargo",
|
||||
"paste",
|
||||
"regex",
|
||||
"rustversion",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"tracing",
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.58.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6"
|
||||
dependencies = [
|
||||
"windows-core",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.58.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99"
|
||||
dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-result",
|
||||
"windows-strings",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.58.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-interface"
|
||||
version = "0.58.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
|
||||
dependencies = [
|
||||
"windows-result",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rt"
|
||||
version = "0.33.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
@@ -0,0 +1,142 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2024"
|
||||
rust-version = "1.85.0"
|
||||
name = "wdk-build"
|
||||
version = "0.5.1"
|
||||
build = "build.rs"
|
||||
autolib = false
|
||||
autobins = false
|
||||
autoexamples = false
|
||||
autotests = false
|
||||
autobenches = false
|
||||
description = "A library to configure a Cargo build script for binding generation and downstream linking of the WDK (Windows Driver Kit)"
|
||||
readme = "README.md"
|
||||
keywords = [
|
||||
"wdk",
|
||||
"windows",
|
||||
"build-dependencies",
|
||||
]
|
||||
categories = [
|
||||
"development-tools::build-utils",
|
||||
"development-tools::ffi",
|
||||
]
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/microsoft/windows-drivers-rs"
|
||||
|
||||
[package.metadata.cargo-machete]
|
||||
ignored = ["regex"]
|
||||
|
||||
[features]
|
||||
nightly = []
|
||||
|
||||
[lib]
|
||||
name = "wdk_build"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies.anyhow]
|
||||
version = "1.0.97"
|
||||
|
||||
[dependencies.bindgen]
|
||||
version = "0.71.0"
|
||||
|
||||
[dependencies.camino]
|
||||
version = "1.1.9"
|
||||
|
||||
[dependencies.cargo_metadata]
|
||||
version = "0.19.2"
|
||||
|
||||
[dependencies.cfg-if]
|
||||
version = "1.0.3"
|
||||
|
||||
[dependencies.clap]
|
||||
version = "4.5.40"
|
||||
features = ["derive"]
|
||||
|
||||
[dependencies.clap-cargo]
|
||||
version = "0.15.2"
|
||||
|
||||
[dependencies.paste]
|
||||
version = "1.0.15"
|
||||
|
||||
[dependencies.regex]
|
||||
version = "1.11.1"
|
||||
features = ["unicode-case"]
|
||||
|
||||
[dependencies.rustversion]
|
||||
version = "1.0.20"
|
||||
|
||||
[dependencies.semver]
|
||||
version = "1.0.26"
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0"
|
||||
features = ["derive"]
|
||||
|
||||
[dependencies.serde_json]
|
||||
version = "1.0"
|
||||
|
||||
[dependencies.thiserror]
|
||||
version = "2.0.12"
|
||||
|
||||
[dependencies.tracing]
|
||||
version = "0.1.40"
|
||||
|
||||
[dependencies.windows]
|
||||
version = "0.58.0"
|
||||
features = [
|
||||
"Win32_Foundation",
|
||||
"Win32_System_Registry",
|
||||
]
|
||||
|
||||
[dev-dependencies.assert_fs]
|
||||
version = "1.1.3"
|
||||
|
||||
[dev-dependencies.windows]
|
||||
version = "0.58.0"
|
||||
features = ["Win32_UI_Shell"]
|
||||
|
||||
[build-dependencies.rustversion]
|
||||
version = "1.0.20"
|
||||
|
||||
[lints.clippy]
|
||||
all = "deny"
|
||||
cargo = "warn"
|
||||
multiple_unsafe_ops_per_block = "deny"
|
||||
nursery = "warn"
|
||||
pedantic = "warn"
|
||||
undocumented_unsafe_blocks = "deny"
|
||||
unnecessary_safety_doc = "deny"
|
||||
|
||||
[lints.rust]
|
||||
missing_docs = "warn"
|
||||
unsafe_op_in_unsafe_fn = "forbid"
|
||||
|
||||
[lints.rust.unexpected_cfgs]
|
||||
level = "warn"
|
||||
priority = 0
|
||||
check-cfg = [
|
||||
"cfg(wdk_build_unstable)",
|
||||
"cfg(skip_umdf_static_crt_check)",
|
||||
]
|
||||
|
||||
[lints.rustdoc]
|
||||
bare_urls = "warn"
|
||||
broken_intra_doc_links = "warn"
|
||||
invalid_codeblock_attributes = "warn"
|
||||
invalid_html_tags = "warn"
|
||||
invalid_rust_codeblocks = "warn"
|
||||
missing_crate_level_docs = "warn"
|
||||
private_intra_doc_links = "warn"
|
||||
redundant_explicit_links = "warn"
|
||||
unescaped_backticks = "warn"
|
||||
@@ -0,0 +1,237 @@
|
||||
# windows-drivers-rs
|
||||
|
||||
This repo is a collection of Rust crates that enable developers to develop Windows Drivers in Rust. It is the intention to support both WDM and WDF driver development models. This repo contains the following crates:
|
||||
|
||||
* [wdk-build](./crates/wdk-build): A library to configure a Cargo build script for binding generation and downstream linking of the WDK (Windows Driver Kit). While this crate is written to be flexible with different WDK releases and different WDF version, it is currently only tested for NI eWDK, KMDF 1.33, UMDF 2.33, and WDM Drivers. There may be missing linker options for older DDKs.
|
||||
* [wdk-sys](./crates/wdk-sys): Direct FFI bindings to APIs available in the Windows Development Kit (WDK). This includes both autogenerated ffi bindings from `bindgen`, and also manual re-implementations of macros that bindgen fails to generate.
|
||||
* [wdk](./crates/wdk): Safe idiomatic bindings to APIs available in the Windows Development Kit (WDK)
|
||||
* [wdk-panic](./crates/wdk-panic/): Default panic handler implementations for programs built with WDK
|
||||
* [wdk-alloc](./crates/wdk-alloc): alloc support for binaries compiled with the Windows Development Kit (WDK)
|
||||
* [wdk-macros](./crates/wdk-macros): A collection of macros that help make it easier to interact with wdk-sys's direct bindings. This crate is re-exported via `wdk-sys` and crates should typically never need to directly depend on `wdk-macros`
|
||||
|
||||
To see an example of this repo used to create drivers, see [Windows-rust-driver-samples](https://github.com/microsoft/Windows-rust-driver-samples).
|
||||
|
||||
Note: This project is still in early stages of development and is not yet recommended for production use. We encourage community experimentation and collaboration through our [GitHub Discussions forum](https://github.com/microsoft/windows-drivers-rs/discussions)!
|
||||
|
||||
## <a name="supported-configs">Supported Configurations
|
||||
|
||||
This project was built with support of WDM, KMDF, and UMDF drivers in mind, as well as Win32 Services. This includes support for all versions of WDF included in WDK 22H2 and newer. Currently, the crates available on [`crates.io`](https://crates.io) only support KMDF v1.33, but bindings can be generated for everything else by cloning `windows-drivers-rs` and modifying the config specified in [`build.rs` of `wdk-sys`](./crates/wdk-sys/build.rs). Crates.io support for other WDK configurations is planned in the near future.
|
||||
|
||||
## Repo Layout
|
||||
|
||||
* [crates](./crates): Contains all the main crates that are a part of the Cargo workspace.
|
||||
* [examples](./examples): Contains workspace-level examples. These examples consist of different types of minimal Windows drivers (ie. WDM, KMDF, UMDF).
|
||||
* [tests](./tests): Contains workspace-level tests, including tests for metadata-based wdk configuration in packages and workspaces.
|
||||
|
||||
**Note:**: Since the workspace level examples and tests use different WDK configurations, and WDR only supports one WDK configuration per workspace, the workspace-level examples and tests folder are excluded from the [repository root's Cargo manifest](./Cargo.toml).
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Build Requirements
|
||||
|
||||
* Binding generation via `bindgen` requires `libclang`. The easiest way to acquire this is via `winget`
|
||||
* `winget install -i LLVM.LLVM --version 17.0.6 --force`
|
||||
* Ensure you select the GUI option to add LLVM to the PATH
|
||||
* LLVM 18 has a bug that causes bindings to fail to generate for ARM64. Continue using LLVM 17 until LLVM 19 comes out with [the fix](https://github.com/llvm/llvm-project/pull/93235). See [this](https://github.com/rust-lang/rust-bindgen/issues/2842) for more details.
|
||||
* To execute post-build tasks (ie. `inf2cat`, `infverif`, etc.), `cargo make` is used
|
||||
* `cargo install --locked cargo-make --no-default-features --features tls-native`
|
||||
|
||||
* Building programs with the WDK also requires being in a valid WDK environment. The recommended way to do this is to [enter an eWDK developer prompt](https://learn.microsoft.com/en-us/windows-hardware/drivers/develop/using-the-enterprise-wdk#getting-started)
|
||||
|
||||
### Adding windows-drivers-rs to Your Driver Package
|
||||
|
||||
The crates in this repository are available from [`crates.io`](https://crates.io), but take into account the current limitations outlined in [Supported Configurations](#supported-configs). If you need to support a different config, try cloning this repo and using [path dependencies](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#specifying-path-dependencies)
|
||||
|
||||
1. Create a new Cargo package with a lib crate:
|
||||
|
||||
```pwsh
|
||||
cargo new <driver_name> --lib
|
||||
```
|
||||
|
||||
1. Add dependencies on `windows-drivers-rs` crates:
|
||||
|
||||
```pwsh
|
||||
cd <driver_name>
|
||||
cargo add --build wdk-build
|
||||
cargo add wdk wdk-sys wdk-alloc wdk-panic
|
||||
```
|
||||
|
||||
1. Set the crate type to `cdylib` by adding the following snippet to `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
```
|
||||
|
||||
1. Add a wdk metadata section and configure the wdk for your use case. This also lets the cargo-make tasks know that the package is a driver and that the driver packaging steps need to run.
|
||||
|
||||
UMDF Example:
|
||||
```toml
|
||||
[package.metadata.wdk.driver-model]
|
||||
driver-type = "UMDF"
|
||||
umdf-version-major = 1
|
||||
target-umdf-version-minor = 33
|
||||
```
|
||||
|
||||
1. **For Kernel Mode crates** (ex. `KMDF` drivers, `WDM` drivers): Set crate panic strategy to `abort` in `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[profile.dev]
|
||||
panic = "abort"
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
```
|
||||
|
||||
1. Create a `build.rs` and add the following snippet:
|
||||
|
||||
```rust
|
||||
fn main() -> Result<(), wdk_build::ConfigError> {
|
||||
wdk_build::configure_wdk_binary_build()
|
||||
}
|
||||
```
|
||||
|
||||
1. **For Kernel Mode crates** (ex. `KMDF` drivers, `WDM` drivers): Mark your driver crate as `no_std` in `lib.rs`:
|
||||
|
||||
```rust
|
||||
#![no_std]
|
||||
```
|
||||
|
||||
1. **For Kernel Mode crates** (ex. `KMDF` drivers, `WDM` drivers): Add a panic handler in `lib.rs`:
|
||||
|
||||
```rust
|
||||
#[cfg(not(test))]
|
||||
extern crate wdk_panic;
|
||||
|
||||
```
|
||||
|
||||
1. **For Kernel Mode crates** (ex. `KMDF` drivers, `WDM` drivers): Add an optional global allocator in `lib.rs`:
|
||||
|
||||
```rust
|
||||
#[cfg(not(test))]
|
||||
use wdk_alloc::WdkAllocator;
|
||||
|
||||
#[cfg(not(test))]
|
||||
#[global_allocator]
|
||||
static GLOBAL_ALLOCATOR: WdkAllocator = WdkAllocator;
|
||||
```
|
||||
|
||||
This is only required if you want to be able to use the [`alloc` modules](https://doc.rust-lang.org/alloc/) in the rust standard library.
|
||||
|
||||
1. Add a DriverEntry in `lib.rs`:
|
||||
|
||||
```rust
|
||||
use wdk_sys::{
|
||||
PDRIVER_OBJECT,
|
||||
NTSTATUS,
|
||||
PCUNICODE_STRING,
|
||||
};
|
||||
|
||||
// SAFETY: "DriverEntry" is the required symbol name for Windows driver entry points.
|
||||
// No other function in this compilation unit exports this name, preventing symbol conflicts.
|
||||
#[unsafe(export_name = "DriverEntry")] // WDF expects a symbol with the name DriverEntry
|
||||
pub unsafe extern "system" fn driver_entry(
|
||||
driver: PDRIVER_OBJECT,
|
||||
registry_path: PCUNICODE_STRING,
|
||||
) -> NTSTATUS {
|
||||
0
|
||||
}
|
||||
```
|
||||
|
||||
Note: In Kernel Mode crates, you can use `driver: &mut DRIVER_OBJECT` instead of `driver: PDRIVER_OBJECT`.
|
||||
|
||||
1. Add a `Makefile.toml`:
|
||||
```toml
|
||||
extend = "target/rust-driver-makefile.toml"
|
||||
|
||||
[config]
|
||||
load_script = '''
|
||||
#!@rust
|
||||
//! ```cargo
|
||||
//! [dependencies]
|
||||
//! wdk-build = "0.5.1"
|
||||
//! ```
|
||||
#![allow(unused_doc_comments)]
|
||||
|
||||
wdk_build::cargo_make::load_rust_driver_makefile()?
|
||||
'''
|
||||
```
|
||||
|
||||
1. Add an inx file that matches the name of your `cdylib` crate.
|
||||
|
||||
1. Enable static crt linkage. One approach is to add this to your `.cargo/config.toml`:
|
||||
|
||||
```toml
|
||||
[build]
|
||||
rustflags = ["-C", "target-feature=+crt-static"]
|
||||
```
|
||||
|
||||
1. Build the driver:
|
||||
|
||||
```pwsh
|
||||
cargo make
|
||||
```
|
||||
|
||||
A signed driver package, including a `WDRLocalTestCert.cer` file, will be generated at `target/<Cargo profile>/package`. If a specific target architecture was specified, the driver package will be generated at `target/<target architecture>/<Cargo profile>/package`
|
||||
|
||||
Minimal examples of `WDM`, `KMDF`, and `UMDF` drivers can be found in the [examples directory](./examples).
|
||||
|
||||
## Cargo Make
|
||||
|
||||
[`cargo-make`](https://github.com/sagiegurari/cargo-make) is used to facilitate builds using `windows-drivers-rs`, including for executing post-build driver packaging steps.
|
||||
|
||||
To execute the default action (build and package driver):
|
||||
|
||||
`cargo make default`
|
||||
|
||||
When executing the default task, just `cargo make` make also works since the `default` task is implied.
|
||||
|
||||
### Argument Forwarding
|
||||
|
||||
`windows-drivers-rs` extends `cargo make` to forward specific arguments to the underlying `cargo` commands. In order to specify arguments to forward, they must be provided **after explicitly specifying the `cargo-make` task name** (ie. omitting the name for the `default` task is not supported).
|
||||
|
||||
#### Examples
|
||||
|
||||
For a specific target:
|
||||
|
||||
`cargo make default --target <TARGET TRIPLE>`
|
||||
|
||||
For release builds:
|
||||
|
||||
`cargo make default --release` or `cargo make default --profile release`
|
||||
|
||||
To specify specific features:
|
||||
|
||||
`cargo make default --features <FEATURES>`
|
||||
|
||||
To specify a specific rust toolchain:
|
||||
|
||||
`cargo make default +<TOOLCHAIN>`
|
||||
|
||||
To display help and see the full list of supported CLI args to forward to Cargo:
|
||||
|
||||
`cargo make help`
|
||||
|
||||
### Driver Package Signature Verification
|
||||
|
||||
The `WDK_BUILD_ENABLE_SIGNTOOL_VERIFY` [cargo-make environment variable](https://github.com/sagiegurari/cargo-make?tab=readme-ov-file#environment-variables) can be set to `true` to enable tasks that handle signature verification of the generated `.sys` and `.cat` files. `signtool verify` requires the certificate to be installed as in the `Trusted Root Certification Authorities` for this verification to function. These tasks are not enabled by default as the default behavior of `WDR` is to sign with a generated test certificate. These test certificates are typically only installed into `Trusted Root Certification Authorities` on computers dedicated to testing drivers, and not personal development machines, given the security implications of installing your own root certificates.
|
||||
|
||||
If you understand these implications, and have installed the test certificate, then you may validate the signatures as follows:
|
||||
|
||||
```
|
||||
cargo make --env WDK_BUILD_ENABLE_SIGNTOOL_VERIFY=true
|
||||
```
|
||||
|
||||
## Contact
|
||||
|
||||
* For bug reports, feature requests, and other actionable items, please use [GitHub Issues](https://github.com/microsoft/windows-drivers-rs/issues)
|
||||
* For broader questions, architectural discussions, and community engagement, please use [GitHub Discussions](https://github.com/microsoft/windows-drivers-rs/discussions)
|
||||
* For inquiries not suitable for public forums, email us at <RustWindowsDrivers@microsoft.com>
|
||||
|
||||
## Crates.io Release Policy
|
||||
|
||||
Releases to crates.io are not made after every change merged to main. Releases will only be made when requested by the community, or when the `windows-drivers-rs` team believes there is sufficient value in pushing a release.
|
||||
|
||||
## Trademark Notice
|
||||
|
||||
Trademarks This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow Microsoft’s Trademark & Brand Guidelines. Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party’s policies.
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// License: MIT OR Apache-2.0
|
||||
|
||||
//! Build script for the `wdk-build` crate
|
||||
//!
|
||||
//! This provides a `nightly_toolchain` feature to the `wdk-build` crate, so
|
||||
//! that it can conditionally enable unstable features.
|
||||
|
||||
fn main() {
|
||||
println!("cargo::rustc-check-cfg=cfg(nightly_toolchain)");
|
||||
setup_nightly_cfgs();
|
||||
}
|
||||
|
||||
// Custom attributes cannot be applied to expressions yet, so separate functions are required for nightly/non-nightly: https://github.com/rust-lang/rust/issues/15701
|
||||
#[rustversion::nightly]
|
||||
fn setup_nightly_cfgs() {
|
||||
println!("cargo::rustc-cfg=nightly_toolchain");
|
||||
}
|
||||
|
||||
#[rustversion::not(nightly)]
|
||||
const fn setup_nightly_cfgs() {}
|
||||
@@ -0,0 +1,567 @@
|
||||
# This file is leveraged to build downstream drivers. See examples at https://github.com/microsoft/Windows-rust-drivers-samples
|
||||
|
||||
[config]
|
||||
min_version = "0.37.16"
|
||||
init_task = "wdk-build-init"
|
||||
reduce_output = false
|
||||
|
||||
[env]
|
||||
# This allows all workspace members to access this makefile
|
||||
CARGO_MAKE_EXTEND_WORKSPACE_MAKEFILE = true
|
||||
|
||||
# CARGO_MAKE_CARGO_BUILD_TEST_FLAGS is set to "--all-features" by default in cargo-make: https://github.com/sagiegurari/cargo-make/blob/c0abc4d0ae1bcc03adde22b63fa0accc4af2b3bc/src/lib/descriptor/makefiles/stable.toml#L31
|
||||
# This is set to "" here to match the default behavior of Cargo.
|
||||
CARGO_MAKE_CARGO_BUILD_TEST_FLAGS = { unset = true }
|
||||
|
||||
# rust-script condition_script's return `Err` to signal that the task should not be run. Hide Err backtraces by default to keep output cleaner.
|
||||
RUST_LIB_BACKTRACE = 0
|
||||
|
||||
WDK_BUILD_BASE_INFVERIF_FLAGS = "/v"
|
||||
|
||||
[plugins.impl.rust-env-update]
|
||||
script = '''
|
||||
assert ${task.has_script} "script is required for rust-env-update plugin"
|
||||
assert_eq ${task.script_runner} @rust "script_runner must be set to @rust for rust-env-update plugin"
|
||||
|
||||
cargo_make_rust_script_provider = get_env CARGO_MAKE_RUST_SCRIPT_PROVIDER
|
||||
assert_eq ${cargo_make_rust_script_provider} rust-script "rust-env-update plugin is only compatible with rust-script"
|
||||
|
||||
taskjson = json_parse ${task.as_json}
|
||||
|
||||
# Install dependency crate
|
||||
out = exec --fail-on-error cargo install ${taskjson.install_crate.crate_name} --version ${taskjson.install_crate.min_version}
|
||||
assert_eq ${out.code} 0 "[tasks.${task.name}]'s install_crate failed with exit code: ${out.code}\nstdout:\n${out.stdout}\nstderr:\n${out.stderr}"
|
||||
|
||||
# Enable rust-env-update's rust-script cache (Note: when developing locally on WDR itself, rust-script.exe --clear-cache can be used to force a rebuild of the script's wdk-build dependency)
|
||||
filepath = set "${CARGO_MAKE_CRATE_CUSTOM_TRIPLE_TARGET_DIRECTORY}/cargo-make-script/${task.name}/rust-env-update.rs"
|
||||
# If a file already exists, only overwrite it if the script has changed (so that rust-script caching can be leveraged)
|
||||
if is_file ${filepath}
|
||||
old_hash = digest --algo sha256 --file ${filepath}
|
||||
new_hash = digest --algo sha256 ${taskjson.script}
|
||||
if not eq ${old_hash} ${new_hash}
|
||||
writefile ${filepath} ${taskjson.script}
|
||||
end
|
||||
else
|
||||
writefile ${filepath} ${taskjson.script}
|
||||
end
|
||||
|
||||
# Append cli args to task args
|
||||
task_args = array_join ${task.args} " "
|
||||
cli_args = array_join ${flow.cli.args} " "
|
||||
combined_args = concat ${cli_args} " " ${task_args}
|
||||
combined_args = trim ${combined_args}
|
||||
|
||||
# Execute rust-script
|
||||
out = exec --fail-on-error rust-script --base-path ${taskjson.env.CARGO_MAKE_CURRENT_TASK_INITIAL_MAKEFILE_DIRECTORY} ${CARGO_MAKE_CRATE_CUSTOM_TRIPLE_TARGET_DIRECTORY}/cargo-make-script/${task.name}/rust-env-update.rs %{combined_args}
|
||||
assert_eq ${out.code} 0 "[tasks.${task.name}]'s script failed with exit code: ${out.code}\nstdout:\n${out.stdout}\nstderr:\n${out.stderr}\nThe temporary rust-script file is located at ${CARGO_MAKE_CRATE_CUSTOM_TRIPLE_TARGET_DIRECTORY}/cargo-make-script/${task.name}/rust-env-update.rs"
|
||||
|
||||
if contains ${combined_args} "--help"
|
||||
println ${out.stdout}
|
||||
|
||||
# If help was triggered, exit with code 1 to prevent the rest of the makefile from running
|
||||
exit 1
|
||||
end
|
||||
|
||||
# Set cargo-make env vars based on output of rust-script
|
||||
script_output = trim ${out.stdout}
|
||||
if not is_empty ${script_output}
|
||||
script_output_array = split ${script_output} \n
|
||||
|
||||
# Search the stdout output of the script, with the following behaviours for each line:
|
||||
# 1. If the line is between the "FORWARDING ARGS TO CARGO-MAKE:" start delimited and the "END OF FORWARDING ARGS TO CARGO-MAKE" end delimiter, update the cargo-make process' environment variables based on the key-value pairs in the line.
|
||||
# 2. If the line is not between the start and end delimiters, print the line normally.
|
||||
looking_for_start_delimiter = set true
|
||||
for line in ${script_output_array}
|
||||
if ${looking_for_start_delimiter}
|
||||
if eq ${line} "FORWARDING ARGS TO CARGO-MAKE:"
|
||||
looking_for_start_delimiter = set false
|
||||
else
|
||||
# Any output not surrounded by the start and end delimiter lines should be printed normally
|
||||
println ${line}
|
||||
end
|
||||
else
|
||||
if eq ${line} "END OF FORWARDING ARGS TO CARGO-MAKE"
|
||||
looking_for_start_delimiter = set true
|
||||
else
|
||||
# Set cargo-make env_var based on line output
|
||||
parts = split ${line} =
|
||||
key = array_get ${parts} 0
|
||||
value = array_get ${parts} 1
|
||||
set_env ${key} ${value}
|
||||
end
|
||||
end
|
||||
end
|
||||
assert ${looking_for_start_delimiter} "A matching \"END OF FORWARDING ARGS TO CARGO-MAKE\" for a \"FORWARDING ARGS TO CARGO-MAKE:\" was not found in script output."
|
||||
end
|
||||
'''
|
||||
|
||||
# This plugin adds support for cargo-make's emulated workspace feature to work on emulated workspace members which are Cargo workspaces themselves.
|
||||
# Since Cargo workspaces are not detected in cargo-make emulated workspace members, the task is rerun in a forked subprocess with the CARGO_MAKE_CRATE_CURRENT_WORKSPACE_MEMBER env var unset to allow cargo-make's workspace detection to run.
|
||||
[plugins.impl.nested-cargo-workspace-in-cargo-make-emulated-workspace-support]
|
||||
script = '''
|
||||
# If current flow is executing in a Cargo workspace, which is a member of a cargo-make emulated workspace
|
||||
if ${CARGO_MAKE_WORKSPACE_EMULATION} and ${CARGO_MAKE_CRATE_IS_WORKSPACE}
|
||||
|
||||
# Re-run the task in a forked subprocess, allowing cargo-make to run in a workspace context (i.e. running on each of the members of the Cargo workspace)
|
||||
echo Executing \"${task.name}\" Task in a forked subprocess to run on Cargo workspace: ${CARGO_MAKE_CRATE_CURRENT_WORKSPACE_MEMBER}
|
||||
|
||||
# Unset the CARGO_MAKE_CRATE_CURRENT_WORKSPACE_MEMBER env var to allow cargo-make's workspace detection to run
|
||||
unset_env CARGO_MAKE_CRATE_CURRENT_WORKSPACE_MEMBER
|
||||
|
||||
cm_plugin_run_custom_task "{\"run_task\":{\"name\":\"${task.name}\",\"fork\":true}}"
|
||||
else
|
||||
cm_plugin_run_task
|
||||
end
|
||||
'''
|
||||
|
||||
[tasks.wdk-build-init]
|
||||
private = true
|
||||
install_crate = { crate_name = "rust-script", min_version = "0.30.0" }
|
||||
plugin = "rust-env-update"
|
||||
script_runner = "@rust"
|
||||
script = '''
|
||||
//! ```cargo
|
||||
//! [dependencies]
|
||||
//! wdk-build = { path = ".", version = "0.5.1" }
|
||||
//! ```
|
||||
#![allow(unused_doc_comments)]
|
||||
|
||||
let cli_env_vars = wdk_build::cargo_make::validate_command_line_args();
|
||||
let path_env_vars = wdk_build::cargo_make::setup_path()?;
|
||||
let wdk_version_env_vars = wdk_build::cargo_make::setup_wdk_version()?;
|
||||
|
||||
wdk_build::cargo_make::forward_printed_env_vars(
|
||||
cli_env_vars.into_iter().chain(path_env_vars).chain(wdk_version_env_vars),
|
||||
);
|
||||
'''
|
||||
|
||||
[tasks.setup-wdk-config-env-vars]
|
||||
# This exists as a separate task outside of `wdk-build-init` so that any wdk-metadata-detection errors can be a hard error, without failing every task flow that executes on non-driver crates in the workspace.
|
||||
private = true
|
||||
install_crate = { crate_name = "rust-script", min_version = "0.30.0" }
|
||||
plugin = "rust-env-update"
|
||||
script_runner = "@rust"
|
||||
script_runner_args = [
|
||||
"--base-path",
|
||||
"${CARGO_MAKE_CURRENT_TASK_INITIAL_MAKEFILE_DIRECTORY}",
|
||||
]
|
||||
script = '''
|
||||
//! ```cargo
|
||||
//! [dependencies]
|
||||
//! wdk-build = { path = ".", version = "0.5.1" }
|
||||
//! ```
|
||||
#![allow(unused_doc_comments)]
|
||||
|
||||
let serialized_wdk_metadata_map = wdk_build::metadata::to_map_with_prefix::<std::collections::BTreeMap<_, _>>(
|
||||
"WDK_BUILD_METADATA",
|
||||
&wdk_build::metadata::Wdk::try_from(&wdk_build::cargo_make::get_cargo_metadata()?)?,
|
||||
)?;
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
compile_error!(
|
||||
"windows-drivers-rs is designed to be run on a Windows host machine in a WDK \
|
||||
environment. Please build using a Windows target."
|
||||
);
|
||||
|
||||
for (key, value) in &serialized_wdk_metadata_map {
|
||||
// SAFETY: this function is only conditionally compiled for windows targets, and
|
||||
// env::set_var is always safe for windows targets
|
||||
unsafe {
|
||||
std::env::set_var(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
wdk_build::cargo_make::forward_printed_env_vars(
|
||||
serialized_wdk_metadata_map
|
||||
.into_iter()
|
||||
.map(|(key, _)| key),
|
||||
);
|
||||
'''
|
||||
|
||||
[tasks.copy-inx-to-output]
|
||||
private = true
|
||||
script_runner = "@rust"
|
||||
script_runner_args = [
|
||||
"--base-path",
|
||||
"${CARGO_MAKE_CURRENT_TASK_INITIAL_MAKEFILE_DIRECTORY}",
|
||||
]
|
||||
script = '''
|
||||
//! ```cargo
|
||||
//! [dependencies]
|
||||
//! wdk-build = { path = ".", version = "0.5.1" }
|
||||
//! ```
|
||||
#![allow(unused_doc_comments)]
|
||||
|
||||
// Create build output directory if it doesn't exist
|
||||
let output_folder_path = wdk_build::cargo_make::get_wdk_build_output_directory();
|
||||
if !output_folder_path.exists() {
|
||||
std::fs::create_dir_all(&output_folder_path).expect(&format!("creation of '{}' folder should succeed", output_folder_path.display()));
|
||||
}
|
||||
|
||||
let cargo_make_working_directory = std::env::var("CARGO_MAKE_WORKING_DIRECTORY").expect(
|
||||
"CARGO_MAKE_WORKING_DIRECTORY should be set by cargo-make via the env section of \
|
||||
rust-driver-makefile.toml",
|
||||
);
|
||||
|
||||
let source_file = [
|
||||
cargo_make_working_directory,
|
||||
format!("{}.inx", wdk_build::cargo_make::get_current_package_name()),
|
||||
]
|
||||
.iter()
|
||||
.collect::<std::path::PathBuf>();
|
||||
|
||||
let destination_file = wdk_build::cargo_make::get_wdk_build_output_directory().join(format!(
|
||||
"{}.inf",
|
||||
wdk_build::cargo_make::get_current_package_name()
|
||||
));
|
||||
|
||||
std::fs::copy(&source_file, &destination_file).expect(&format!(
|
||||
"copy of '{}' file to '{}' file should succeed",
|
||||
source_file.display(),
|
||||
destination_file.display()
|
||||
));
|
||||
'''
|
||||
|
||||
[tasks.generate-driver-binary-file]
|
||||
private = true
|
||||
dependencies = ["setup-wdk-config-env-vars", "build"]
|
||||
condition_script_runner_args = [
|
||||
"--base-path",
|
||||
"${CARGO_MAKE_CURRENT_TASK_INITIAL_MAKEFILE_DIRECTORY}",
|
||||
]
|
||||
condition_script = '''
|
||||
#!@rust
|
||||
|
||||
//! ```cargo
|
||||
//! [dependencies]
|
||||
//! wdk-build = { path = ".", version = "0.5.1" }
|
||||
//! ```
|
||||
#![allow(unused_doc_comments)]
|
||||
|
||||
wdk_build::cargo_make::condition_script(|| {
|
||||
let driver_type = std::env::var("WDK_BUILD_METADATA-DRIVER_MODEL-DRIVER_TYPE")
|
||||
.expect("WDK_BUILD_METADATA-DRIVER_MODEL-DRIVER_TYPE should be set by setup-wdk-config-env-vars cargo-make task");
|
||||
|
||||
match driver_type.as_str() {
|
||||
"WDM" | "KMDF" => Ok(()),
|
||||
_ => Err("Non-Kernel Mode Driver detected. Skipping generate-driver-binary-file task."),
|
||||
}
|
||||
})?
|
||||
'''
|
||||
script_runner_args = [
|
||||
"--base-path",
|
||||
"${CARGO_MAKE_CURRENT_TASK_INITIAL_MAKEFILE_DIRECTORY}",
|
||||
]
|
||||
script = '''
|
||||
#!@rust
|
||||
|
||||
//! ```cargo
|
||||
//! [dependencies]
|
||||
//! wdk-build = { path = ".", version = "0.5.1" }
|
||||
//! ```
|
||||
#![allow(unused_doc_comments)]
|
||||
|
||||
let source_file = wdk_build::cargo_make::get_wdk_build_output_directory().join(format!(
|
||||
"{}.dll",
|
||||
wdk_build::cargo_make::get_current_package_name()
|
||||
));
|
||||
|
||||
let destination_file = wdk_build::cargo_make::get_wdk_build_output_directory().join(format!(
|
||||
"{}.sys",
|
||||
wdk_build::cargo_make::get_current_package_name()
|
||||
));
|
||||
|
||||
std::fs::copy(&source_file, &destination_file).expect(&format!(
|
||||
"copy of '{}' file to '{}' file should succeed",
|
||||
source_file.display(),
|
||||
destination_file.display()
|
||||
));
|
||||
'''
|
||||
|
||||
[tasks.stampinf]
|
||||
private = true
|
||||
dependencies = ["setup-wdk-config-env-vars", "copy-inx-to-output"]
|
||||
env = { "WDK_BUILD_STAMPINF_WDF_FLAGS" = { source = "${WDK_BUILD_METADATA-DRIVER_MODEL-DRIVER_TYPE}", default_value = "", mapping = { "KMDF" = "-k ${WDK_BUILD_METADATA-DRIVER_MODEL-KMDF_VERSION_MAJOR}.${WDK_BUILD_METADATA-DRIVER_MODEL-TARGET_KMDF_VERSION_MINOR}", "UMDF" = "-u ${WDK_BUILD_METADATA-DRIVER_MODEL-UMDF_VERSION_MAJOR}.${WDK_BUILD_METADATA-DRIVER_MODEL-TARGET_UMDF_VERSION_MINOR}.0" } }, "WDK_BUILD_STAMPINF_ARCH" = { source = "${CARGO_MAKE_CRATE_TARGET_TRIPLE}", default_value = "UNKNOWN", mapping = { "x86_64-pc-windows-msvc" = "amd64", "aarch64-pc-windows-msvc" = "arm64" } } }
|
||||
command = "stampinf"
|
||||
args = [
|
||||
"-f",
|
||||
"${WDK_BUILD_OUTPUT_DIRECTORY}/${CARGO_MAKE_CRATE_FS_NAME}.inf",
|
||||
"-d",
|
||||
"*",
|
||||
"-a",
|
||||
"${WDK_BUILD_STAMPINF_ARCH}",
|
||||
"-c",
|
||||
"${CARGO_MAKE_CRATE_FS_NAME}.cat",
|
||||
"-v",
|
||||
"*",
|
||||
"@@split(WDK_BUILD_STAMPINF_WDF_FLAGS, ,remove-empty)",
|
||||
]
|
||||
|
||||
[tasks.infverif]
|
||||
private = true
|
||||
dependencies = ["setup-wdk-config-env-vars", "stampinf"]
|
||||
# TODO: This should be if WDK <= GE && DRIVER_MODEL == UMDF
|
||||
env = { "WDK_BUILD_BASE_INFVERIF_FLAGS" = { source = "${WDK_BUILD_METADATA-DRIVER_MODEL-DRIVER_TYPE}", default_value = "${WDK_BUILD_BASE_INFVERIF_FLAGS} /w", mapping = { "UMDF" = "${WDK_BUILD_BASE_INFVERIF_FLAGS} /u" } } }
|
||||
command = "infverif"
|
||||
args = [
|
||||
"@@split(WDK_BUILD_BASE_INFVERIF_FLAGS, ,remove-empty)",
|
||||
"@@split(WDK_BUILD_ADDITIONAL_INFVERIF_FLAGS, ,remove-empty)",
|
||||
"${WDK_BUILD_OUTPUT_DIRECTORY}/${CARGO_MAKE_CRATE_FS_NAME}.inf",
|
||||
]
|
||||
|
||||
[tasks.copy-driver-binary-to-package]
|
||||
private = true
|
||||
dependencies = ["setup-wdk-config-env-vars", "generate-driver-binary-file"]
|
||||
env = { "WDK_BUILD_DRIVER_EXTENSION" = { source = "${WDK_BUILD_METADATA-DRIVER_MODEL-DRIVER_TYPE}", default_value = "UNKNOWN_EXTENSION", mapping = { "WDM" = "sys", "KMDF" = "sys", "UMDF" = "dll" } } }
|
||||
script_runner = "@rust"
|
||||
script_runner_args = [
|
||||
"--base-path",
|
||||
"${CARGO_MAKE_CURRENT_TASK_INITIAL_MAKEFILE_DIRECTORY}",
|
||||
]
|
||||
script = '''
|
||||
//! ```cargo
|
||||
//! [dependencies]
|
||||
//! wdk-build = { path = ".", version = "0.5.1" }
|
||||
//! ```
|
||||
#![allow(unused_doc_comments)]
|
||||
|
||||
let driver_binary_extension = std::env::var("WDK_BUILD_DRIVER_EXTENSION").expect("WDK_BUILD_DRIVER_EXTENSION should be set by cargo-make");
|
||||
wdk_build::cargo_make::copy_to_driver_package_folder(
|
||||
wdk_build::cargo_make::get_wdk_build_output_directory().join(format!(
|
||||
"{}.{driver_binary_extension}",
|
||||
wdk_build::cargo_make::get_current_package_name()
|
||||
)),
|
||||
)?
|
||||
'''
|
||||
|
||||
[tasks.copy-pdb-to-package]
|
||||
private = true
|
||||
dependencies = ["build"]
|
||||
script_runner = "@rust"
|
||||
script_runner_args = [
|
||||
"--base-path",
|
||||
"${CARGO_MAKE_CURRENT_TASK_INITIAL_MAKEFILE_DIRECTORY}",
|
||||
]
|
||||
script = '''
|
||||
//! ```cargo
|
||||
//! [dependencies]
|
||||
//! wdk-build = { path = ".", version = "0.5.1" }
|
||||
//! ```
|
||||
#![allow(unused_doc_comments)]
|
||||
|
||||
wdk_build::cargo_make::copy_to_driver_package_folder(
|
||||
wdk_build::cargo_make::get_wdk_build_output_directory().join(format!(
|
||||
"{}.pdb",
|
||||
wdk_build::cargo_make::get_current_package_name()
|
||||
)),
|
||||
)?
|
||||
'''
|
||||
|
||||
[tasks.copy-inf-to-package]
|
||||
private = true
|
||||
dependencies = ["stampinf"]
|
||||
script_runner = "@rust"
|
||||
script_runner_args = [
|
||||
"--base-path",
|
||||
"${CARGO_MAKE_CURRENT_TASK_INITIAL_MAKEFILE_DIRECTORY}",
|
||||
]
|
||||
script = '''
|
||||
//! ```cargo
|
||||
//! [dependencies]
|
||||
//! wdk-build = { path = ".", version = "0.5.1" }
|
||||
//! ```
|
||||
#![allow(unused_doc_comments)]
|
||||
|
||||
wdk_build::cargo_make::copy_to_driver_package_folder(
|
||||
wdk_build::cargo_make::get_wdk_build_output_directory().join(format!(
|
||||
"{}.inf",
|
||||
wdk_build::cargo_make::get_current_package_name()
|
||||
)),
|
||||
)?
|
||||
'''
|
||||
|
||||
[tasks.copy-map-to-package]
|
||||
private = true
|
||||
dependencies = ["build"]
|
||||
script_runner = "@rust"
|
||||
script_runner_args = [
|
||||
"--base-path",
|
||||
"${CARGO_MAKE_CURRENT_TASK_INITIAL_MAKEFILE_DIRECTORY}",
|
||||
]
|
||||
script = '''
|
||||
//! ```cargo
|
||||
//! [dependencies]
|
||||
//! wdk-build = { path = ".", version = "0.5.1" }
|
||||
//! ```
|
||||
#![allow(unused_doc_comments)]
|
||||
|
||||
wdk_build::cargo_make::copy_to_driver_package_folder(
|
||||
wdk_build::cargo_make::get_wdk_build_output_directory().join(format!(
|
||||
"deps/{}.map",
|
||||
wdk_build::cargo_make::get_current_package_name()
|
||||
)),
|
||||
)?
|
||||
'''
|
||||
|
||||
[tasks.inf2cat]
|
||||
private = true
|
||||
dependencies = ["copy-driver-binary-to-package", "copy-inf-to-package"]
|
||||
env = { "WDK_BUILD_INF2CAT_OS" = { source = "${CARGO_MAKE_CRATE_TARGET_TRIPLE}", default_value = "UNKNOWN", mapping = { "x86_64-pc-windows-msvc" = "10_x64", "aarch64-pc-windows-msvc" = "Server10_arm64" } } }
|
||||
command = "inf2cat"
|
||||
args = [
|
||||
"/driver:${WDK_BUILD_OUTPUT_DIRECTORY}/${CARGO_MAKE_CRATE_FS_NAME}_package",
|
||||
"/os:${WDK_BUILD_INF2CAT_OS}",
|
||||
"/uselocaltime",
|
||||
]
|
||||
|
||||
[tasks.generate-certificate]
|
||||
private = true
|
||||
condition_script_runner_args = [
|
||||
"--base-path",
|
||||
"${CARGO_MAKE_CURRENT_TASK_INITIAL_MAKEFILE_DIRECTORY}",
|
||||
]
|
||||
condition_script = '''
|
||||
#!@rust
|
||||
|
||||
//! ```cargo
|
||||
//! [dependencies]
|
||||
//! wdk-build = { path = ".", version = "0.5.1" }
|
||||
//! anyhow = "1"
|
||||
//! ```
|
||||
#![allow(unused_doc_comments)]
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
wdk_build::cargo_make::generate_certificate_condition_script()
|
||||
}
|
||||
'''
|
||||
command = "makecert"
|
||||
args = [
|
||||
"-r",
|
||||
"-pe",
|
||||
"-a",
|
||||
"SHA256",
|
||||
"-eku",
|
||||
"1.3.6.1.5.5.7.3.3",
|
||||
"-ss",
|
||||
"WDRTestCertStore", # FIXME: this should be a parameter
|
||||
"-n",
|
||||
"CN=WDRLocalTestCert", # FIXME: this should be a parameter
|
||||
"${WDK_BUILD_OUTPUT_DIRECTORY}/WDRLocalTestCert.cer",
|
||||
]
|
||||
|
||||
[tasks.copy-certificate-to-package]
|
||||
private = true
|
||||
dependencies = ["generate-certificate"]
|
||||
script_runner = "@rust"
|
||||
script_runner_args = [
|
||||
"--base-path",
|
||||
"${CARGO_MAKE_CURRENT_TASK_INITIAL_MAKEFILE_DIRECTORY}",
|
||||
]
|
||||
script = '''
|
||||
//! ```cargo
|
||||
//! [dependencies]
|
||||
//! wdk-build = { path = ".", version = "0.5.1" }
|
||||
//! ```
|
||||
#![allow(unused_doc_comments)]
|
||||
|
||||
wdk_build::cargo_make::copy_to_driver_package_folder(
|
||||
wdk_build::cargo_make::get_wdk_build_output_directory().join("WDRLocalTestCert.cer"),
|
||||
)?
|
||||
'''
|
||||
|
||||
[tasks.signtool-sign]
|
||||
private = true
|
||||
dependencies = ["generate-certificate"]
|
||||
command = "signtool"
|
||||
args = [
|
||||
"sign",
|
||||
"/v",
|
||||
"/s",
|
||||
"WDRTestCertStore", # FIXME: this should be a parameter
|
||||
"/n",
|
||||
"WDRLocalTestCert", # FIXME: this should be a parameter
|
||||
"/t",
|
||||
"http://timestamp.digicert.com",
|
||||
"/fd",
|
||||
"SHA256",
|
||||
"${WDK_BUILD_SIGNTOOL_SIGN_INPUT_FILE}",
|
||||
]
|
||||
|
||||
[tasks.sign-driver-binary]
|
||||
private = true
|
||||
dependencies = ["setup-wdk-config-env-vars", "copy-driver-binary-to-package"]
|
||||
env = { "WDK_BUILD_SIGNTOOL_SIGN_INPUT_FILE" = "${WDK_BUILD_OUTPUT_DIRECTORY}/${CARGO_MAKE_CRATE_FS_NAME}_package/${CARGO_MAKE_CRATE_FS_NAME}.${WDK_BUILD_DRIVER_EXTENSION}" }
|
||||
run_task = "signtool-sign"
|
||||
|
||||
[tasks.sign-cat]
|
||||
private = true
|
||||
dependencies = ["inf2cat", "sign-driver-binary"]
|
||||
env = { "WDK_BUILD_SIGNTOOL_SIGN_INPUT_FILE" = "${WDK_BUILD_OUTPUT_DIRECTORY}/${CARGO_MAKE_CRATE_FS_NAME}_package/${CARGO_MAKE_CRATE_FS_NAME}.cat" }
|
||||
run_task = "signtool-sign"
|
||||
|
||||
[tasks.signtool-verify]
|
||||
private = true
|
||||
condition = { env_true = ["WDK_BUILD_ENABLE_SIGNTOOL_VERIFY"] }
|
||||
command = "signtool"
|
||||
args = ["verify", "/v", "/pa", "${WDK_BUILD_SIGNTOOL_VERIFY_INPUT_FILE}"]
|
||||
|
||||
[tasks.verify-signature-driver-binary]
|
||||
private = true
|
||||
dependencies = ["setup-wdk-config-env-vars", "sign-driver-binary"]
|
||||
env = { "WDK_BUILD_SIGNTOOL_VERIFY_INPUT_FILE" = "${WDK_BUILD_OUTPUT_DIRECTORY}/${CARGO_MAKE_CRATE_FS_NAME}_package/${CARGO_MAKE_CRATE_FS_NAME}.${WDK_BUILD_DRIVER_EXTENSION}" }
|
||||
run_task = "signtool-verify"
|
||||
|
||||
[tasks.verify-signature-cat]
|
||||
private = true
|
||||
dependencies = ["sign-cat"]
|
||||
env = { "WDK_BUILD_SIGNTOOL_VERIFY_INPUT_FILE" = "${WDK_BUILD_OUTPUT_DIRECTORY}/${CARGO_MAKE_CRATE_FS_NAME}_package/${CARGO_MAKE_CRATE_FS_NAME}.cat" }
|
||||
run_task = "signtool-verify"
|
||||
|
||||
[tasks.package-driver]
|
||||
private = true
|
||||
dependencies = [
|
||||
"copy-driver-binary-to-package",
|
||||
"copy-pdb-to-package",
|
||||
"copy-inf-to-package",
|
||||
"copy-map-to-package",
|
||||
"copy-certificate-to-package",
|
||||
"sign-driver-binary",
|
||||
"verify-signature-driver-binary",
|
||||
"sign-cat",
|
||||
"verify-signature-cat",
|
||||
"infverif",
|
||||
]
|
||||
|
||||
[tasks.package-driver-flow]
|
||||
# Note: Dependencies are always run, regardless of the condition_script result. This allows `cargo make` in mixed driver/non-driver workspaces
|
||||
dependencies = ["build"]
|
||||
# Only run package-driver flow if the current package is marked as a driver
|
||||
plugin = "nested-cargo-workspace-in-cargo-make-emulated-workspace-support"
|
||||
condition_script_runner_args = [
|
||||
"--base-path",
|
||||
"${CARGO_MAKE_CURRENT_TASK_INITIAL_MAKEFILE_DIRECTORY}",
|
||||
]
|
||||
condition_script = '''
|
||||
#!@rust
|
||||
|
||||
//! ```cargo
|
||||
//! [dependencies]
|
||||
//! wdk-build = { path = ".", version = "0.5.1" }
|
||||
//! anyhow = "1"
|
||||
//! ```
|
||||
#![allow(unused_doc_comments)]
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
wdk_build::cargo_make::package_driver_flow_condition_script()
|
||||
}
|
||||
'''
|
||||
run_task = "package-driver"
|
||||
|
||||
[tasks.help]
|
||||
extend = "wdk-build-init"
|
||||
private = false
|
||||
workspace = false
|
||||
args = ["--help"]
|
||||
|
||||
[tasks.default]
|
||||
alias = "package-driver-flow"
|
||||
@@ -0,0 +1,48 @@
|
||||
# This file is used to extend the standard rust-driver-makefile to build official sample drivers. See examples at https://github.com/microsoft/Windows-rust-drivers-samples
|
||||
# Using this file requires extending both the standard makefile and this makefile in order, as follows:
|
||||
# extend = [ { path = "target/rust-driver-makefile.toml" }, { path = "target/rust-driver-sample-makefile.toml" } ]
|
||||
|
||||
[tasks.wdk-samples-setup]
|
||||
private = true
|
||||
install_crate = { crate_name = "rust-script", min_version = "0.30.0" }
|
||||
plugin = "rust-env-update"
|
||||
script_runner = "@rust"
|
||||
script = '''
|
||||
//! ```cargo
|
||||
//! [dependencies]
|
||||
//! wdk-build = { path = ".", version = "0.5.1" }
|
||||
//! ```
|
||||
#![allow(unused_doc_comments)]
|
||||
|
||||
let env_string = std::env::var_os(wdk_build::cargo_make::WDK_VERSION_ENV_VAR)
|
||||
.map_or_else(
|
||||
|| panic!("Couldn't read WDK build version that should have been set in init"),
|
||||
|os_env_string| os_env_string.to_string_lossy().into_owned(),
|
||||
);
|
||||
let samples_infverif_env_vars = wdk_build::cargo_make::setup_infverif_for_samples(&env_string)?;
|
||||
|
||||
wdk_build::cargo_make::forward_printed_env_vars(
|
||||
samples_infverif_env_vars,
|
||||
);
|
||||
'''
|
||||
|
||||
[tasks.infverif]
|
||||
dependencies = ["wdk-samples-setup", "stampinf"]
|
||||
condition_script_runner_args = [
|
||||
"--base-path",
|
||||
"${CARGO_MAKE_CURRENT_TASK_INITIAL_MAKEFILE_DIRECTORY}",
|
||||
]
|
||||
condition_script = '''
|
||||
#!@rust
|
||||
|
||||
//! ```cargo
|
||||
//! [dependencies]
|
||||
//! wdk-build = { path = ".", version = "0.5.1" }
|
||||
//! anyhow = "1"
|
||||
//! ```
|
||||
#![allow(unused_doc_comments)]
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
wdk_build::cargo_make::driver_sample_infverif_condition_script()
|
||||
}
|
||||
'''
|
||||
@@ -0,0 +1,273 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// License: MIT OR Apache-2.0
|
||||
|
||||
use std::{borrow::Borrow, fmt};
|
||||
|
||||
use bindgen::{
|
||||
Builder,
|
||||
callbacks::{ItemInfo, ItemKind, ParseCallbacks},
|
||||
};
|
||||
use cargo_metadata::MetadataCommand;
|
||||
use tracing::debug;
|
||||
|
||||
use crate::{Config, ConfigError, DriverConfig, find_top_level_cargo_manifest};
|
||||
|
||||
/// An extension trait that provides a way to create a [`bindgen::Builder`]
|
||||
/// configured for generating bindings to the wdk
|
||||
pub trait BuilderExt {
|
||||
/// Returns a `bindgen::Builder` with the default configuration for
|
||||
/// generation of bindings to the WDK
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Implementation may return `wdk_build::ConfigError` if it fails to create
|
||||
/// a builder
|
||||
fn wdk_default(config: impl Borrow<Config> + fmt::Debug) -> Result<Builder, ConfigError>;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
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
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Will return `wdk_build::ConfigError` if any of the resolved include or
|
||||
/// library paths do not exist
|
||||
#[tracing::instrument(level = "debug")]
|
||||
fn wdk_default(config: impl Borrow<Config> + fmt::Debug) -> Result<Self, ConfigError> {
|
||||
let config = config.borrow();
|
||||
|
||||
let mut builder = Self::default()
|
||||
.use_core() // Can't use std for kernel code
|
||||
.derive_default(true) // allows for default initializing structs
|
||||
// CStr types are safer and easier to work with when interacting with string constants
|
||||
// from C
|
||||
.generate_cstr(true)
|
||||
// Building in eWDK can pollute system search path when clang-sys tries to detect
|
||||
// c_search_paths
|
||||
.detect_include_paths(false)
|
||||
.clang_args(config.include_paths()?.map(|include_path| {
|
||||
format!(
|
||||
"--include-directory={}",
|
||||
include_path
|
||||
.to_str()
|
||||
.expect("Non Unicode paths are not supported")
|
||||
)
|
||||
}))
|
||||
.clang_args(
|
||||
config
|
||||
.preprocessor_definitions()
|
||||
.map(|(key, value)| {
|
||||
format!(
|
||||
"--define-macro={key}{}",
|
||||
value.map(|v| format!("={v}")).unwrap_or_default()
|
||||
)
|
||||
})
|
||||
.chain(Config::wdk_bindgen_compiler_flags()),
|
||||
)
|
||||
.blocklist_item("ExAllocatePoolWithTag") // Deprecated
|
||||
.blocklist_item("ExAllocatePoolWithQuotaTag") // Deprecated
|
||||
.blocklist_item("ExAllocatePoolWithTagPriority") // Deprecated
|
||||
.blocklist_item("ExAllocatePool") // Deprecated
|
||||
.blocklist_item("USBD_CalculateUsbBandwidth") // Deprecated
|
||||
.blocklist_item("USBD_CreateConfigurationRequest") // Deprecated
|
||||
.blocklist_item("USBD_Debug_LogEntry") // Deprecated
|
||||
.blocklist_item("USBD_GetUSBDIVersion") // Deprecated
|
||||
.blocklist_item("USBD_ParseConfigurationDescriptor") // Deprecated
|
||||
.blocklist_item("USBD_QueryBusTime") // Deprecated
|
||||
.blocklist_item("USBD_RegisterHcFilter") // Deprecated
|
||||
.blocklist_item("IOCTL_USB_DIAG_IGNORE_HUBS_OFF") // Deprecated/Internal-Use-Only
|
||||
.blocklist_item("IOCTL_USB_DIAG_IGNORE_HUBS_ON") // Deprecated/Internal-Use-Only
|
||||
.blocklist_item("IOCTL_USB_DIAGNOSTIC_MODE_OFF") // Deprecated/Internal-Use-Only
|
||||
.blocklist_item("IOCTL_USB_DIAGNOSTIC_MODE_ON") // Deprecated/Internal-Use-Only
|
||||
.blocklist_item("IOCTL_USB_GET_HUB_CAPABILITIES") // Deprecated/Internal-Use-Only
|
||||
.blocklist_item("IOCTL_USB_HCD_DISABLE_PORT") // Deprecated/Internal-Use-Only
|
||||
.blocklist_item("IOCTL_USB_HCD_ENABLE_PORT") // Deprecated/Internal-Use-Only
|
||||
.blocklist_item("IOCTL_USB_HCD_GET_STATS_1") // Deprecated/Internal-Use-Only
|
||||
.blocklist_item("IOCTL_USB_HCD_GET_STATS_2") // Deprecated/Internal-Use-Only
|
||||
.blocklist_item("IOCTL_USB_RESET_HUB") // Deprecated/Internal-Use-Only
|
||||
.opaque_type("_KGDTENTRY64") // No definition in WDK
|
||||
.opaque_type("_KIDTENTRY64") // No definition in WDK
|
||||
// FIXME: bitfield generated with non-1byte alignment in _MCG_CAP
|
||||
.blocklist_item(".*MCG_CAP(?:__bindgen.*)?")
|
||||
.blocklist_item(".*WHEA_XPF_MCA_SECTION")
|
||||
.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
|
||||
// https://github.com/rust-lang/rust-bindgen/issues/3177
|
||||
.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")
|
||||
.must_use_type("HRESULT")
|
||||
// Defaults enums to generate as a set of constants contained in a module (default value
|
||||
// is EnumVariation::Consts which generates enums as global constants)
|
||||
.default_enum_style(bindgen::EnumVariation::ModuleConsts)
|
||||
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
|
||||
.parse_callbacks(Box::new(WdkCallbacks::new(config)))
|
||||
.formatter(bindgen::Formatter::Prettyplease)
|
||||
.rust_target(get_rust_target()?)
|
||||
.rust_edition(get_rust_edition()?);
|
||||
|
||||
// The `_USBPM_CLIENT_CONFIG_EXTRA_INFO` struct only has members when
|
||||
// _KERNEL_MODE flag is defined. We need to mark this type as opaque to avoid
|
||||
// generating an empty struct, since they are not currently supported by
|
||||
// bindgen: https://github.com/rust-lang/rust-bindgen/issues/1683
|
||||
if let DriverConfig::Umdf(_) = config.driver_config {
|
||||
builder = builder.opaque_type("_USBPM_CLIENT_CONFIG_EXTRA_INFO");
|
||||
}
|
||||
|
||||
Ok(builder)
|
||||
}
|
||||
}
|
||||
|
||||
impl ParseCallbacks for WdkCallbacks {
|
||||
fn generated_name_override(&self, item_info: ItemInfo) -> Option<String> {
|
||||
// Override the generated name for the WDF function table symbol, since bindgen is unable to currently translate the #define automatically: https://github.com/rust-lang/rust-bindgen/issues/2544
|
||||
if let Some(wdf_function_table_symbol_name) = &self.wdf_function_table_symbol_name {
|
||||
if let ItemInfo {
|
||||
name: item_name,
|
||||
kind: ItemKind::Var,
|
||||
..
|
||||
} = item_info
|
||||
{
|
||||
if item_name == wdf_function_table_symbol_name {
|
||||
return Some("WdfFunctions".to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl WdkCallbacks {
|
||||
#[tracing::instrument(level = "trace")]
|
||||
fn new(config: &Config) -> Self {
|
||||
Self {
|
||||
wdf_function_table_symbol_name: config.compute_wdffunctions_symbol_name(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
#[tracing::instrument(level = "trace")]
|
||||
fn get_rust_target() -> Result<bindgen::RustTarget, ConfigError> {
|
||||
let nightly_feature = cfg!(feature = "nightly");
|
||||
let nightly_toolchain = rustversion::cfg!(nightly);
|
||||
|
||||
match (nightly_feature, nightly_toolchain) {
|
||||
(true, true) => Ok(bindgen::RustTarget::nightly()),
|
||||
(false, false) => get_stable_rust_target(),
|
||||
(true, false) => {
|
||||
tracing::warn!(
|
||||
"A non-nightly toolchain has been detected. Nightly bindgen features are only \
|
||||
enabled with both nightly feature enablement and nightly toolchain use. "
|
||||
);
|
||||
get_stable_rust_target()
|
||||
}
|
||||
(false, true) => {
|
||||
tracing::warn!(
|
||||
"The nightly feature for wdk-build is disabled. Nightly bindgen features are only \
|
||||
enabled with both nightly feature enablement and nightly toolchain use. "
|
||||
);
|
||||
get_stable_rust_target()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieves the stable Rust target for the current build configuration.
|
||||
// Queries the MSRV from the `CARGO_PKG_RUST_VERSION` environment variable and
|
||||
// uses it to create a `bindgen::RustTarget::stable` value.
|
||||
#[tracing::instrument(level = "trace")]
|
||||
fn get_stable_rust_target() -> Result<bindgen::RustTarget, ConfigError> {
|
||||
let package_msrv = semver::Version::parse(env!("CARGO_PKG_RUST_VERSION"))
|
||||
.map_err(|e| ConfigError::RustVersionParseError { error_source: e })?;
|
||||
|
||||
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.
|
||||
#[tracing::instrument(level = "trace")]
|
||||
fn get_rust_edition() -> Result<bindgen::RustEdition, ConfigError> {
|
||||
const WDK_BUILD_PACKAGE_NAME: &str = "wdk-build";
|
||||
// Run `cargo_metadata` in the same working directory as the top level manifest
|
||||
// in order to respect `config.toml` overrides
|
||||
let top_level_cargo_manifest_path = find_top_level_cargo_manifest();
|
||||
debug!(
|
||||
"Top level Cargo manifest path: {:?}",
|
||||
top_level_cargo_manifest_path
|
||||
);
|
||||
let cwd = top_level_cargo_manifest_path
|
||||
.parent()
|
||||
.expect("Cargo manifest should have a valid parent directory");
|
||||
let wdk_sys_cargo_metadata = MetadataCommand::new().current_dir(cwd).exec()?;
|
||||
|
||||
let wdk_sys_package_metadata = wdk_sys_cargo_metadata
|
||||
.packages
|
||||
.iter()
|
||||
.find(|package| package.name == WDK_BUILD_PACKAGE_NAME)
|
||||
.ok_or_else(|| ConfigError::WdkBuildPackageNotFoundInCargoMetadata)?;
|
||||
|
||||
let rust_edition: BindgenRustEditionWrapper = wdk_sys_package_metadata.edition.try_into()?;
|
||||
Ok(rust_edition.0)
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
+2232
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,57 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// License: MIT OR Apache-2.0
|
||||
|
||||
use serde::ser::{self};
|
||||
use thiserror::Error;
|
||||
|
||||
/// A specialized [`Result`] type for [`metadata`](crate::metadata)
|
||||
/// serialization and deserialization operations.
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
/// This type represents all possible errors that can occur when serializing
|
||||
/// or deserializing [`metadata::Wdk`](crate::metadata::Wdk).
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error {
|
||||
/// catch-all error emitted during serialization, when a more specific
|
||||
/// error type is not available. This type of error is commonly
|
||||
/// generated from [`serde`]'s `derive` feature's generated `Serialize`
|
||||
/// impls.
|
||||
#[error("custom serialization error: {message}")]
|
||||
CustomSerialization {
|
||||
/// Message describing the error
|
||||
message: String,
|
||||
},
|
||||
|
||||
/// error emitted when an empty key name is encountered during
|
||||
/// serialization. Serialization of values always requires a non-empty
|
||||
/// key name
|
||||
#[error("empty key name encountered during serialization of value: {value_being_serialized}")]
|
||||
EmptySerializationKeyName {
|
||||
/// Value being serialized
|
||||
value_being_serialized: String,
|
||||
},
|
||||
|
||||
/// error emitted when duplicate key names are found during
|
||||
/// serialization. Serializing into a
|
||||
/// [`metadata::Map`](crate::metadata::Map) requires unique key names
|
||||
#[error(
|
||||
"duplicate keys found during serialization:\nkey: {key}\nvalue 1: {value_1}\nvalue 2: \
|
||||
{value_2}"
|
||||
)]
|
||||
DuplicateSerializationKeys {
|
||||
/// Key name
|
||||
key: String,
|
||||
/// One of the conflicting values
|
||||
value_1: String,
|
||||
/// One of the conflicting values
|
||||
value_2: String,
|
||||
},
|
||||
}
|
||||
|
||||
impl ser::Error for Error {
|
||||
fn custom<T: std::fmt::Display>(msg: T) -> Self {
|
||||
Self::CustomSerialization {
|
||||
message: msg.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// License: MIT OR Apache-2.0
|
||||
|
||||
use std::{
|
||||
collections::{BTreeMap, HashMap, btree_map, hash_map},
|
||||
hash::{BuildHasher, Hash},
|
||||
};
|
||||
|
||||
/// Trait for map-like type that is returned by
|
||||
/// [`metadata::to_map`](crate::metadata::to_map)
|
||||
/// and [`metadata::to_map_with_prefix`](crate::metadata::to_map_with_prefix).
|
||||
pub trait Map<K, V>: Default {
|
||||
/// Creates a new, empty map
|
||||
#[must_use]
|
||||
fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Inserts a new key-value pair into the map, or calls a function/closure
|
||||
/// if the key already exists.
|
||||
///
|
||||
/// The function/closure is called with the existing key, the existing
|
||||
/// value, and the new value it tried to insert. The closure can decide
|
||||
/// whether the function will return an `Err` or if it will still return a
|
||||
/// `Ok` despite not inserting the value.
|
||||
///
|
||||
/// # Errors
|
||||
/// This function returns an error if the key already exists and `f` returns
|
||||
/// an `Err` value
|
||||
fn insert_or_else<F, E>(&mut self, key: K, value: V, f: F) -> Result<(), E>
|
||||
where
|
||||
F: FnMut(&K, &V, V) -> Result<(), E>;
|
||||
}
|
||||
|
||||
impl<K: Eq + Hash, V, S: BuildHasher + Default> Map<K, V> for HashMap<K, V, S> {
|
||||
fn insert_or_else<F, E>(&mut self, key: K, value: V, mut f: F) -> Result<(), E>
|
||||
where
|
||||
F: FnMut(&K, &V, V) -> Result<(), E>,
|
||||
{
|
||||
match self.entry(key) {
|
||||
hash_map::Entry::Occupied(entry) => f(entry.key(), entry.get(), value),
|
||||
hash_map::Entry::Vacant(entry) => {
|
||||
entry.insert(value);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Ord, V> Map<K, V> for BTreeMap<K, V> {
|
||||
fn insert_or_else<F, E>(&mut self, key: K, value: V, mut f: F) -> Result<(), E>
|
||||
where
|
||||
F: FnMut(&K, &V, V) -> Result<(), E>,
|
||||
{
|
||||
match self.entry(key) {
|
||||
btree_map::Entry::Occupied(entry) => f(entry.key(), entry.get(), value),
|
||||
btree_map::Entry::Vacant(entry) => {
|
||||
entry.insert(value);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// License: MIT OR Apache-2.0
|
||||
|
||||
//! Parsing and serializing metadata about WDK projects
|
||||
//!
|
||||
//! This module provides a [`Wdk`] struct that represents the cargo metadata
|
||||
//! specified in the `metadata.wdk` section any `Cargo.toml`. This corresponds
|
||||
//! with the settings in the `Driver Settings` property pages for WDK projects
|
||||
//! in Visual Studio. This module also also provides [`serde`]-compatible
|
||||
//! serialization and deserialization for the metadata.
|
||||
|
||||
pub use error::{Error, Result};
|
||||
pub use map::Map;
|
||||
pub use ser::{Serializer, to_map, to_map_with_prefix};
|
||||
|
||||
pub(crate) mod ser;
|
||||
|
||||
mod error;
|
||||
mod map;
|
||||
|
||||
use std::collections::HashSet;
|
||||
|
||||
use camino::Utf8PathBuf;
|
||||
use cargo_metadata::Metadata;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::DriverConfig;
|
||||
|
||||
/// Metadata specified in the `metadata.wdk` section of the `Cargo.toml`
|
||||
/// of a crate that depends on the WDK, or in a cargo workspace.
|
||||
///
|
||||
/// This corresponds with the settings in the `Driver Settings` property pages
|
||||
/// for WDK projects in Visual Studio
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||||
#[serde(
|
||||
deny_unknown_fields,
|
||||
rename_all(serialize = "SCREAMING_SNAKE_CASE", deserialize = "kebab-case")
|
||||
)]
|
||||
pub struct Wdk {
|
||||
/// Metadata corresponding to the `Driver Model` property page in the WDK
|
||||
pub driver_model: DriverConfig,
|
||||
}
|
||||
|
||||
/// Errors that could result from trying to construct a
|
||||
/// [`metadata::Wdk`](crate::metadata::Wdk) from information parsed by `cargo
|
||||
/// metadata`
|
||||
#[derive(Debug, Error)]
|
||||
pub enum TryFromCargoMetadataError {
|
||||
/// Error returned when no WDK configuration metadata is detected in the
|
||||
/// dependency graph
|
||||
#[error(
|
||||
"no WDK configuration metadata is detected in the dependency graph. This could happen \
|
||||
when building WDR itself, or building library crates that depend on the WDK but defer \
|
||||
WDK configuration to their consumers"
|
||||
)]
|
||||
NoWdkConfigurationsDetected,
|
||||
|
||||
/// Error returned when multiple configurations of the WDK are detected
|
||||
/// across the dependency graph
|
||||
#[error(
|
||||
"multiple configurations of the WDK are detected across the dependency graph, but only \
|
||||
one configuration is allowed: {wdk_metadata_configurations:#?}"
|
||||
)]
|
||||
MultipleWdkConfigurationsDetected {
|
||||
/// [`HashSet`] of unique [`metadata::Wdk`](crate::metadata::Wdk)
|
||||
/// derived from detected WDK metadata
|
||||
wdk_metadata_configurations: HashSet<Wdk>,
|
||||
},
|
||||
|
||||
/// Error returned when [`crate::metadata::Wdk`] fails to be deserialized
|
||||
/// from [`cargo_metadata::Metadata`] output
|
||||
#[error("failed to deserialize metadata::Wdk from {metadata_source}")]
|
||||
WdkMetadataDeserialization {
|
||||
/// `String` that describes what part of
|
||||
/// `cargo_metadata::Metadata` was used as the source for
|
||||
/// deserialization
|
||||
metadata_source: String,
|
||||
/// [`serde_json::Error`] that caused the deserialization to fail
|
||||
#[source]
|
||||
error_source: serde_json::Error,
|
||||
},
|
||||
}
|
||||
|
||||
impl TryFrom<&Metadata> for Wdk {
|
||||
type Error = TryFromCargoMetadataError;
|
||||
|
||||
fn try_from(metadata: &Metadata) -> std::result::Result<Self, Self::Error> {
|
||||
let wdk_metadata_configurations = {
|
||||
// Parse WDK metadata from workspace and all packages
|
||||
let mut configs = parse_packages_wdk_metadata(&metadata.packages)?;
|
||||
if let Some(workspace_metadata) =
|
||||
parse_workspace_wdk_metadata(&metadata.workspace_metadata)?
|
||||
{
|
||||
configs.insert(workspace_metadata);
|
||||
}
|
||||
configs
|
||||
};
|
||||
|
||||
// Ensure that only one configuration of WDK is allowed per dependency graph
|
||||
match wdk_metadata_configurations.len() {
|
||||
1 => Ok(wdk_metadata_configurations.into_iter().next().expect(
|
||||
"wdk_metadata_configurations should have exactly one element because of the \
|
||||
.len() check above",
|
||||
)),
|
||||
|
||||
0 => Err(TryFromCargoMetadataError::NoWdkConfigurationsDetected),
|
||||
|
||||
_ => Err(
|
||||
TryFromCargoMetadataError::MultipleWdkConfigurationsDetected {
|
||||
wdk_metadata_configurations,
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_packages_wdk_metadata(
|
||||
packages: &[cargo_metadata::Package],
|
||||
) -> std::result::Result<HashSet<Wdk>, TryFromCargoMetadataError> {
|
||||
let wdk_metadata_configurations = packages
|
||||
.iter()
|
||||
.filter_map(|package| match &package.metadata["wdk"] {
|
||||
serde_json::Value::Null => None,
|
||||
// When wdk section is empty, treat it as if it wasn't there. This is to allow for using
|
||||
// empty wdk metadata sections to mark the package as a driver (ex. for detection in
|
||||
// `package_driver_flow_condition_script`)
|
||||
serde_json::Value::Object(map) if map.is_empty() => None,
|
||||
wdk_metadata => Some(Wdk::deserialize(wdk_metadata).map_err(|err| {
|
||||
TryFromCargoMetadataError::WdkMetadataDeserialization {
|
||||
metadata_source: format!(
|
||||
"{} for {} package",
|
||||
stringify!(package.metadata["wdk"]),
|
||||
package.name
|
||||
),
|
||||
error_source: err,
|
||||
}
|
||||
})),
|
||||
})
|
||||
.collect::<std::result::Result<HashSet<_>, _>>()?;
|
||||
Ok(wdk_metadata_configurations)
|
||||
}
|
||||
|
||||
fn parse_workspace_wdk_metadata(
|
||||
workspace_metadata: &serde_json::Value,
|
||||
) -> std::result::Result<Option<Wdk>, TryFromCargoMetadataError> {
|
||||
Ok(match &workspace_metadata["wdk"] {
|
||||
serde_json::Value::Null => None,
|
||||
wdk_metadata => Some(Wdk::deserialize(wdk_metadata).map_err(|err| {
|
||||
TryFromCargoMetadataError::WdkMetadataDeserialization {
|
||||
metadata_source: stringify!(workspace_metadata["wdk"]).to_string(),
|
||||
error_source: err,
|
||||
}
|
||||
})?),
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn iter_manifest_paths(metadata: Metadata) -> impl IntoIterator<Item = Utf8PathBuf> {
|
||||
let mut cargo_manifest_paths = HashSet::new();
|
||||
|
||||
// Add all package manifest paths
|
||||
for package in metadata.packages {
|
||||
cargo_manifest_paths.insert(package.manifest_path);
|
||||
}
|
||||
|
||||
// Add workspace manifest path
|
||||
let workspace_manifest_path: Utf8PathBuf = {
|
||||
let mut path = metadata.workspace_root;
|
||||
path.push("Cargo.toml");
|
||||
path
|
||||
};
|
||||
cargo_manifest_paths.insert(workspace_manifest_path);
|
||||
|
||||
cargo_manifest_paths
|
||||
}
|
||||
@@ -0,0 +1,746 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// License: MIT OR Apache-2.0
|
||||
|
||||
use serde::{
|
||||
Serialize,
|
||||
ser::{self, Impossible},
|
||||
};
|
||||
|
||||
use super::{
|
||||
error::{Error, Result},
|
||||
map::Map,
|
||||
};
|
||||
|
||||
/// delimiter used to separate the names of the different nodes encoded into a
|
||||
/// key name. Since `-` is not valid in Rust identifiers, it is used
|
||||
/// as a separator between different node names.
|
||||
pub const KEY_NAME_SEPARATOR: char = '-';
|
||||
|
||||
/// Serialize a value into a [`Map`] where the keys represent a
|
||||
/// `KEY_NAME_SEPARATOR`-separated list of field names.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error if the type being serialized:
|
||||
/// * results in duplicate key names
|
||||
/// * results in an empty key name
|
||||
/// * otherwise fails to be parsed and correctly serialized into a [`Map`]
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// use std::collections::BTreeMap;
|
||||
///
|
||||
/// use wdk_build::{
|
||||
/// DriverConfig,
|
||||
/// KmdfConfig,
|
||||
/// metadata::{self, to_map},
|
||||
/// };
|
||||
///
|
||||
/// let wdk_metadata = metadata::Wdk {
|
||||
/// driver_model: DriverConfig::Kmdf(KmdfConfig {
|
||||
/// kmdf_version_major: 1,
|
||||
/// target_kmdf_version_minor: 23,
|
||||
/// minimum_kmdf_version_minor: None,
|
||||
/// }),
|
||||
/// };
|
||||
///
|
||||
/// let output = to_map::<BTreeMap<_, _>>(&wdk_metadata).unwrap();
|
||||
///
|
||||
/// assert_eq!(output["DRIVER_MODEL-DRIVER_TYPE"], "KMDF");
|
||||
/// assert_eq!(output["DRIVER_MODEL-KMDF_VERSION_MAJOR"], "1");
|
||||
/// assert_eq!(output["DRIVER_MODEL-TARGET_KMDF_VERSION_MINOR"], "23");
|
||||
///
|
||||
/// // `None` values are not serialized
|
||||
/// assert_eq!(output.get("DRIVER_MODEL-MINIMUM_KMDF_VERSION_MINOR"), None);
|
||||
/// ```
|
||||
pub fn to_map<M>(value: &impl Serialize) -> Result<M>
|
||||
where
|
||||
M: Map<String, String>,
|
||||
{
|
||||
let mut serialization_buffer: Vec<(String, String)> = Vec::new();
|
||||
value.serialize(&mut Serializer::new(&mut serialization_buffer))?;
|
||||
convert_serialized_output_to_map(serialization_buffer)
|
||||
}
|
||||
|
||||
/// Serialize a value into a [`Map`] where the keys represent a
|
||||
/// `KEY_NAME_SEPARATOR`-separated list of field names prepended with a
|
||||
/// prefix.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error if the type being serialized:
|
||||
/// * results in duplicate key names
|
||||
/// * results in an empty key name
|
||||
/// * otherwise fails to be parsed and correctly serialized into a [`Map`]
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// use std::collections::BTreeMap;
|
||||
///
|
||||
/// use wdk_build::{
|
||||
/// DriverConfig,
|
||||
/// KmdfConfig,
|
||||
/// metadata::{self, to_map_with_prefix},
|
||||
/// };
|
||||
///
|
||||
/// let wdk_metadata = metadata::Wdk {
|
||||
/// driver_model: DriverConfig::Kmdf(KmdfConfig {
|
||||
/// kmdf_version_major: 1,
|
||||
/// target_kmdf_version_minor: 33,
|
||||
/// minimum_kmdf_version_minor: Some(31),
|
||||
/// }),
|
||||
/// };
|
||||
///
|
||||
/// let output = to_map_with_prefix::<BTreeMap<_, _>>("WDK_BUILD_METADATA", &wdk_metadata).unwrap();
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// output["WDK_BUILD_METADATA-DRIVER_MODEL-DRIVER_TYPE"],
|
||||
/// "KMDF"
|
||||
/// );
|
||||
/// assert_eq!(
|
||||
/// output["WDK_BUILD_METADATA-DRIVER_MODEL-KMDF_VERSION_MAJOR"],
|
||||
/// "1"
|
||||
/// );
|
||||
/// assert_eq!(
|
||||
/// output["WDK_BUILD_METADATA-DRIVER_MODEL-TARGET_KMDF_VERSION_MINOR"],
|
||||
/// "33"
|
||||
/// );
|
||||
/// assert_eq!(
|
||||
/// output["WDK_BUILD_METADATA-DRIVER_MODEL-MINIMUM_KMDF_VERSION_MINOR"],
|
||||
/// "31"
|
||||
/// );
|
||||
/// ```
|
||||
pub fn to_map_with_prefix<M>(prefix: impl Into<String>, value: &impl Serialize) -> Result<M>
|
||||
where
|
||||
M: Map<String, String>,
|
||||
{
|
||||
let mut serialization_buffer: Vec<(String, String)> = Vec::new();
|
||||
value.serialize(&mut Serializer::with_prefix(
|
||||
prefix.into(),
|
||||
&mut serialization_buffer,
|
||||
))?;
|
||||
convert_serialized_output_to_map(serialization_buffer)
|
||||
}
|
||||
|
||||
fn convert_serialized_output_to_map<M>(serialization_buffer: Vec<(String, String)>) -> Result<M>
|
||||
where
|
||||
M: Map<String, String>,
|
||||
{
|
||||
let mut output_map = M::new();
|
||||
for (key, value) in serialization_buffer {
|
||||
output_map.insert_or_else(key, value, |key, existing_value, new_value| {
|
||||
Err(Error::DuplicateSerializationKeys {
|
||||
key: key.clone(),
|
||||
value_1: existing_value.clone(),
|
||||
value_2: new_value,
|
||||
})
|
||||
})?;
|
||||
}
|
||||
|
||||
Ok(output_map)
|
||||
}
|
||||
|
||||
/// [`serde`] serializer that serializes values into a [`Vec`] of key-value
|
||||
/// pairs.
|
||||
///
|
||||
/// This serializer is useful when you want to have more granular control of the
|
||||
/// output of the serializer. Most usecases should already be covered by the
|
||||
/// [`to_map`] and [`to_map_with_prefix`] functions.
|
||||
pub struct Serializer<'a> {
|
||||
root_key_name: Option<String>,
|
||||
dst: &'a mut Vec<(String, String)>,
|
||||
}
|
||||
|
||||
impl<'a> ser::Serializer for &'a mut Serializer<'a> {
|
||||
type Error = Error;
|
||||
type Ok = ();
|
||||
type SerializeMap = Impossible<Self::Ok, Self::Error>;
|
||||
type SerializeSeq = Impossible<Self::Ok, Self::Error>;
|
||||
type SerializeStruct = Self;
|
||||
type SerializeStructVariant = Impossible<Self::Ok, Self::Error>;
|
||||
type SerializeTuple = Impossible<Self::Ok, Self::Error>;
|
||||
type SerializeTupleStruct = Impossible<Self::Ok, Self::Error>;
|
||||
type SerializeTupleVariant = Impossible<Self::Ok, Self::Error>;
|
||||
|
||||
unsupported_serde_serialize_method! {
|
||||
// simple types
|
||||
bytes newtype_struct newtype_variant unit_struct unit_variant
|
||||
// complex types (returns SerializeXYZ types)
|
||||
map seq struct_variant tuple tuple_struct tuple_variant
|
||||
}
|
||||
|
||||
fn serialize_str(self, value: &str) -> Result<Self::Ok> {
|
||||
self.dst.push((
|
||||
self.root_key_name
|
||||
.clone()
|
||||
.ok_or_else(|| Error::EmptySerializationKeyName {
|
||||
value_being_serialized: value.to_string(),
|
||||
})?,
|
||||
value.to_string(),
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_bool(self, value: bool) -> Result<Self::Ok> {
|
||||
self.dst.push((
|
||||
self.root_key_name
|
||||
.clone()
|
||||
.ok_or_else(|| Error::EmptySerializationKeyName {
|
||||
value_being_serialized: value.to_string(),
|
||||
})?,
|
||||
value.to_string(),
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_char(self, value: char) -> Result<Self::Ok> {
|
||||
self.dst.push((
|
||||
self.root_key_name
|
||||
.clone()
|
||||
.ok_or_else(|| Error::EmptySerializationKeyName {
|
||||
value_being_serialized: value.to_string(),
|
||||
})?,
|
||||
value.to_string(),
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_i8(self, value: i8) -> Result<Self::Ok> {
|
||||
self.dst.push((
|
||||
self.root_key_name
|
||||
.clone()
|
||||
.ok_or_else(|| Error::EmptySerializationKeyName {
|
||||
value_being_serialized: value.to_string(),
|
||||
})?,
|
||||
value.to_string(),
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_i16(self, value: i16) -> Result<Self::Ok> {
|
||||
self.dst.push((
|
||||
self.root_key_name
|
||||
.clone()
|
||||
.ok_or_else(|| Error::EmptySerializationKeyName {
|
||||
value_being_serialized: value.to_string(),
|
||||
})?,
|
||||
value.to_string(),
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_i32(self, value: i32) -> Result<Self::Ok> {
|
||||
self.dst.push((
|
||||
self.root_key_name
|
||||
.clone()
|
||||
.ok_or_else(|| Error::EmptySerializationKeyName {
|
||||
value_being_serialized: value.to_string(),
|
||||
})?,
|
||||
value.to_string(),
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_i64(self, value: i64) -> Result<Self::Ok> {
|
||||
self.dst.push((
|
||||
self.root_key_name
|
||||
.clone()
|
||||
.ok_or_else(|| Error::EmptySerializationKeyName {
|
||||
value_being_serialized: value.to_string(),
|
||||
})?,
|
||||
value.to_string(),
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_f32(self, value: f32) -> Result<Self::Ok> {
|
||||
self.dst.push((
|
||||
self.root_key_name
|
||||
.clone()
|
||||
.ok_or_else(|| Error::EmptySerializationKeyName {
|
||||
value_being_serialized: value.to_string(),
|
||||
})?,
|
||||
value.to_string(),
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_f64(self, value: f64) -> Result<Self::Ok> {
|
||||
self.dst.push((
|
||||
self.root_key_name
|
||||
.clone()
|
||||
.ok_or_else(|| Error::EmptySerializationKeyName {
|
||||
value_being_serialized: value.to_string(),
|
||||
})?,
|
||||
value.to_string(),
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_none(self) -> Result<Self::Ok> {
|
||||
self.serialize_unit()
|
||||
}
|
||||
|
||||
fn serialize_some<T>(self, value: &T) -> Result<Self::Ok>
|
||||
where
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
value.serialize(self)
|
||||
}
|
||||
|
||||
fn serialize_unit(self) -> Result<Self::Ok> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_u8(self, value: u8) -> Result<Self::Ok> {
|
||||
self.dst.push((
|
||||
self.root_key_name
|
||||
.clone()
|
||||
.ok_or_else(|| Error::EmptySerializationKeyName {
|
||||
value_being_serialized: value.to_string(),
|
||||
})?,
|
||||
value.to_string(),
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_u16(self, value: u16) -> Result<Self::Ok> {
|
||||
self.dst.push((
|
||||
self.root_key_name
|
||||
.clone()
|
||||
.ok_or_else(|| Error::EmptySerializationKeyName {
|
||||
value_being_serialized: value.to_string(),
|
||||
})?,
|
||||
value.to_string(),
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_u32(self, value: u32) -> Result<Self::Ok> {
|
||||
self.dst.push((
|
||||
self.root_key_name
|
||||
.clone()
|
||||
.ok_or_else(|| Error::EmptySerializationKeyName {
|
||||
value_being_serialized: value.to_string(),
|
||||
})?,
|
||||
value.to_string(),
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_u64(self, value: u64) -> Result<Self::Ok> {
|
||||
self.dst.push((
|
||||
self.root_key_name
|
||||
.clone()
|
||||
.ok_or_else(|| Error::EmptySerializationKeyName {
|
||||
value_being_serialized: value.to_string(),
|
||||
})?,
|
||||
value.to_string(),
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_struct(self, _name: &'static str, _len: usize) -> Result<Self::SerializeStruct> {
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ser::SerializeStruct for &'a mut Serializer<'a> {
|
||||
type Error = Error;
|
||||
type Ok = ();
|
||||
|
||||
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<Self::Ok>
|
||||
where
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
value.serialize(&mut Serializer::with_prefix(
|
||||
self.root_key_name.as_ref().map_or_else(
|
||||
|| key.to_string(),
|
||||
|root_key_name| format!("{root_key_name}{KEY_NAME_SEPARATOR}{key}"),
|
||||
),
|
||||
self.dst,
|
||||
))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Self::Ok> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Serializer<'a> {
|
||||
/// Create a new instance of the `Serializer` struct
|
||||
pub const fn new(dst: &'a mut Vec<(String, String)>) -> Self {
|
||||
Self {
|
||||
root_key_name: None,
|
||||
dst,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new instance of the `Serializer` struct with a prefix used as
|
||||
/// the root for all keys
|
||||
pub const fn with_prefix(prefix: String, dst: &'a mut Vec<(String, String)>) -> Self {
|
||||
Self {
|
||||
root_key_name: Some(prefix),
|
||||
dst,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
/// Helper macro when implementing the `Serializer` part of a new data
|
||||
/// format for Serde.
|
||||
///
|
||||
/// Generates [`serde::ser::Serializer`] trait methods for serde data model
|
||||
/// types that aren't supported by this serializer. This generates a
|
||||
/// method that calls [`unimplemented!`].
|
||||
macro_rules! unsupported_serde_serialize_method {
|
||||
($($method_type:ident)*) => {
|
||||
$(unsupported_serde_serialize_method_helper! {$method_type})*
|
||||
};
|
||||
}
|
||||
#[doc(hidden)]
|
||||
pub(crate) use unsupported_serde_serialize_method;
|
||||
|
||||
#[doc(hidden)]
|
||||
macro_rules! unsupported_serde_serialize_method_helper {
|
||||
// methods for simple types (returns Ok)
|
||||
(bytes) => {
|
||||
unsupported_serde_serialize_method_definition! {
|
||||
serialize_bytes(_v: &[u8]) -> std::result::Result<
|
||||
<Self as serde::ser::Serializer>::Ok,
|
||||
<Self as serde::ser::Serializer>::Error,
|
||||
>
|
||||
}
|
||||
};
|
||||
(newtype_struct) => {
|
||||
unsupported_serde_serialize_method_definition! {
|
||||
serialize_newtype_struct<T>(_name: &'static str, _value: &T) -> std::result::Result<
|
||||
<Self as serde::ser::Serializer>::Ok,
|
||||
<Self as serde::ser::Serializer>::Error,
|
||||
>
|
||||
}
|
||||
};
|
||||
(newtype_variant) => {
|
||||
unsupported_serde_serialize_method_definition! {
|
||||
serialize_newtype_variant<T>(_name: &'static str, _variant_index: u32, _variant: &'static str, _value: &T) -> std::result::Result<
|
||||
<Self as serde::ser::Serializer>::Ok,
|
||||
<Self as serde::ser::Serializer>::Error,
|
||||
>
|
||||
}
|
||||
};
|
||||
(none) => {
|
||||
unsupported_serde_serialize_method_definition! {
|
||||
serialize_none() -> std::result::Result<
|
||||
<Self as serde::ser::Serializer>::Ok,
|
||||
<Self as serde::ser::Serializer>::Error,
|
||||
>
|
||||
}
|
||||
};
|
||||
(some) => {
|
||||
unsupported_serde_serialize_method_definition! {
|
||||
serialize_some<T>(_value: &T) -> std::result::Result<
|
||||
<Self as serde::ser::Serializer>::Ok,
|
||||
<Self as serde::ser::Serializer>::Error,
|
||||
>
|
||||
}
|
||||
};
|
||||
(str) => {
|
||||
unsupported_serde_serialize_method_definition! {
|
||||
serialize_str(_v: &str) -> std::result::Result<
|
||||
<Self as serde::ser::Serializer>::Ok,
|
||||
<Self as serde::ser::Serializer>::Error,
|
||||
>
|
||||
}
|
||||
};
|
||||
(unit) => {
|
||||
unsupported_serde_serialize_method_definition! {
|
||||
serialize_unit() -> std::result::Result<
|
||||
<Self as serde::ser::Serializer>::Ok,
|
||||
<Self as serde::ser::Serializer>::Error,
|
||||
>
|
||||
}
|
||||
};
|
||||
(unit_struct) => {
|
||||
unsupported_serde_serialize_method_definition! {
|
||||
serialize_unit_struct(_name: &'static str) -> std::result::Result<
|
||||
<Self as serde::ser::Serializer>::Ok,
|
||||
<Self as serde::ser::Serializer>::Error,
|
||||
>
|
||||
}
|
||||
};
|
||||
(unit_variant) => {
|
||||
unsupported_serde_serialize_method_definition! {
|
||||
serialize_unit_variant(_name: &'static str, _variant_index: u32, _variant: &'static str) -> std::result::Result<
|
||||
<Self as serde::ser::Serializer>::Ok,
|
||||
<Self as serde::ser::Serializer>::Error,
|
||||
>
|
||||
}
|
||||
};
|
||||
// methods for complex types (returns SerializeXYZ types)
|
||||
(map) => {
|
||||
unsupported_serde_serialize_method_definition! {
|
||||
serialize_map(_len: Option<usize>) -> std::result::Result<
|
||||
<Self as serde::ser::Serializer>::SerializeMap,
|
||||
<Self as serde::ser::Serializer>::Error,
|
||||
>
|
||||
}
|
||||
};
|
||||
(struct) => {
|
||||
unsupported_serde_serialize_method_definition! {
|
||||
serialize_struct(_name: &'static str, _len: usize) -> std::result::Result<
|
||||
<Self as serde::ser::Serializer>::SerializeStruct,
|
||||
<Self as serde::ser::Serializer>::Error,
|
||||
>
|
||||
}
|
||||
};
|
||||
(struct_variant) => {
|
||||
unsupported_serde_serialize_method_definition! {
|
||||
serialize_struct_variant(_name: &'static str, _variant_index: u32, _variant: &'static str, _len: usize) -> std::result::Result<
|
||||
<Self as serde::ser::Serializer>::SerializeStructVariant,
|
||||
<Self as serde::ser::Serializer>::Error,
|
||||
>
|
||||
}
|
||||
};
|
||||
(seq) => {
|
||||
unsupported_serde_serialize_method_definition! {
|
||||
serialize_seq(_len: Option<usize>) -> std::result::Result<
|
||||
<Self as serde::ser::Serializer>::SerializeSeq,
|
||||
<Self as serde::ser::Serializer>::Error,
|
||||
>
|
||||
}
|
||||
};
|
||||
(tuple) => {
|
||||
unsupported_serde_serialize_method_definition! {
|
||||
serialize_tuple(_len: usize) -> std::result::Result<
|
||||
<Self as serde::ser::Serializer>::SerializeTuple,
|
||||
<Self as serde::ser::Serializer>::Error,
|
||||
>
|
||||
}
|
||||
};
|
||||
(tuple_struct) => {
|
||||
unsupported_serde_serialize_method_definition! {
|
||||
serialize_tuple_struct(_name: &'static str, _len: usize) -> std::result::Result<
|
||||
<Self as serde::ser::Serializer>::SerializeTupleStruct,
|
||||
<Self as serde::ser::Serializer>::Error,
|
||||
>
|
||||
}
|
||||
};
|
||||
(tuple_variant) => {
|
||||
unsupported_serde_serialize_method_definition! {
|
||||
serialize_tuple_variant(_name: &'static str, _variant_index: u32, _variant: &'static str, _len: usize) -> std::result::Result<
|
||||
<Self as serde::ser::Serializer>::SerializeTupleVariant,
|
||||
<Self as serde::ser::Serializer>::Error,
|
||||
>
|
||||
}
|
||||
};
|
||||
// every other method has no extra arguments and is for simple types
|
||||
($method_type:ident) => {
|
||||
paste::paste! {
|
||||
unsupported_serde_serialize_method_definition! {
|
||||
[<serialize_ $method_type>](_v: $method_type) -> std::result::Result<
|
||||
<Self as serde::ser::Serializer>::Ok,
|
||||
<Self as serde::ser::Serializer>::Error,
|
||||
>
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
#[doc(hidden)]
|
||||
pub(crate) use unsupported_serde_serialize_method_helper;
|
||||
|
||||
#[doc(hidden)]
|
||||
macro_rules! unsupported_serde_serialize_method_definition {
|
||||
// methods with generic argument
|
||||
($func:ident <$generic_arg:ident> ($($arg:ident : $ty:ty),*) -> std::result::Result<$ok:ty, $err:ty$(,)?>) => {
|
||||
#[inline]
|
||||
fn $func <$generic_arg> (self, $($arg: $ty,)*) -> std::result::Result<$ok, $err>
|
||||
where
|
||||
$generic_arg: ?Sized + Serialize {
|
||||
unimplemented!(
|
||||
"{} is not implemented for {} since it is currently not needed to serialize the metadata::Wdk struct",
|
||||
stringify!($func),
|
||||
std::any::type_name::<Self>(),
|
||||
)
|
||||
}
|
||||
};
|
||||
// methods without generic argument
|
||||
($func:ident ($($arg:ident : $ty:ty),*) -> std::result::Result<$ok:ty, $err:ty$(,)?>) => {
|
||||
#[inline]
|
||||
fn $func (self, $($arg: $ty,)*) -> std::result::Result<$ok, $err> {
|
||||
unimplemented!(
|
||||
"{} is not implemented for {} since it is currently not needed to serialize the metadata::Wdk struct",
|
||||
stringify!($func),
|
||||
std::any::type_name::<Self>(),
|
||||
)
|
||||
}
|
||||
};
|
||||
}
|
||||
#[doc(hidden)]
|
||||
pub(crate) use unsupported_serde_serialize_method_definition;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::{
|
||||
collections::{BTreeMap, HashMap},
|
||||
vec,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
use crate::{DriverConfig, KmdfConfig, UmdfConfig, metadata};
|
||||
|
||||
#[test]
|
||||
fn test_kmdf() {
|
||||
let wdk_metadata = metadata::Wdk {
|
||||
driver_model: DriverConfig::Kmdf(KmdfConfig {
|
||||
kmdf_version_major: 1,
|
||||
target_kmdf_version_minor: 23,
|
||||
minimum_kmdf_version_minor: Some(21),
|
||||
}),
|
||||
};
|
||||
|
||||
let output = to_map::<BTreeMap<_, _>>(&wdk_metadata).unwrap();
|
||||
|
||||
assert_eq!(output["DRIVER_MODEL-DRIVER_TYPE"], "KMDF");
|
||||
assert_eq!(output["DRIVER_MODEL-KMDF_VERSION_MAJOR"], "1");
|
||||
assert_eq!(output["DRIVER_MODEL-TARGET_KMDF_VERSION_MINOR"], "23");
|
||||
assert_eq!(output["DRIVER_MODEL-MINIMUM_KMDF_VERSION_MINOR"], "21");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_kmdf_no_minimum() {
|
||||
let wdk_metadata = metadata::Wdk {
|
||||
driver_model: DriverConfig::Kmdf(KmdfConfig {
|
||||
kmdf_version_major: 1,
|
||||
target_kmdf_version_minor: 23,
|
||||
minimum_kmdf_version_minor: None,
|
||||
}),
|
||||
};
|
||||
|
||||
let output = to_map::<BTreeMap<_, _>>(&wdk_metadata).unwrap();
|
||||
|
||||
assert_eq!(output["DRIVER_MODEL-DRIVER_TYPE"], "KMDF");
|
||||
assert_eq!(output["DRIVER_MODEL-KMDF_VERSION_MAJOR"], "1");
|
||||
assert_eq!(output["DRIVER_MODEL-TARGET_KMDF_VERSION_MINOR"], "23");
|
||||
|
||||
// `None` values are not serialized
|
||||
assert_eq!(output.get("DRIVER_MODEL-MINIMUM_KMDF_VERSION_MINOR"), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_kmdf_with_prefix() {
|
||||
let wdk_metadata = metadata::Wdk {
|
||||
driver_model: DriverConfig::Kmdf(KmdfConfig {
|
||||
kmdf_version_major: 1,
|
||||
target_kmdf_version_minor: 33,
|
||||
minimum_kmdf_version_minor: Some(31),
|
||||
}),
|
||||
};
|
||||
|
||||
let output =
|
||||
to_map_with_prefix::<BTreeMap<_, _>>("WDK_BUILD_METADATA", &wdk_metadata).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
output["WDK_BUILD_METADATA-DRIVER_MODEL-DRIVER_TYPE"],
|
||||
"KMDF"
|
||||
);
|
||||
assert_eq!(
|
||||
output["WDK_BUILD_METADATA-DRIVER_MODEL-KMDF_VERSION_MAJOR"],
|
||||
"1"
|
||||
);
|
||||
assert_eq!(
|
||||
output["WDK_BUILD_METADATA-DRIVER_MODEL-TARGET_KMDF_VERSION_MINOR"],
|
||||
"33"
|
||||
);
|
||||
assert_eq!(
|
||||
output["WDK_BUILD_METADATA-DRIVER_MODEL-MINIMUM_KMDF_VERSION_MINOR"],
|
||||
"31"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_kmdf_with_hashmap() {
|
||||
let wdk_metadata = metadata::Wdk {
|
||||
driver_model: DriverConfig::Kmdf(KmdfConfig {
|
||||
kmdf_version_major: 1,
|
||||
target_kmdf_version_minor: 33,
|
||||
minimum_kmdf_version_minor: Some(31),
|
||||
}),
|
||||
};
|
||||
|
||||
let output = to_map::<HashMap<_, _>>(&wdk_metadata).unwrap();
|
||||
|
||||
assert_eq!(output["DRIVER_MODEL-DRIVER_TYPE"], "KMDF");
|
||||
assert_eq!(output["DRIVER_MODEL-KMDF_VERSION_MAJOR"], "1");
|
||||
assert_eq!(output["DRIVER_MODEL-TARGET_KMDF_VERSION_MINOR"], "33");
|
||||
assert_eq!(output["DRIVER_MODEL-MINIMUM_KMDF_VERSION_MINOR"], "31");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_umdf() {
|
||||
let wdk_metadata = metadata::Wdk {
|
||||
driver_model: DriverConfig::Umdf(UmdfConfig {
|
||||
umdf_version_major: 1,
|
||||
target_umdf_version_minor: 23,
|
||||
minimum_umdf_version_minor: Some(21),
|
||||
}),
|
||||
};
|
||||
|
||||
let output = to_map::<BTreeMap<_, _>>(&wdk_metadata).unwrap();
|
||||
|
||||
assert_eq!(output["DRIVER_MODEL-DRIVER_TYPE"], "UMDF");
|
||||
assert_eq!(output["DRIVER_MODEL-UMDF_VERSION_MAJOR"], "1");
|
||||
assert_eq!(output["DRIVER_MODEL-TARGET_UMDF_VERSION_MINOR"], "23");
|
||||
assert_eq!(output["DRIVER_MODEL-MINIMUM_UMDF_VERSION_MINOR"], "21");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_umdf_no_minimum() {
|
||||
let wdk_metadata = metadata::Wdk {
|
||||
driver_model: DriverConfig::Umdf(UmdfConfig {
|
||||
umdf_version_major: 1,
|
||||
target_umdf_version_minor: 23,
|
||||
minimum_umdf_version_minor: None,
|
||||
}),
|
||||
};
|
||||
|
||||
let output = to_map::<BTreeMap<_, _>>(&wdk_metadata).unwrap();
|
||||
|
||||
assert_eq!(output["DRIVER_MODEL-DRIVER_TYPE"], "UMDF");
|
||||
assert_eq!(output["DRIVER_MODEL-UMDF_VERSION_MAJOR"], "1");
|
||||
assert_eq!(output["DRIVER_MODEL-TARGET_UMDF_VERSION_MINOR"], "23");
|
||||
|
||||
// `None` values are not serialized
|
||||
assert_eq!(output.get("DRIVER_MODEL-MINIMUM_UMDF_VERSION_MINOR"), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_wdm() {
|
||||
let wdk_metadata = metadata::Wdk {
|
||||
driver_model: DriverConfig::Wdm,
|
||||
};
|
||||
|
||||
let output = to_map::<BTreeMap<_, _>>(&wdk_metadata).unwrap();
|
||||
|
||||
assert_eq!(output["DRIVER_MODEL-DRIVER_TYPE"], "WDM");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_conflicting_keys_in_convert_serialized_output_to_map() {
|
||||
let input = vec![("KEY_NAME", "VALUE_1"), ("KEY_NAME", "VALUE_2")]
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k.to_string(), v.to_string()))
|
||||
.collect();
|
||||
|
||||
let err = convert_serialized_output_to_map::<BTreeMap<_, _>>(input).unwrap_err();
|
||||
|
||||
assert!(matches!(
|
||||
err,
|
||||
Error::DuplicateSerializationKeys {
|
||||
key,
|
||||
value_1,
|
||||
value_2,
|
||||
} if key == "KEY_NAME" && value_1 == "VALUE_1" && value_2 == "VALUE_2"
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,713 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// License: MIT OR Apache-2.0
|
||||
|
||||
//! Private module for utility code related to the cargo-make experience for
|
||||
//! building drivers.
|
||||
|
||||
use std::{
|
||||
env,
|
||||
ffi::{CStr, OsStr},
|
||||
io,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use windows::{
|
||||
Win32::System::Registry::{
|
||||
HKEY,
|
||||
HKEY_LOCAL_MACHINE,
|
||||
KEY_READ,
|
||||
RRF_RT_REG_SZ,
|
||||
RegCloseKey,
|
||||
RegGetValueA,
|
||||
RegOpenKeyExA,
|
||||
},
|
||||
core::{PCSTR, s},
|
||||
};
|
||||
|
||||
use crate::{ConfigError, CpuArchitecture, IoError, TwoPartVersion};
|
||||
|
||||
/// Detect `WDKContentRoot` Directory. Logic is based off of Toolset.props in
|
||||
/// NI(22H2) WDK
|
||||
#[must_use]
|
||||
pub fn detect_wdk_content_root() -> Option<PathBuf> {
|
||||
// If WDKContentRoot is present in environment(ex. running in an eWDK prompt),
|
||||
// use it
|
||||
if let Ok(wdk_content_root) = env::var("WDKContentRoot") {
|
||||
let path = Path::new(wdk_content_root.as_str());
|
||||
if path.is_dir() {
|
||||
return Some(path.to_path_buf());
|
||||
}
|
||||
eprintln!(
|
||||
"WDKContentRoot was detected to be {}, but does not exist or is not a valid directory.",
|
||||
path.display()
|
||||
);
|
||||
}
|
||||
|
||||
// If MicrosoftKitRoot environment variable is set, use it to set WDKContentRoot
|
||||
if let Ok(microsoft_kit_root) = env::var("MicrosoftKitRoot") {
|
||||
let path = Path::new(microsoft_kit_root.as_str());
|
||||
|
||||
if !path.is_absolute() {
|
||||
eprintln!(
|
||||
"MicrosoftKitRoot({}) was found in environment, but is not an absolute path.",
|
||||
path.display()
|
||||
);
|
||||
} else if !path.is_dir() {
|
||||
eprintln!(
|
||||
"MicrosoftKitRoot({}) was found in environment, but does not exist or is not a \
|
||||
valid directory.",
|
||||
path.display()
|
||||
);
|
||||
} else {
|
||||
let wdk_kit_version = env::var("WDKKitVersion").unwrap_or_else(|_| "10.0".to_string());
|
||||
let path = path.join("Windows Kits").join(wdk_kit_version);
|
||||
if path.is_dir() {
|
||||
return Some(path);
|
||||
}
|
||||
eprintln!(
|
||||
"WDKContentRoot was detected to be {}, but does not exist or is not a valid \
|
||||
directory.",
|
||||
path.display()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Check HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Kits\Installed
|
||||
// Roots@KitsRoot10 registry key
|
||||
if let Some(path) = read_registry_key_string_value(
|
||||
HKEY_LOCAL_MACHINE,
|
||||
s!(r"SOFTWARE\Microsoft\Windows Kits\Installed Roots"),
|
||||
s!(r"KitsRoot10"),
|
||||
) {
|
||||
return Some(Path::new(path.as_str()).to_path_buf());
|
||||
}
|
||||
|
||||
// Check HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows
|
||||
// Kits\Installed Roots@KitsRoot10 registry key
|
||||
if let Some(path) = read_registry_key_string_value(
|
||||
HKEY_LOCAL_MACHINE,
|
||||
s!(r"SOFTWARE\Wow6432Node\Microsoft\Windows Kits\Installed Roots"),
|
||||
s!(r"KitsRoot10"),
|
||||
) {
|
||||
return Some(Path::new(path.as_str()).to_path_buf());
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Searches a directory and determines the latest windows SDK version in that
|
||||
/// directory
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns a `ConfigError::DirectoryNotFound` error if the directory provided
|
||||
/// does not exist.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the path provided is not valid Unicode.
|
||||
pub fn get_latest_windows_sdk_version(path_to_search: &Path) -> Result<String, ConfigError> {
|
||||
Ok(path_to_search
|
||||
.read_dir()
|
||||
.map_err(|source| IoError::with_path(path_to_search, source))?
|
||||
.filter_map(std::result::Result::ok)
|
||||
.map(|valid_directory_entry| valid_directory_entry.path())
|
||||
.filter(|path| {
|
||||
path.is_dir()
|
||||
&& path.file_name().is_some_and(|directory_name| {
|
||||
directory_name
|
||||
.to_str()
|
||||
.is_some_and(|directory_name| directory_name.starts_with("10."))
|
||||
})
|
||||
})
|
||||
.max() // Get the latest SDK folder in case there are multiple installed
|
||||
.ok_or(ConfigError::DirectoryNotFound {
|
||||
directory: format!(
|
||||
"Windows SDK Directory in {}",
|
||||
path_to_search.to_string_lossy()
|
||||
),
|
||||
})?
|
||||
.file_name()
|
||||
.expect("path should never terminate in ..")
|
||||
.to_str()
|
||||
.expect("directory name should always be valid Unicode")
|
||||
.to_string())
|
||||
}
|
||||
|
||||
/// Detect architecture based on cargo TARGET variable.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the `CARGO_CFG_TARGET_ARCH` environment variable is not set,
|
||||
/// or if the cargo architecture is unsupported.
|
||||
#[must_use]
|
||||
pub fn detect_cpu_architecture_in_build_script() -> CpuArchitecture {
|
||||
let target_arch = env::var("CARGO_CFG_TARGET_ARCH").expect(
|
||||
"Cargo should have set the CARGO_CFG_TARGET_ARCH environment variable when executing \
|
||||
build.rs",
|
||||
);
|
||||
|
||||
CpuArchitecture::try_from_cargo_str(&target_arch).unwrap_or_else(|| {
|
||||
panic!("The target architecture, {target_arch}, is currently not supported.")
|
||||
})
|
||||
}
|
||||
|
||||
/// Validates that a given string matches the WDK version format (10.xxx.yyy.zzz
|
||||
/// where xxx, yyy, and zzz are numeric and not necessarily 3 digits long).
|
||||
#[rustversion::attr(
|
||||
nightly,
|
||||
allow(
|
||||
clippy::nonminimal_bool,
|
||||
reason = "is_some_or is not stable until 1.82.0 is released on 10/17/24"
|
||||
)
|
||||
)]
|
||||
pub fn validate_wdk_version_format<S: AsRef<str>>(version_string: S) -> bool {
|
||||
let version = version_string.as_ref();
|
||||
let version_parts: Vec<&str> = version.split('.').collect();
|
||||
|
||||
// First, check if we have "10" as our first value
|
||||
if version_parts.first().is_none_or(|first| *first != "10") {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now check that we have four entries.
|
||||
if version_parts.len() != 4 {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Finally, confirm each part is numeric.
|
||||
if !version_parts
|
||||
.iter()
|
||||
.all(|version_part| version_part.parse::<i32>().is_ok())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
/// Returns the version number from a full WDK version string.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function returns a [`ConfigError::WdkVersionStringFormatError`] if the
|
||||
/// version string provided is ill-formed.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If the WDK version format validation function is ever changed not to
|
||||
/// validate that there are 4 substrings in the WDK version string, this
|
||||
/// function will panic.
|
||||
pub fn get_wdk_version_number<S: AsRef<str> + ToString + ?Sized>(
|
||||
version_string: &S,
|
||||
) -> Result<String, ConfigError> {
|
||||
if !validate_wdk_version_format(version_string) {
|
||||
return Err(ConfigError::WdkVersionStringFormatError {
|
||||
version: version_string.to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
let version_substrings = version_string.as_ref().split('.').collect::<Vec<&str>>();
|
||||
let version_substring = version_substrings.get(2).expect(
|
||||
"WDK version string was validated to be well-formatted, but we couldn't get the \
|
||||
appropriate substring!",
|
||||
);
|
||||
Ok((*version_substring).to_string())
|
||||
}
|
||||
|
||||
/// Read a string value from a registry key
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `key_handle` - a [`windows::Win32::System::Registry::HKEY`] to the base
|
||||
/// key
|
||||
/// * `sub_key` - a [`windows::core::PCSTR`] that is the path of a registry key
|
||||
/// relative to the `key_handle` argument
|
||||
/// * `value` - a [`windows::core::PCSTR`] that is the name of the string
|
||||
/// registry value to read
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if read value isn't valid UTF-8 or if the opened regkey could not be
|
||||
/// closed
|
||||
fn read_registry_key_string_value(
|
||||
key_handle: HKEY,
|
||||
sub_key: PCSTR,
|
||||
value: PCSTR,
|
||||
) -> Option<String> {
|
||||
let mut opened_key_handle = HKEY::default();
|
||||
let mut len = 0;
|
||||
if
|
||||
// SAFETY: `&mut opened_key_handle` is coerced to a &raw mut, so the address passed as the
|
||||
// argument is always valid. `&mut opened_key_handle` is coerced to a pointer of the correct
|
||||
// type.
|
||||
unsafe { RegOpenKeyExA(key_handle, sub_key, 0, KEY_READ, &raw mut opened_key_handle) }
|
||||
.is_ok()
|
||||
{
|
||||
if
|
||||
// SAFETY: `opened_key_handle` is valid key opened with the `KEY_QUERY_VALUE` access right
|
||||
// (included in `KEY_READ`). `&mut len` is coerced to a &raw mut, so the address passed as
|
||||
// the argument is always valid. `&mut len` is coerced to a pointer of the correct
|
||||
// type.
|
||||
unsafe {
|
||||
RegGetValueA(
|
||||
opened_key_handle,
|
||||
None,
|
||||
value,
|
||||
RRF_RT_REG_SZ,
|
||||
None,
|
||||
None,
|
||||
Some(&raw mut len),
|
||||
)
|
||||
}
|
||||
.is_ok()
|
||||
{
|
||||
let mut buffer = vec![0u8; len as usize];
|
||||
if
|
||||
// SAFETY: `opened_key_handle` is valid key opened with the `KEY_QUERY_VALUE` access
|
||||
// right (included in `KEY_READ`). `&mut buffer` is coerced to a &raw mut,
|
||||
// so the address passed as the argument is always valid. `&mut buffer` is
|
||||
// coerced to a pointer of the correct type. `&mut len` is coerced to a &raw
|
||||
// mut, so the address passed as the argument is always valid. `&mut len` is
|
||||
// coerced to a pointer of the correct type.
|
||||
unsafe {
|
||||
RegGetValueA(
|
||||
opened_key_handle,
|
||||
None,
|
||||
value,
|
||||
RRF_RT_REG_SZ,
|
||||
None,
|
||||
Some(buffer.as_mut_ptr().cast()),
|
||||
Some(&raw mut len),
|
||||
)
|
||||
}
|
||||
.is_ok()
|
||||
{
|
||||
// SAFETY: `opened_key_handle` is valid opened key that was opened by
|
||||
// `RegOpenKeyExA`
|
||||
unsafe { RegCloseKey(opened_key_handle) }
|
||||
.ok()
|
||||
.expect("opened_key_handle should be successfully closed");
|
||||
return Some(
|
||||
CStr::from_bytes_with_nul(&buffer[..len as usize])
|
||||
.expect(
|
||||
"RegGetValueA should always return a null-terminated string. The read \
|
||||
string (REG_SZ) from the registry should not contain any interior \
|
||||
nulls.",
|
||||
)
|
||||
.to_str()
|
||||
.expect("Registry value should be parseable as UTF8")
|
||||
.to_string(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// SAFETY: `opened_key_handle` is valid opened key that was opened by
|
||||
// `RegOpenKeyExA`
|
||||
unsafe { RegCloseKey(opened_key_handle) }
|
||||
.ok()
|
||||
.expect("opened_key_handle should be successfully closed");
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Detects the Windows SDK version from the `Version_Number` env var or from
|
||||
/// the WDK content's `Lib` directory.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `wdk_content_root` - A reference to the path where the WDK content root is
|
||||
/// located.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns a `ConfigError::DirectoryNotFound` error if the directory provided
|
||||
/// does not exist.
|
||||
pub fn detect_windows_sdk_version(wdk_content_root: &Path) -> Result<String, ConfigError> {
|
||||
env::var("Version_Number")
|
||||
.or_else(|_| get_latest_windows_sdk_version(&wdk_content_root.join("Lib")))
|
||||
}
|
||||
|
||||
/// Finds the maximum version in a directory where subdirectories are named with
|
||||
/// version format "x.y"
|
||||
pub fn find_max_version_in_directory<P: AsRef<Path>>(
|
||||
directory_path: P,
|
||||
) -> Result<TwoPartVersion, IoError> {
|
||||
let directory_path = directory_path.as_ref();
|
||||
std::fs::read_dir(directory_path)
|
||||
.map_err(|source| IoError::with_path(directory_path, source))?
|
||||
.flatten()
|
||||
.filter(|entry| entry.file_type().is_ok_and(|ft| ft.is_dir()))
|
||||
.filter_map(|entry| entry.file_name().to_str()?.parse().ok())
|
||||
.max()
|
||||
.ok_or_else(|| {
|
||||
IoError::with_path(
|
||||
directory_path,
|
||||
io::Error::new(
|
||||
io::ErrorKind::NotFound,
|
||||
format!("Maximum version in {} not found", directory_path.display()),
|
||||
),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Safely sets an environment variable. Will not compile if crate is not
|
||||
/// targeted for Windows.
|
||||
///
|
||||
/// This function provides a safe wrapper around [`std::env::set_var`] that
|
||||
/// became unsafe in Rust 2024 edition.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function may panic if key is empty, contains an ASCII equals sign '='
|
||||
/// or the NUL character '\0', or when value contains the NUL character.
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn set_var<K, V>(key: K, value: V)
|
||||
where
|
||||
K: AsRef<OsStr>,
|
||||
V: AsRef<OsStr>,
|
||||
{
|
||||
// SAFETY: this function is only conditionally compiled for windows targets, and
|
||||
// env::set_var is always safe for windows targets
|
||||
unsafe {
|
||||
env::set_var(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
pub fn set_var<K, V>(_key: K, _value: V)
|
||||
where
|
||||
K: AsRef<OsStr>,
|
||||
V: AsRef<OsStr>,
|
||||
{
|
||||
compile_error!(
|
||||
"windows-drivers-rs is designed to be run on a Windows host machine in a WDK environment. \
|
||||
Please build using a Windows target."
|
||||
);
|
||||
}
|
||||
|
||||
/// Safely removes an environment variable. Will not compile if crate is not
|
||||
/// targeted for Windows.
|
||||
///
|
||||
/// This function provides a safe wrapper around [`std::env::remove_var`] that
|
||||
/// became unsafe in Rust 2024 edition.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function may panic if key is empty, contains an ASCII equals sign '='
|
||||
/// or the NUL character '\0', or when value contains the NUL character.
|
||||
#[allow(dead_code)]
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn remove_var<K>(key: K)
|
||||
where
|
||||
K: AsRef<OsStr>,
|
||||
{
|
||||
// SAFETY: this function is only conditionally compiled for windows targets, and
|
||||
// env::remove_var is always safe for windows targets
|
||||
unsafe {
|
||||
env::remove_var(key);
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
pub fn remove_var<K>(_key: K)
|
||||
where
|
||||
K: AsRef<OsStr>,
|
||||
{
|
||||
compile_error!(
|
||||
"windows-drivers-rs is designed to be run on a Windows host machine in a WDK environment. \
|
||||
Please build using a Windows target."
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use assert_fs::prelude::*;
|
||||
|
||||
use super::*;
|
||||
|
||||
// Function with_clean_env clears the inputted environment variable and runs the
|
||||
// closure
|
||||
fn with_clean_env<F>(key: &str, f: F)
|
||||
where
|
||||
F: FnOnce(),
|
||||
{
|
||||
let original = env::var(key).ok();
|
||||
|
||||
// SAFETY: We have verified that this is built for a Windows host due to no
|
||||
// compile errors from building `set_var`.
|
||||
unsafe {
|
||||
env::remove_var(key);
|
||||
}
|
||||
|
||||
f();
|
||||
|
||||
if let Some(val) = &original {
|
||||
// SAFETY: We have verified that this is built for a Windows host due to no
|
||||
// compile errors from building `set_var`.
|
||||
unsafe {
|
||||
env::set_var(key, val);
|
||||
}
|
||||
} else {
|
||||
// SAFETY: We have verified that this is built for a Windows host due to no
|
||||
// compile errors from building `set_var`.
|
||||
unsafe {
|
||||
env::remove_var(key);
|
||||
}
|
||||
}
|
||||
|
||||
assert!(env::var(key).ok() == original);
|
||||
}
|
||||
|
||||
mod read_registry_key_string_value {
|
||||
use windows::Win32::UI::Shell::{
|
||||
FOLDERID_ProgramFiles,
|
||||
KF_FLAG_DEFAULT,
|
||||
SHGetKnownFolderPath,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn read_reg_key_programfilesdir() {
|
||||
let program_files_dir =
|
||||
// SAFETY: FOLDERID_ProgramFiles is a constant from the windows crate, so the pointer (resulting from its reference being coerced) is always valid to be dereferenced
|
||||
unsafe { SHGetKnownFolderPath(&FOLDERID_ProgramFiles, KF_FLAG_DEFAULT, None) }
|
||||
.expect("Program Files Folder should always resolve via SHGetKnownFolderPath.");
|
||||
|
||||
assert_eq!(
|
||||
read_registry_key_string_value(
|
||||
HKEY_LOCAL_MACHINE,
|
||||
s!(r"SOFTWARE\Microsoft\Windows\CurrentVersion"),
|
||||
s!("ProgramFilesDir")
|
||||
),
|
||||
Some(
|
||||
// SAFETY: program_files_dir pointer stays valid for reads up until and
|
||||
// including its terminating null
|
||||
unsafe { program_files_dir.to_string() }
|
||||
.expect("Path resolved from FOLDERID_ProgramFiles should be valid UTF16.")
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validate_wdk_strings() {
|
||||
let test_string = "10.0.12345.0";
|
||||
assert_eq!(
|
||||
get_wdk_version_number(test_string).ok(),
|
||||
Some("12345".to_string())
|
||||
);
|
||||
let test_string = "10.0.5.0";
|
||||
assert_eq!(
|
||||
get_wdk_version_number(test_string).ok(),
|
||||
Some("5".to_string())
|
||||
);
|
||||
let test_string = "10.0.0.0";
|
||||
assert_eq!(
|
||||
get_wdk_version_number(test_string).ok(),
|
||||
Some("0".to_string())
|
||||
);
|
||||
let test_string = "11.0.0.0";
|
||||
assert_eq!(
|
||||
format!("{}", get_wdk_version_number(test_string).err().unwrap()),
|
||||
format!(
|
||||
"the WDK version string provided ({}) was not in a valid format",
|
||||
test_string
|
||||
)
|
||||
);
|
||||
let test_string = "10.0.12345.0.0";
|
||||
assert_eq!(
|
||||
format!("{}", get_wdk_version_number(test_string).err().unwrap()),
|
||||
format!(
|
||||
"the WDK version string provided ({}) was not in a valid format",
|
||||
test_string
|
||||
)
|
||||
);
|
||||
let test_string = "10.0.12345.a";
|
||||
assert_eq!(
|
||||
format!("{}", get_wdk_version_number(test_string).err().unwrap()),
|
||||
format!(
|
||||
"the WDK version string provided ({}) was not in a valid format",
|
||||
test_string
|
||||
)
|
||||
);
|
||||
let test_string = "10.0.12345";
|
||||
assert_eq!(
|
||||
format!("{}", get_wdk_version_number(test_string).err().unwrap()),
|
||||
format!(
|
||||
"the WDK version string provided ({}) was not in a valid format",
|
||||
test_string
|
||||
)
|
||||
);
|
||||
let test_string = "10.0.1234!5.0";
|
||||
assert_eq!(
|
||||
format!("{}", get_wdk_version_number(test_string).err().unwrap()),
|
||||
format!(
|
||||
"the WDK version string provided ({}) was not in a valid format",
|
||||
test_string
|
||||
)
|
||||
);
|
||||
let test_string = "Not a real version!";
|
||||
assert_eq!(
|
||||
format!("{}", get_wdk_version_number(test_string).err().unwrap()),
|
||||
format!(
|
||||
"the WDK version string provided ({}) was not in a valid format",
|
||||
test_string
|
||||
)
|
||||
);
|
||||
let test_string = "";
|
||||
assert_eq!(
|
||||
format!("{}", get_wdk_version_number(test_string).err().unwrap()),
|
||||
format!(
|
||||
"the WDK version string provided ({}) was not in a valid format",
|
||||
test_string
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
mod find_max_version_in_directory {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn empty_directory() {
|
||||
let temp_dir = assert_fs::TempDir::new().unwrap();
|
||||
let result = find_max_version_in_directory(temp_dir.path());
|
||||
assert!(result.is_err());
|
||||
assert_eq!(
|
||||
result.unwrap_err().source.kind(),
|
||||
std::io::ErrorKind::NotFound
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nonexistent_directory() {
|
||||
let nonexistent_path = std::path::Path::new("/this/path/does/not/exist");
|
||||
let result = find_max_version_in_directory(nonexistent_path);
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn valid_version_directories() {
|
||||
// Single valid version directory
|
||||
let temp_dir = assert_fs::TempDir::new().unwrap();
|
||||
temp_dir.child("3.14").create_dir_all().unwrap();
|
||||
temp_dir.child("folder1").create_dir_all().unwrap();
|
||||
assert_eq!(
|
||||
find_max_version_in_directory(temp_dir.path()).unwrap(),
|
||||
TwoPartVersion(3, 14)
|
||||
);
|
||||
// Multiple valid version directories
|
||||
let temp_dir = assert_fs::TempDir::new().unwrap();
|
||||
temp_dir.child("1.2").create_dir_all().unwrap();
|
||||
temp_dir.child("1.10").create_dir_all().unwrap();
|
||||
temp_dir.child("2.0").create_dir_all().unwrap();
|
||||
temp_dir.child("not_a_version").create_dir_all().unwrap();
|
||||
assert_eq!(
|
||||
find_max_version_in_directory(temp_dir.path()).unwrap(),
|
||||
TwoPartVersion(2, 0)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_version_directories() {
|
||||
// Single invalid directory
|
||||
let temp_dir = assert_fs::TempDir::new().unwrap();
|
||||
temp_dir.child("folder1").create_dir_all().unwrap();
|
||||
let result = find_max_version_in_directory(temp_dir.path());
|
||||
assert!(result.is_err());
|
||||
assert_eq!(
|
||||
result.unwrap_err().source.kind(),
|
||||
std::io::ErrorKind::NotFound
|
||||
);
|
||||
|
||||
// Multiple invalid directories
|
||||
let temp_dir = assert_fs::TempDir::new().unwrap();
|
||||
temp_dir.child("folder1").create_dir_all().unwrap();
|
||||
temp_dir.child("1.2.3").create_dir_all().unwrap(); // Too many dots
|
||||
temp_dir.child("a.b").create_dir_all().unwrap(); // Non-numeric
|
||||
temp_dir.child("1").create_dir_all().unwrap(); // No dot
|
||||
temp_dir.child("1.").create_dir_all().unwrap(); // Missing minor
|
||||
temp_dir.child(".5").create_dir_all().unwrap(); // Missing major
|
||||
let result = find_max_version_in_directory(temp_dir.path());
|
||||
assert!(result.is_err());
|
||||
assert_eq!(
|
||||
result.unwrap_err().source.kind(),
|
||||
std::io::ErrorKind::NotFound
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn major_version_priority() {
|
||||
let temp_dir = assert_fs::TempDir::new().unwrap();
|
||||
temp_dir.child("1.999").create_dir_all().unwrap();
|
||||
temp_dir.child("2.0").create_dir_all().unwrap();
|
||||
temp_dir.child("1.1000").create_dir_all().unwrap();
|
||||
assert_eq!(
|
||||
find_max_version_in_directory(temp_dir.path()).unwrap(),
|
||||
TwoPartVersion(2, 0)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn minor_version_comparison() {
|
||||
let temp_dir = assert_fs::TempDir::new().unwrap();
|
||||
temp_dir.child("1.5").create_dir_all().unwrap();
|
||||
temp_dir.child("1.10").create_dir_all().unwrap();
|
||||
temp_dir.child("1.2").create_dir_all().unwrap();
|
||||
assert_eq!(
|
||||
find_max_version_in_directory(temp_dir.path()).unwrap(),
|
||||
TwoPartVersion(1, 10)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zero_versions() {
|
||||
let temp_dir = assert_fs::TempDir::new().unwrap();
|
||||
temp_dir.child("0.0").create_dir_all().unwrap();
|
||||
temp_dir.child("0.1").create_dir_all().unwrap();
|
||||
assert_eq!(
|
||||
find_max_version_in_directory(temp_dir.path()).unwrap(),
|
||||
TwoPartVersion(0, 1)
|
||||
);
|
||||
temp_dir.child("1.0").create_dir_all().unwrap();
|
||||
assert_eq!(
|
||||
find_max_version_in_directory(temp_dir.path()).unwrap(),
|
||||
TwoPartVersion(1, 0)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mixed_valid_and_invalid_entries() {
|
||||
let temp_dir = assert_fs::TempDir::new().unwrap();
|
||||
temp_dir.child("1.5").create_dir_all().unwrap();
|
||||
temp_dir.child("2.0").create_dir_all().unwrap();
|
||||
temp_dir.child("invalid").create_dir_all().unwrap();
|
||||
temp_dir.child("1.2.3").create_dir_all().unwrap(); // Invalid: too many dots
|
||||
temp_dir.child("a.b").create_dir_all().unwrap(); // Invalid: non-numeric
|
||||
temp_dir.child("not_version").touch().unwrap(); // File: ignored
|
||||
temp_dir.child("3.0").touch().unwrap(); // File: ignored
|
||||
// Should find the maximum among valid version directories only
|
||||
assert_eq!(
|
||||
find_max_version_in_directory(temp_dir.path()).unwrap(),
|
||||
TwoPartVersion(2, 0)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
mod safe_env_vars {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn set_var_and_remove_var() {
|
||||
let key = "WDK_BUILD_TEST_VAR";
|
||||
with_clean_env(key, || {
|
||||
set_var(key, "test_value");
|
||||
assert_eq!(env::var(key).unwrap(), "test_value");
|
||||
remove_var(key);
|
||||
assert!(env::var(key).is_err());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
|
||||
## [0.5.1](https://github.com/microsoft/windows-drivers-rs/compare/wdk-sys-v0.5.0...wdk-sys-v0.5.1) - 2025-11-13
|
||||
|
||||
### Other
|
||||
|
||||
- fix wdk-build version in readme ([#568](https://github.com/microsoft/windows-drivers-rs/pull/568))
|
||||
|
||||
## [0.5.0](https://github.com/microsoft/windows-drivers-rs/compare/wdk-sys-v0.4.0...wdk-sys-v0.5.0) - 2025-11-06
|
||||
|
||||
### Added
|
||||
|
||||
- enhance error handling with IoError and IoErrorMetadata for improved std::io::Error diagnostics for fs errors ([#480](https://github.com/microsoft/windows-drivers-rs/pull/480))
|
||||
|
||||
### Fixed
|
||||
|
||||
- use latest version of ucx in the WDKContent as default ([#411](https://github.com/microsoft/windows-drivers-rs/pull/411))
|
||||
- allow unnecessary_transmutes lint for bindgen-generated types.rs ([#350](https://github.com/microsoft/windows-drivers-rs/pull/350))
|
||||
|
||||
### Other
|
||||
|
||||
- [**breaking**] bump to Rust 2024 Edition ([#430](https://github.com/microsoft/windows-drivers-rs/pull/430))
|
||||
- improve logging for build action ([#495](https://github.com/microsoft/windows-drivers-rs/pull/495))
|
||||
- enforce typo checking ([#452](https://github.com/microsoft/windows-drivers-rs/pull/452))
|
||||
- Add stubs for __CxxFrameHandler4 and __GSHandlerCheck_EH4 ([#438](https://github.com/microsoft/windows-drivers-rs/pull/438))
|
||||
|
||||
## [0.4.0](https://github.com/microsoft/windows-drivers-rs/compare/wdk-sys-v0.3.0...wdk-sys-v0.4.0) - 2025-04-18
|
||||
|
||||
### Added
|
||||
|
||||
- extend coverage in `wdk-sys` to include usb-related headers ([#296](https://github.com/microsoft/windows-drivers-rs/pull/296))
|
||||
- expand wdk-sys coverage to include gpio and parallel ports related headers ([#278](https://github.com/microsoft/windows-drivers-rs/pull/278))
|
||||
- add support for Storage API subset in `wdk-sys` ([#287](https://github.com/microsoft/windows-drivers-rs/pull/287))
|
||||
- expand `wdk-sys` coverage to include spb-related headers ([#263](https://github.com/microsoft/windows-drivers-rs/pull/263))
|
||||
- [**breaking**] expand `wdk-sys` coverage to include hid-related headers ([#260](https://github.com/microsoft/windows-drivers-rs/pull/260))
|
||||
- Use stack-based formatter for debug-printing. ([#233](https://github.com/microsoft/windows-drivers-rs/pull/233))
|
||||
|
||||
### Fixed
|
||||
|
||||
- passing cache tests when WDK config is enabled ([#332](https://github.com/microsoft/windows-drivers-rs/pull/332))
|
||||
- [**breaking**] specify rust version & edition to wdk-default bindgen::builder ([#314](https://github.com/microsoft/windows-drivers-rs/pull/314))
|
||||
- use absolute paths for items used in PAGED_CODE macro ([#297](https://github.com/microsoft/windows-drivers-rs/pull/297))
|
||||
|
||||
### Other
|
||||
|
||||
- update README to clarify community engagement and contact methods ([#312](https://github.com/microsoft/windows-drivers-rs/pull/312))
|
||||
- [**breaking**] Remove lazy static instances ([#250](https://github.com/microsoft/windows-drivers-rs/pull/250))
|
||||
- use `is_none_or` for `clippy::nonminimal_bool` and resolve `clippy::needless_raw_string_hashes` ([#231](https://github.com/microsoft/windows-drivers-rs/pull/231))
|
||||
|
||||
## [0.3.0](https://github.com/microsoft/windows-drivers-rs/compare/wdk-sys-v0.2.0...wdk-sys-v0.3.0) - 2024-09-27
|
||||
|
||||
### Added
|
||||
|
||||
- add more precise NTSTATUS const fns ([#183](https://github.com/microsoft/windows-drivers-rs/pull/183))
|
||||
- configure WDK configuration via parsing Cargo manifest metadata ([#186](https://github.com/microsoft/windows-drivers-rs/pull/186))
|
||||
|
||||
### Fixed
|
||||
|
||||
- typos in Getting Started section of README.md ([#213](https://github.com/microsoft/windows-drivers-rs/pull/213))
|
||||
- [**breaking**] prevent linking of wdk libraries in tests that depend on `wdk-sys` ([#118](https://github.com/microsoft/windows-drivers-rs/pull/118))
|
||||
|
||||
### Other
|
||||
|
||||
- Improve doc comments to comply with `too_long_first_doc_paragraph` clippy lint ([#202](https://github.com/microsoft/windows-drivers-rs/pull/202))
|
||||
- Update README.md ([#180](https://github.com/microsoft/windows-drivers-rs/pull/180))
|
||||
- update readme to call out bugged LLVM 18 versions ([#169](https://github.com/microsoft/windows-drivers-rs/pull/169))
|
||||
- Build perf: Make calls to bindgen run in parallel ([#159](https://github.com/microsoft/windows-drivers-rs/pull/159))
|
||||
- Bump rustversion from 1.0.14 to 1.0.15 ([#145](https://github.com/microsoft/windows-drivers-rs/pull/145))
|
||||
- use a standardized workspace lint table ([#134](https://github.com/microsoft/windows-drivers-rs/pull/134))
|
||||
- Bump anyhow from 1.0.79 to 1.0.82 ([#140](https://github.com/microsoft/windows-drivers-rs/pull/140))
|
||||
- Bump thiserror from 1.0.56 to 1.0.59 ([#142](https://github.com/microsoft/windows-drivers-rs/pull/142))
|
||||
- change version bounds for `manual_c_str_literals` and `ref_as_ptr` clippy lints ([#127](https://github.com/microsoft/windows-drivers-rs/pull/127))
|
||||
- fix `winget` llvm install command option ([#115](https://github.com/microsoft/windows-drivers-rs/pull/115))
|
||||
- fix various pipeline breakages (nightly rustfmt bug, new nightly clippy lints, upstream winget dependency issue) ([#117](https://github.com/microsoft/windows-drivers-rs/pull/117))
|
||||
- add lint exceptions for clippy::manual_c_str_literals and clippy::ref_as_ptr ([#108](https://github.com/microsoft/windows-drivers-rs/pull/108))
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
|
||||
## [0.2.0](https://github/microsoft/windows-drivers-rs/compare/wdk-sys-v0.1.0...wdk-sys-v0.2.0) - 2024-02-08
|
||||
|
||||
### Added
|
||||
- generate CStr for c string constants instead of &[u8] ([#72](https://github/microsoft/windows-drivers-rs/pull/72))
|
||||
|
||||
### Fixed
|
||||
- resolve warnings in rust-script blocks and only fail warnings in CI ([#87](https://github/microsoft/windows-drivers-rs/pull/87))
|
||||
|
||||
### Other
|
||||
- update dependencies
|
||||
- allow multiple_crate_versions in wdk-build (build dependency) ([#98](https://github/microsoft/windows-drivers-rs/pull/98))
|
||||
- allow exception for clippy::pub_underscore_fields in generated code ([#77](https://github/microsoft/windows-drivers-rs/pull/77))
|
||||
- Bump thiserror from 1.0.48 to 1.0.55 ([#59](https://github/microsoft/windows-drivers-rs/pull/59))
|
||||
- reduce noise from bindgen warnings
|
||||
- fix clippy errors missed due to buggy ci stage
|
||||
- restrict to one unsafe operation per block ([#24](https://github/microsoft/windows-drivers-rs/pull/24))
|
||||
- [**breaking**] enable rustdoc lints and resolve errors
|
||||
- remove extra keywords in cargo manifests
|
||||
- initial open-source check in
|
||||
+859
@@ -0,0 +1,859 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"is_terminal_polyfill",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"once_cell_polyfill",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.97"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f"
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.71.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"itertools",
|
||||
"log",
|
||||
"prettyplease",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
"shlex",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
|
||||
|
||||
[[package]]
|
||||
name = "camino"
|
||||
version = "1.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo-platform"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo_metadata"
|
||||
version = "0.19.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba"
|
||||
dependencies = [
|
||||
"camino",
|
||||
"cargo-platform",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1d05d92f4b1fd76aad469d46cdd858ca761576082cd37df81416691e50199fb"
|
||||
dependencies = [
|
||||
"find-msvc-tools",
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cexpr"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9"
|
||||
|
||||
[[package]]
|
||||
name = "clang-sys"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"libc",
|
||||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap-cargo"
|
||||
version = "0.15.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d546f0e84ff2bfa4da1ce9b54be42285767ba39c688572ca32412a09a73851e5"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"clap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "find-msvc-tools"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0399f9d26e5191ce32c498bebd31e7a3ceabc2745f0ac54af3f335126c3f24b3"
|
||||
|
||||
[[package]]
|
||||
name = "fs4"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8640e34b88f7652208ce9e88b1a37a2ae95227d84abec377ccd3c5cfeb141ed4"
|
||||
dependencies = [
|
||||
"rustix",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.172"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
|
||||
|
||||
[[package]]
|
||||
name = "matchers"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
|
||||
dependencies = [
|
||||
"regex-automata",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.50.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell_polyfill"
|
||||
version = "1.70.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
|
||||
|
||||
[[package]]
|
||||
name = "prettyplease"
|
||||
version = "0.2.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.101"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
||||
|
||||
[[package]]
|
||||
name = "scratch"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f6280af86e5f559536da57a45ebc84948833b3bee313a7dd25232e09c878a52"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.219"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.219"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.140"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
|
||||
dependencies = [
|
||||
"pin-project-lite",
|
||||
"tracing-attributes",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-attributes"
|
||||
version = "0.1.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"valuable",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-log"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
|
||||
dependencies = [
|
||||
"log",
|
||||
"once_cell",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.3.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5"
|
||||
dependencies = [
|
||||
"matchers",
|
||||
"nu-ansi-term",
|
||||
"once_cell",
|
||||
"regex-automata",
|
||||
"sharded-slab",
|
||||
"smallvec",
|
||||
"thread_local",
|
||||
"tracing",
|
||||
"tracing-core",
|
||||
"tracing-log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "valuable"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
||||
|
||||
[[package]]
|
||||
name = "wdk-build"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c150122a579af759770b354064cd2994d29e97525d904f65ff1412ad5122766"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bindgen",
|
||||
"camino",
|
||||
"cargo_metadata",
|
||||
"cfg-if",
|
||||
"clap",
|
||||
"clap-cargo",
|
||||
"paste",
|
||||
"regex",
|
||||
"rustversion",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"tracing",
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wdk-macros"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b288d5ef6b276345d197fe0b82ef274dcb5a1f658a2294c67ff85b775f63ee26"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fs4",
|
||||
"itertools",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"scratch",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wdk-sys"
|
||||
version = "0.5.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bindgen",
|
||||
"cargo_metadata",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"rustversion",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"wdk-build",
|
||||
"wdk-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.58.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6"
|
||||
dependencies = [
|
||||
"windows-core",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.58.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99"
|
||||
dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-result",
|
||||
"windows-strings",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.58.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-interface"
|
||||
version = "0.58.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
|
||||
dependencies = [
|
||||
"windows-result",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2024"
|
||||
name = "wdk-sys"
|
||||
version = "0.5.1"
|
||||
build = "build.rs"
|
||||
links = "wdk"
|
||||
autolib = false
|
||||
autobins = false
|
||||
autoexamples = false
|
||||
autotests = false
|
||||
autobenches = false
|
||||
description = "Direct bindings to APIs available in the Windows Development Kit (WDK)"
|
||||
readme = "README.md"
|
||||
keywords = [
|
||||
"wdk",
|
||||
"windows",
|
||||
"wdf",
|
||||
"wdm",
|
||||
"ffi",
|
||||
]
|
||||
categories = [
|
||||
"external-ffi-bindings",
|
||||
"development-tools::ffi",
|
||||
"os::windows-apis",
|
||||
"os",
|
||||
]
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/microsoft/windows-drivers-rs"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
gpio = []
|
||||
hid = []
|
||||
nightly = [
|
||||
"wdk-macros/nightly",
|
||||
"wdk-build/nightly",
|
||||
]
|
||||
parallel-ports = ["gpio"]
|
||||
spb = []
|
||||
storage = []
|
||||
test-stubs = []
|
||||
usb = []
|
||||
iddcx = []
|
||||
|
||||
[lib]
|
||||
name = "wdk_sys"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies.rustversion]
|
||||
version = "1.0.20"
|
||||
|
||||
[dependencies.wdk-macros]
|
||||
version = "=0.5.1"
|
||||
|
||||
[build-dependencies.anyhow]
|
||||
version = "1.0.97"
|
||||
|
||||
[build-dependencies.bindgen]
|
||||
version = "0.71.0"
|
||||
|
||||
[build-dependencies.cargo_metadata]
|
||||
version = "0.19.2"
|
||||
|
||||
[build-dependencies.cc]
|
||||
version = "1.2.39"
|
||||
|
||||
[build-dependencies.cfg-if]
|
||||
version = "1.0.3"
|
||||
|
||||
[build-dependencies.serde_json]
|
||||
version = "1.0"
|
||||
|
||||
[build-dependencies.thiserror]
|
||||
version = "2.0.12"
|
||||
|
||||
[build-dependencies.tracing]
|
||||
version = "0.1.40"
|
||||
|
||||
[build-dependencies.tracing-subscriber]
|
||||
version = "0.3.20"
|
||||
features = ["env-filter"]
|
||||
|
||||
[build-dependencies.wdk-build]
|
||||
version = "0.5.1"
|
||||
|
||||
[lints.clippy]
|
||||
all = "deny"
|
||||
cargo = "warn"
|
||||
multiple_unsafe_ops_per_block = "deny"
|
||||
nursery = "warn"
|
||||
pedantic = "warn"
|
||||
undocumented_unsafe_blocks = "deny"
|
||||
unnecessary_safety_doc = "forbid"
|
||||
|
||||
[lints.rust]
|
||||
missing_docs = "warn"
|
||||
unsafe_op_in_unsafe_fn = "deny"
|
||||
|
||||
[lints.rustdoc]
|
||||
bare_urls = "warn"
|
||||
broken_intra_doc_links = "warn"
|
||||
invalid_codeblock_attributes = "warn"
|
||||
invalid_html_tags = "warn"
|
||||
invalid_rust_codeblocks = "warn"
|
||||
missing_crate_level_docs = "warn"
|
||||
private_intra_doc_links = "warn"
|
||||
redundant_explicit_links = "warn"
|
||||
unescaped_backticks = "warn"
|
||||
+237
@@ -0,0 +1,237 @@
|
||||
# windows-drivers-rs
|
||||
|
||||
This repo is a collection of Rust crates that enable developers to develop Windows Drivers in Rust. It is the intention to support both WDM and WDF driver development models. This repo contains the following crates:
|
||||
|
||||
* [wdk-build](./crates/wdk-build): A library to configure a Cargo build script for binding generation and downstream linking of the WDK (Windows Driver Kit). While this crate is written to be flexible with different WDK releases and different WDF version, it is currently only tested for NI eWDK, KMDF 1.33, UMDF 2.33, and WDM Drivers. There may be missing linker options for older DDKs.
|
||||
* [wdk-sys](./crates/wdk-sys): Direct FFI bindings to APIs available in the Windows Development Kit (WDK). This includes both autogenerated ffi bindings from `bindgen`, and also manual re-implementations of macros that bindgen fails to generate.
|
||||
* [wdk](./crates/wdk): Safe idiomatic bindings to APIs available in the Windows Development Kit (WDK)
|
||||
* [wdk-panic](./crates/wdk-panic/): Default panic handler implementations for programs built with WDK
|
||||
* [wdk-alloc](./crates/wdk-alloc): alloc support for binaries compiled with the Windows Development Kit (WDK)
|
||||
* [wdk-macros](./crates/wdk-macros): A collection of macros that help make it easier to interact with wdk-sys's direct bindings. This crate is re-exported via `wdk-sys` and crates should typically never need to directly depend on `wdk-macros`
|
||||
|
||||
To see an example of this repo used to create drivers, see [Windows-rust-driver-samples](https://github.com/microsoft/Windows-rust-driver-samples).
|
||||
|
||||
Note: This project is still in early stages of development and is not yet recommended for production use. We encourage community experimentation and collaboration through our [GitHub Discussions forum](https://github.com/microsoft/windows-drivers-rs/discussions)!
|
||||
|
||||
## <a name="supported-configs">Supported Configurations
|
||||
|
||||
This project was built with support of WDM, KMDF, and UMDF drivers in mind, as well as Win32 Services. This includes support for all versions of WDF included in WDK 22H2 and newer. Currently, the crates available on [`crates.io`](https://crates.io) only support KMDF v1.33, but bindings can be generated for everything else by cloning `windows-drivers-rs` and modifying the config specified in [`build.rs` of `wdk-sys`](./crates/wdk-sys/build.rs). Crates.io support for other WDK configurations is planned in the near future.
|
||||
|
||||
## Repo Layout
|
||||
|
||||
* [crates](./crates): Contains all the main crates that are a part of the Cargo workspace.
|
||||
* [examples](./examples): Contains workspace-level examples. These examples consist of different types of minimal Windows drivers (ie. WDM, KMDF, UMDF).
|
||||
* [tests](./tests): Contains workspace-level tests, including tests for metadata-based wdk configuration in packages and workspaces.
|
||||
|
||||
**Note:**: Since the workspace level examples and tests use different WDK configurations, and WDR only supports one WDK configuration per workspace, the workspace-level examples and tests folder are excluded from the [repository root's Cargo manifest](./Cargo.toml).
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Build Requirements
|
||||
|
||||
* Binding generation via `bindgen` requires `libclang`. The easiest way to acquire this is via `winget`
|
||||
* `winget install -i LLVM.LLVM --version 17.0.6 --force`
|
||||
* Ensure you select the GUI option to add LLVM to the PATH
|
||||
* LLVM 18 has a bug that causes bindings to fail to generate for ARM64. Continue using LLVM 17 until LLVM 19 comes out with [the fix](https://github.com/llvm/llvm-project/pull/93235). See [this](https://github.com/rust-lang/rust-bindgen/issues/2842) for more details.
|
||||
* To execute post-build tasks (ie. `inf2cat`, `infverif`, etc.), `cargo make` is used
|
||||
* `cargo install --locked cargo-make --no-default-features --features tls-native`
|
||||
|
||||
* Building programs with the WDK also requires being in a valid WDK environment. The recommended way to do this is to [enter an eWDK developer prompt](https://learn.microsoft.com/en-us/windows-hardware/drivers/develop/using-the-enterprise-wdk#getting-started)
|
||||
|
||||
### Adding windows-drivers-rs to Your Driver Package
|
||||
|
||||
The crates in this repository are available from [`crates.io`](https://crates.io), but take into account the current limitations outlined in [Supported Configurations](#supported-configs). If you need to support a different config, try cloning this repo and using [path dependencies](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#specifying-path-dependencies)
|
||||
|
||||
1. Create a new Cargo package with a lib crate:
|
||||
|
||||
```pwsh
|
||||
cargo new <driver_name> --lib
|
||||
```
|
||||
|
||||
1. Add dependencies on `windows-drivers-rs` crates:
|
||||
|
||||
```pwsh
|
||||
cd <driver_name>
|
||||
cargo add --build wdk-build
|
||||
cargo add wdk wdk-sys wdk-alloc wdk-panic
|
||||
```
|
||||
|
||||
1. Set the crate type to `cdylib` by adding the following snippet to `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
```
|
||||
|
||||
1. Add a wdk metadata section and configure the wdk for your use case. This also lets the cargo-make tasks know that the package is a driver and that the driver packaging steps need to run.
|
||||
|
||||
UMDF Example:
|
||||
```toml
|
||||
[package.metadata.wdk.driver-model]
|
||||
driver-type = "UMDF"
|
||||
umdf-version-major = 1
|
||||
target-umdf-version-minor = 33
|
||||
```
|
||||
|
||||
1. **For Kernel Mode crates** (ex. `KMDF` drivers, `WDM` drivers): Set crate panic strategy to `abort` in `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[profile.dev]
|
||||
panic = "abort"
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
```
|
||||
|
||||
1. Create a `build.rs` and add the following snippet:
|
||||
|
||||
```rust
|
||||
fn main() -> Result<(), wdk_build::ConfigError> {
|
||||
wdk_build::configure_wdk_binary_build()
|
||||
}
|
||||
```
|
||||
|
||||
1. **For Kernel Mode crates** (ex. `KMDF` drivers, `WDM` drivers): Mark your driver crate as `no_std` in `lib.rs`:
|
||||
|
||||
```rust
|
||||
#![no_std]
|
||||
```
|
||||
|
||||
1. **For Kernel Mode crates** (ex. `KMDF` drivers, `WDM` drivers): Add a panic handler in `lib.rs`:
|
||||
|
||||
```rust
|
||||
#[cfg(not(test))]
|
||||
extern crate wdk_panic;
|
||||
|
||||
```
|
||||
|
||||
1. **For Kernel Mode crates** (ex. `KMDF` drivers, `WDM` drivers): Add an optional global allocator in `lib.rs`:
|
||||
|
||||
```rust
|
||||
#[cfg(not(test))]
|
||||
use wdk_alloc::WdkAllocator;
|
||||
|
||||
#[cfg(not(test))]
|
||||
#[global_allocator]
|
||||
static GLOBAL_ALLOCATOR: WdkAllocator = WdkAllocator;
|
||||
```
|
||||
|
||||
This is only required if you want to be able to use the [`alloc` modules](https://doc.rust-lang.org/alloc/) in the rust standard library.
|
||||
|
||||
1. Add a DriverEntry in `lib.rs`:
|
||||
|
||||
```rust
|
||||
use wdk_sys::{
|
||||
PDRIVER_OBJECT,
|
||||
NTSTATUS,
|
||||
PCUNICODE_STRING,
|
||||
};
|
||||
|
||||
// SAFETY: "DriverEntry" is the required symbol name for Windows driver entry points.
|
||||
// No other function in this compilation unit exports this name, preventing symbol conflicts.
|
||||
#[unsafe(export_name = "DriverEntry")] // WDF expects a symbol with the name DriverEntry
|
||||
pub unsafe extern "system" fn driver_entry(
|
||||
driver: PDRIVER_OBJECT,
|
||||
registry_path: PCUNICODE_STRING,
|
||||
) -> NTSTATUS {
|
||||
0
|
||||
}
|
||||
```
|
||||
|
||||
Note: In Kernel Mode crates, you can use `driver: &mut DRIVER_OBJECT` instead of `driver: PDRIVER_OBJECT`.
|
||||
|
||||
1. Add a `Makefile.toml`:
|
||||
```toml
|
||||
extend = "target/rust-driver-makefile.toml"
|
||||
|
||||
[config]
|
||||
load_script = '''
|
||||
#!@rust
|
||||
//! ```cargo
|
||||
//! [dependencies]
|
||||
//! wdk-build = "0.5.1"
|
||||
//! ```
|
||||
#![allow(unused_doc_comments)]
|
||||
|
||||
wdk_build::cargo_make::load_rust_driver_makefile()?
|
||||
'''
|
||||
```
|
||||
|
||||
1. Add an inx file that matches the name of your `cdylib` crate.
|
||||
|
||||
1. Enable static crt linkage. One approach is to add this to your `.cargo/config.toml`:
|
||||
|
||||
```toml
|
||||
[build]
|
||||
rustflags = ["-C", "target-feature=+crt-static"]
|
||||
```
|
||||
|
||||
1. Build the driver:
|
||||
|
||||
```pwsh
|
||||
cargo make
|
||||
```
|
||||
|
||||
A signed driver package, including a `WDRLocalTestCert.cer` file, will be generated at `target/<Cargo profile>/package`. If a specific target architecture was specified, the driver package will be generated at `target/<target architecture>/<Cargo profile>/package`
|
||||
|
||||
Minimal examples of `WDM`, `KMDF`, and `UMDF` drivers can be found in the [examples directory](./examples).
|
||||
|
||||
## Cargo Make
|
||||
|
||||
[`cargo-make`](https://github.com/sagiegurari/cargo-make) is used to facilitate builds using `windows-drivers-rs`, including for executing post-build driver packaging steps.
|
||||
|
||||
To execute the default action (build and package driver):
|
||||
|
||||
`cargo make default`
|
||||
|
||||
When executing the default task, just `cargo make` make also works since the `default` task is implied.
|
||||
|
||||
### Argument Forwarding
|
||||
|
||||
`windows-drivers-rs` extends `cargo make` to forward specific arguments to the underlying `cargo` commands. In order to specify arguments to forward, they must be provided **after explicitly specifying the `cargo-make` task name** (ie. omitting the name for the `default` task is not supported).
|
||||
|
||||
#### Examples
|
||||
|
||||
For a specific target:
|
||||
|
||||
`cargo make default --target <TARGET TRIPLE>`
|
||||
|
||||
For release builds:
|
||||
|
||||
`cargo make default --release` or `cargo make default --profile release`
|
||||
|
||||
To specify specific features:
|
||||
|
||||
`cargo make default --features <FEATURES>`
|
||||
|
||||
To specify a specific rust toolchain:
|
||||
|
||||
`cargo make default +<TOOLCHAIN>`
|
||||
|
||||
To display help and see the full list of supported CLI args to forward to Cargo:
|
||||
|
||||
`cargo make help`
|
||||
|
||||
### Driver Package Signature Verification
|
||||
|
||||
The `WDK_BUILD_ENABLE_SIGNTOOL_VERIFY` [cargo-make environment variable](https://github.com/sagiegurari/cargo-make?tab=readme-ov-file#environment-variables) can be set to `true` to enable tasks that handle signature verification of the generated `.sys` and `.cat` files. `signtool verify` requires the certificate to be installed as in the `Trusted Root Certification Authorities` for this verification to function. These tasks are not enabled by default as the default behavior of `WDR` is to sign with a generated test certificate. These test certificates are typically only installed into `Trusted Root Certification Authorities` on computers dedicated to testing drivers, and not personal development machines, given the security implications of installing your own root certificates.
|
||||
|
||||
If you understand these implications, and have installed the test certificate, then you may validate the signatures as follows:
|
||||
|
||||
```
|
||||
cargo make --env WDK_BUILD_ENABLE_SIGNTOOL_VERIFY=true
|
||||
```
|
||||
|
||||
## Contact
|
||||
|
||||
* For bug reports, feature requests, and other actionable items, please use [GitHub Issues](https://github.com/microsoft/windows-drivers-rs/issues)
|
||||
* For broader questions, architectural discussions, and community engagement, please use [GitHub Discussions](https://github.com/microsoft/windows-drivers-rs/discussions)
|
||||
* For inquiries not suitable for public forums, email us at <RustWindowsDrivers@microsoft.com>
|
||||
|
||||
## Crates.io Release Policy
|
||||
|
||||
Releases to crates.io are not made after every change merged to main. Releases will only be made when requested by the community, or when the `windows-drivers-rs` team believes there is sufficient value in pushing a release.
|
||||
|
||||
## Trademark Notice
|
||||
|
||||
Trademarks This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow Microsoft’s Trademark & Brand Guidelines. Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party’s policies.
|
||||
+799
@@ -0,0 +1,799 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// License: MIT OR Apache-2.0
|
||||
|
||||
//! Build script for the `wdk-sys` crate.
|
||||
//!
|
||||
//! This parses the WDK configuration from metadata provided in the build tree,
|
||||
//! and generates the relevant bindings to WDK APIs.
|
||||
|
||||
use std::{
|
||||
env,
|
||||
fs::File,
|
||||
io::Write,
|
||||
panic,
|
||||
path::{Path, PathBuf},
|
||||
sync::LazyLock,
|
||||
thread,
|
||||
};
|
||||
|
||||
use anyhow::Context;
|
||||
use bindgen::CodegenConfig;
|
||||
use tracing::{Span, info, info_span, trace};
|
||||
use tracing_subscriber::{
|
||||
EnvFilter,
|
||||
filter::{LevelFilter, ParseError},
|
||||
};
|
||||
use wdk_build::{
|
||||
ApiSubset,
|
||||
BuilderExt,
|
||||
Config,
|
||||
ConfigError,
|
||||
DriverConfig,
|
||||
IoError,
|
||||
KmdfConfig,
|
||||
UmdfConfig,
|
||||
configure_wdk_library_build_and_then,
|
||||
};
|
||||
|
||||
const OUT_DIR_PLACEHOLDER: &str =
|
||||
"<PLACEHOLDER FOR LITERAL VALUE CONTAINING OUT_DIR OF wdk-sys CRATE>";
|
||||
const WDFFUNCTIONS_SYMBOL_NAME_PLACEHOLDER: &str =
|
||||
"<PLACEHOLDER FOR LITERAL VALUE CONTAINING WDFFUNCTIONS SYMBOL NAME>";
|
||||
const WDF_FUNCTION_COUNT_PLACEHOLDER: &str =
|
||||
"<PLACEHOLDER FOR EXPRESSION FOR NUMBER OF WDF FUNCTIONS IN `wdk_sys::WdfFunctions`";
|
||||
|
||||
const WDF_FUNCTION_COUNT_DECLARATION_EXTERNAL_SYMBOL: &str =
|
||||
"// SAFETY: `crate::WdfFunctionCount` is generated as a mutable static, but is not supposed \
|
||||
to be ever mutated by WDF.
|
||||
(unsafe { crate::WdfFunctionCount }) as usize";
|
||||
|
||||
const WDF_FUNCTION_COUNT_DECLARATION_TABLE_INDEX: &str =
|
||||
"crate::_WDFFUNCENUM::WdfFunctionTableNumEntries as usize";
|
||||
|
||||
static WDF_FUNCTION_COUNT_FUNCTION_TEMPLATE: LazyLock<String> = LazyLock::new(|| {
|
||||
format!(
|
||||
r"#[allow(clippy::must_use_candidate)]
|
||||
/// Returns the number of functions available in the WDF function table.
|
||||
/// Should not be used in public API.
|
||||
pub fn get_wdf_function_count() -> usize {{
|
||||
{WDF_FUNCTION_COUNT_PLACEHOLDER}
|
||||
}}"
|
||||
)
|
||||
});
|
||||
|
||||
static CALL_UNSAFE_WDF_BINDING_TEMPLATE: LazyLock<String> = LazyLock::new(|| {
|
||||
format!(
|
||||
r#"
|
||||
/// A procedural macro that allows WDF functions to be called by name.
|
||||
///
|
||||
/// This function parses the name of the WDF function, finds it function
|
||||
/// pointer from the WDF function table, and then calls it with the
|
||||
/// arguments passed to it
|
||||
///
|
||||
/// # Safety
|
||||
/// Function arguments must abide by any rules outlined in the WDF
|
||||
/// documentation. This macro does not perform any validation of the
|
||||
/// arguments passed to it., beyond type validation.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust, no_run
|
||||
/// use wdk_sys::*;
|
||||
///
|
||||
/// pub unsafe extern "system" fn driver_entry(
|
||||
/// driver: &mut DRIVER_OBJECT,
|
||||
/// registry_path: PCUNICODE_STRING,
|
||||
/// ) -> NTSTATUS {{
|
||||
///
|
||||
/// let mut driver_config = WDF_DRIVER_CONFIG {{
|
||||
/// Size: core::mem::size_of::<WDF_DRIVER_CONFIG>() as ULONG,
|
||||
/// ..WDF_DRIVER_CONFIG::default()
|
||||
/// }};
|
||||
/// let driver_handle_output = WDF_NO_HANDLE as *mut WDFDRIVER;
|
||||
///
|
||||
/// unsafe {{
|
||||
/// call_unsafe_wdf_function_binding!(
|
||||
/// WdfDriverCreate,
|
||||
/// driver as PDRIVER_OBJECT,
|
||||
/// registry_path,
|
||||
/// WDF_NO_OBJECT_ATTRIBUTES,
|
||||
/// &mut driver_config,
|
||||
/// driver_handle_output,
|
||||
/// )
|
||||
/// }}
|
||||
/// }}
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! call_unsafe_wdf_function_binding {{
|
||||
( $($tt:tt)* ) => {{
|
||||
$crate::__proc_macros::call_unsafe_wdf_function_binding! (
|
||||
r"{OUT_DIR_PLACEHOLDER}",
|
||||
$($tt)*
|
||||
)
|
||||
}}
|
||||
}}"#
|
||||
)
|
||||
});
|
||||
|
||||
static TEST_STUBS_TEMPLATE: LazyLock<String> = LazyLock::new(|| {
|
||||
format!(
|
||||
r"
|
||||
use crate::WDFFUNC;
|
||||
|
||||
/// Stubbed version of the symbol that `WdfFunctions` links to so that test targets will compile
|
||||
// SAFETY: Generated WDF symbol name is required for test compilation and is unique per build.
|
||||
// No other symbols in this crate export this name, preventing linker conflicts.
|
||||
#[unsafe(no_mangle)]
|
||||
pub static mut {WDFFUNCTIONS_SYMBOL_NAME_PLACEHOLDER}: *const WDFFUNC = core::ptr::null();
|
||||
",
|
||||
)
|
||||
});
|
||||
|
||||
/// Enabled API subsets based off of cargo-features
|
||||
const ENABLED_API_SUBSETS: &[ApiSubset] = &[
|
||||
ApiSubset::Base,
|
||||
ApiSubset::Wdf,
|
||||
#[cfg(feature = "gpio")]
|
||||
ApiSubset::Gpio,
|
||||
#[cfg(feature = "hid")]
|
||||
ApiSubset::Hid,
|
||||
#[cfg(feature = "parallel-ports")]
|
||||
ApiSubset::ParallelPorts,
|
||||
#[cfg(feature = "spb")]
|
||||
ApiSubset::Spb,
|
||||
#[cfg(feature = "storage")]
|
||||
ApiSubset::Storage,
|
||||
#[cfg(feature = "usb")]
|
||||
ApiSubset::Usb,
|
||||
#[cfg(feature = "iddcx")]
|
||||
ApiSubset::Iddcx,
|
||||
];
|
||||
|
||||
type GenerateFn = fn(&Path, &Config) -> Result<(), ConfigError>;
|
||||
const BINDGEN_FILE_GENERATORS_TUPLES: &[(&str, GenerateFn)] = &[
|
||||
("constants.rs", generate_constants),
|
||||
("types.rs", generate_types),
|
||||
("base.rs", generate_base),
|
||||
("wdf.rs", generate_wdf),
|
||||
#[cfg(feature = "gpio")]
|
||||
("gpio.rs", generate_gpio),
|
||||
#[cfg(feature = "hid")]
|
||||
("hid.rs", generate_hid),
|
||||
#[cfg(feature = "parallel-ports")]
|
||||
("parallel_ports.rs", generate_parallel_ports),
|
||||
#[cfg(feature = "spb")]
|
||||
("spb.rs", generate_spb),
|
||||
#[cfg(feature = "storage")]
|
||||
("storage.rs", generate_storage),
|
||||
#[cfg(feature = "usb")]
|
||||
("usb.rs", generate_usb),
|
||||
#[cfg(feature = "iddcx")]
|
||||
("iddcx.rs", generate_iddcx),
|
||||
];
|
||||
|
||||
fn initialize_tracing() -> Result<(), ParseError> {
|
||||
let tracing_filter = EnvFilter::default()
|
||||
// Show up to INFO level by default
|
||||
.add_directive(LevelFilter::INFO.into())
|
||||
// Silence various warnings originating from bindgen that are not currently actionable
|
||||
// FIXME: this currently sets the minimum log level to error for the listed modules. It
|
||||
// should actually be turning off logging (level=off) for specific warnings in these
|
||||
// modules, but a bug in the tracing crate's filtering is preventing this from working as expected. See https://github.com/tokio-rs/tracing/issues/2843.
|
||||
.add_directive("bindgen::codegen::helpers[{message}]=error".parse()?)
|
||||
.add_directive("bindgen::codegen::struct_layout[{message}]=error".parse()?)
|
||||
.add_directive("bindgen::ir::comp[{message}]=error".parse()?)
|
||||
.add_directive("bindgen::ir::context[{message}]=error".parse()?)
|
||||
.add_directive("bindgen::ir::ty[{message}]=error".parse()?)
|
||||
.add_directive("bindgen::ir::var[{message}]=error".parse()?);
|
||||
|
||||
// Allow overriding tracing behaviour via `EnvFilter::DEFAULT_ENV` env var
|
||||
let tracing_filter =
|
||||
if let Ok(filter_directives_from_env_var) = env::var(EnvFilter::DEFAULT_ENV) {
|
||||
// Append each directive from the env var to the filter
|
||||
filter_directives_from_env_var.split(',').fold(
|
||||
tracing_filter,
|
||||
|tracing_filter, filter_directive| {
|
||||
match filter_directive.parse() {
|
||||
Ok(parsed_filter_directive) => {
|
||||
tracing_filter.add_directive(parsed_filter_directive)
|
||||
}
|
||||
Err(parsing_error) => {
|
||||
// Must use eprintln!() here as tracing is not yet initialized
|
||||
eprintln!(
|
||||
"Skipping filter directive, {}, which failed to be parsed from {} \
|
||||
obtained from {} with the following error: {}",
|
||||
filter_directive,
|
||||
filter_directives_from_env_var,
|
||||
EnvFilter::DEFAULT_ENV,
|
||||
parsing_error
|
||||
);
|
||||
tracing_filter
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
} else {
|
||||
tracing_filter
|
||||
};
|
||||
|
||||
tracing_subscriber::fmt()
|
||||
.pretty()
|
||||
.with_env_filter(tracing_filter)
|
||||
.with_span_events(tracing_subscriber::fmt::format::FmtSpan::CLOSE)
|
||||
.init();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn generate_constants(out_path: &Path, config: &Config) -> Result<(), ConfigError> {
|
||||
info!("Generating bindings to WDK: constants.rs");
|
||||
|
||||
let header_contents = config.bindgen_header_contents(ENABLED_API_SUBSETS.iter().copied())?;
|
||||
trace!(header_contents = ?header_contents);
|
||||
|
||||
let bindgen_builder = bindgen::Builder::wdk_default(config)?
|
||||
.with_codegen_config(CodegenConfig::VARS)
|
||||
.header_contents("constants-input.h", &header_contents);
|
||||
trace!(bindgen_builder = ?bindgen_builder);
|
||||
|
||||
let output_file_path = out_path.join("constants.rs");
|
||||
Ok(bindgen_builder
|
||||
.generate()
|
||||
.expect("Bindings should succeed to generate")
|
||||
.write_to_file(&output_file_path)
|
||||
.map_err(|source| IoError::with_path(output_file_path, source))?)
|
||||
}
|
||||
|
||||
fn generate_types(out_path: &Path, config: &Config) -> Result<(), ConfigError> {
|
||||
info!("Generating bindings to WDK: types.rs");
|
||||
|
||||
let header_contents = config.bindgen_header_contents(ENABLED_API_SUBSETS.iter().copied())?;
|
||||
trace!(header_contents = ?header_contents);
|
||||
|
||||
let bindgen_builder = bindgen::Builder::wdk_default(config)?
|
||||
.with_codegen_config(CodegenConfig::TYPES)
|
||||
.header_contents("types-input.h", &header_contents);
|
||||
trace!(bindgen_builder = ?bindgen_builder);
|
||||
|
||||
let output_file_path = out_path.join("types.rs");
|
||||
Ok(bindgen_builder
|
||||
.generate()
|
||||
.expect("Bindings should succeed to generate")
|
||||
.write_to_file(&output_file_path)
|
||||
.map_err(|source| IoError::with_path(output_file_path, source))?)
|
||||
}
|
||||
|
||||
fn generate_base(out_path: &Path, config: &Config) -> Result<(), ConfigError> {
|
||||
let outfile_name = match &config.driver_config {
|
||||
DriverConfig::Wdm | DriverConfig::Kmdf(_) => "ntddk",
|
||||
DriverConfig::Umdf(_) => "windows",
|
||||
};
|
||||
info!("Generating bindings to WDK: {outfile_name}.rs");
|
||||
|
||||
let header_contents = config.bindgen_header_contents([ApiSubset::Base])?;
|
||||
trace!(header_contents = ?header_contents);
|
||||
|
||||
let bindgen_builder = bindgen::Builder::wdk_default(config)?
|
||||
.with_codegen_config((CodegenConfig::TYPES | CodegenConfig::VARS).complement())
|
||||
.header_contents(&format!("{outfile_name}-input.h"), &header_contents);
|
||||
trace!(bindgen_builder = ?bindgen_builder);
|
||||
|
||||
let output_file_path = out_path.join(format!("{outfile_name}.rs"));
|
||||
Ok(bindgen_builder
|
||||
.generate()
|
||||
.expect("Bindings should succeed to generate")
|
||||
.write_to_file(&output_file_path)
|
||||
.map_err(|source| IoError::with_path(output_file_path, source))?)
|
||||
}
|
||||
|
||||
fn generate_wdf(out_path: &Path, config: &Config) -> Result<(), ConfigError> {
|
||||
if let DriverConfig::Kmdf(_) | DriverConfig::Umdf(_) = config.driver_config {
|
||||
info!("Generating bindings to WDK: wdf.rs");
|
||||
|
||||
let header_contents = config.bindgen_header_contents([ApiSubset::Base, ApiSubset::Wdf])?;
|
||||
trace!(header_contents = ?header_contents);
|
||||
|
||||
let bindgen_builder = bindgen::Builder::wdk_default(config)?
|
||||
.with_codegen_config((CodegenConfig::TYPES | CodegenConfig::VARS).complement())
|
||||
.header_contents("wdf-input.h", &header_contents)
|
||||
// Only generate for files that are prefixed with (case-insensitive) wdf (ie.
|
||||
// /some/path/WdfSomeHeader.h), to prevent duplication of code in ntddk.rs
|
||||
.allowlist_file("(?i).*wdf.*");
|
||||
trace!(bindgen_builder = ?bindgen_builder);
|
||||
|
||||
let output_file_path = out_path.join("wdf.rs");
|
||||
Ok(bindgen_builder
|
||||
.generate()
|
||||
.expect("Bindings should succeed to generate")
|
||||
.write_to_file(&output_file_path)
|
||||
.map_err(|source| IoError::with_path(output_file_path, source))?)
|
||||
} else {
|
||||
info!(
|
||||
"Skipping wdf.rs generation since driver_config is {:#?}",
|
||||
config.driver_config
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpio")]
|
||||
fn generate_gpio(out_path: &Path, config: &Config) -> Result<(), ConfigError> {
|
||||
info!("Generating bindings to WDK: gpio.rs");
|
||||
|
||||
let header_contents =
|
||||
config.bindgen_header_contents([ApiSubset::Base, ApiSubset::Wdf, ApiSubset::Gpio])?;
|
||||
trace!(header_contents = ?header_contents);
|
||||
|
||||
let bindgen_builder = {
|
||||
let mut builder = bindgen::Builder::wdk_default(config)?
|
||||
.with_codegen_config((CodegenConfig::TYPES | CodegenConfig::VARS).complement())
|
||||
.header_contents("gpio-input.h", &header_contents);
|
||||
|
||||
// Only allowlist files in the gpio-specific files to avoid
|
||||
// duplicate definitions
|
||||
for header_file in config.headers(ApiSubset::Gpio)? {
|
||||
builder = builder.allowlist_file(format!("(?i).*{header_file}.*"));
|
||||
}
|
||||
builder
|
||||
};
|
||||
trace!(bindgen_builder = ?bindgen_builder);
|
||||
|
||||
let output_file_path = out_path.join("gpio.rs");
|
||||
Ok(bindgen_builder
|
||||
.generate()
|
||||
.expect("Bindings should succeed to generate")
|
||||
.write_to_file(&output_file_path)
|
||||
.map_err(|source| IoError::with_path(output_file_path, source))?)
|
||||
}
|
||||
|
||||
#[cfg(feature = "iddcx")]
|
||||
fn generate_iddcx(out_path: &Path, config: &Config) -> Result<(), ConfigError> {
|
||||
info!("Generating bindings to WDK: iddcx.rs");
|
||||
|
||||
let header_contents =
|
||||
config.bindgen_header_contents([ApiSubset::Base, ApiSubset::Wdf, ApiSubset::Iddcx])?;
|
||||
trace!(header_contents = ?header_contents);
|
||||
|
||||
let bindgen_builder = {
|
||||
bindgen::Builder::wdk_default(config)?
|
||||
.with_codegen_config((CodegenConfig::TYPES | CodegenConfig::VARS).complement())
|
||||
.header_contents("iddcx-input.h", &header_contents)
|
||||
// Allowlist by the "iddcx" path component (separator-agnostic) so ONLY IddCx items are
|
||||
// emitted; the WDF/Win/DXGI types they reference RESOLVE to the shared base/wdf bindings
|
||||
// instead of being redefined.
|
||||
.allowlist_file("(?i).*iddcx.*")
|
||||
};
|
||||
trace!(bindgen_builder = ?bindgen_builder);
|
||||
|
||||
let output_file_path = out_path.join("iddcx.rs");
|
||||
Ok(bindgen_builder
|
||||
.generate()
|
||||
.expect("Bindings should succeed to generate")
|
||||
.write_to_file(&output_file_path)
|
||||
.map_err(|source| IoError::with_path(output_file_path, source))?)
|
||||
}
|
||||
|
||||
#[cfg(feature = "hid")]
|
||||
fn generate_hid(out_path: &Path, config: &Config) -> Result<(), ConfigError> {
|
||||
info!("Generating bindings to WDK: hid.rs");
|
||||
|
||||
let header_contents =
|
||||
config.bindgen_header_contents([ApiSubset::Base, ApiSubset::Wdf, ApiSubset::Hid])?;
|
||||
trace!(header_contents = ?header_contents);
|
||||
|
||||
let bindgen_builder = {
|
||||
let mut builder = bindgen::Builder::wdk_default(config)?
|
||||
.with_codegen_config((CodegenConfig::TYPES | CodegenConfig::VARS).complement())
|
||||
.header_contents("hid-input.h", &header_contents);
|
||||
|
||||
// Only allowlist files in the hid-specific files to avoid
|
||||
// duplicate definitions
|
||||
for header_file in config.headers(ApiSubset::Hid)? {
|
||||
builder = builder.allowlist_file(format!("(?i).*{header_file}.*"));
|
||||
}
|
||||
builder
|
||||
};
|
||||
trace!(bindgen_builder = ?bindgen_builder);
|
||||
|
||||
let output_file_path = out_path.join("hid.rs");
|
||||
Ok(bindgen_builder
|
||||
.generate()
|
||||
.expect("Bindings should succeed to generate")
|
||||
.write_to_file(&output_file_path)
|
||||
.map_err(|source| IoError::with_path(output_file_path, source))?)
|
||||
}
|
||||
|
||||
#[cfg(feature = "parallel-ports")]
|
||||
fn generate_parallel_ports(out_path: &Path, config: &Config) -> Result<(), ConfigError> {
|
||||
info!("Generating bindings to WDK: parallel_ports.rs");
|
||||
|
||||
let header_contents = config.bindgen_header_contents([
|
||||
ApiSubset::Base,
|
||||
ApiSubset::Wdf,
|
||||
ApiSubset::ParallelPorts,
|
||||
])?;
|
||||
trace!(header_contents = ?header_contents);
|
||||
|
||||
let bindgen_builder = {
|
||||
let mut builder = bindgen::Builder::wdk_default(config)?
|
||||
.with_codegen_config((CodegenConfig::TYPES | CodegenConfig::VARS).complement())
|
||||
.header_contents("parallel-ports-input.h", &header_contents);
|
||||
|
||||
// Only allowlist files in the parallel-ports-specific files to
|
||||
// avoid duplicate definitions
|
||||
for header_file in config.headers(ApiSubset::ParallelPorts)? {
|
||||
builder = builder.allowlist_file(format!("(?i).*{header_file}.*"));
|
||||
}
|
||||
builder
|
||||
};
|
||||
trace!(bindgen_builder = ?bindgen_builder);
|
||||
|
||||
let output_file_path = out_path.join("parallel_ports.rs");
|
||||
Ok(bindgen_builder
|
||||
.generate()
|
||||
.expect("Bindings should succeed to generate")
|
||||
.write_to_file(&output_file_path)
|
||||
.map_err(|source| IoError::with_path(output_file_path, source))?)
|
||||
}
|
||||
|
||||
#[cfg(feature = "spb")]
|
||||
fn generate_spb(out_path: &Path, config: &Config) -> Result<(), ConfigError> {
|
||||
info!("Generating bindings to WDK: spb.rs");
|
||||
|
||||
let header_contents =
|
||||
config.bindgen_header_contents([ApiSubset::Base, ApiSubset::Wdf, ApiSubset::Spb])?;
|
||||
trace!(header_contents = ?header_contents);
|
||||
|
||||
let bindgen_builder = {
|
||||
let mut builder = bindgen::Builder::wdk_default(config)?
|
||||
.with_codegen_config((CodegenConfig::TYPES | CodegenConfig::VARS).complement())
|
||||
.header_contents("spb-input.h", &header_contents);
|
||||
|
||||
// Only allowlist files in the spb-specific files to avoid
|
||||
// duplicate definitions
|
||||
for header_file in config.headers(ApiSubset::Spb)? {
|
||||
builder = builder.allowlist_file(format!("(?i).*{header_file}.*"));
|
||||
}
|
||||
builder
|
||||
};
|
||||
trace!(bindgen_builder = ?bindgen_builder);
|
||||
|
||||
let output_file_path = out_path.join("spb.rs");
|
||||
Ok(bindgen_builder
|
||||
.generate()
|
||||
.expect("Bindings should succeed to generate")
|
||||
.write_to_file(&output_file_path)
|
||||
.map_err(|source| IoError::with_path(output_file_path, source))?)
|
||||
}
|
||||
|
||||
#[cfg(feature = "storage")]
|
||||
fn generate_storage(out_path: &Path, config: &Config) -> Result<(), ConfigError> {
|
||||
info!("Generating bindings to WDK: storage.rs");
|
||||
|
||||
let header_contents =
|
||||
config.bindgen_header_contents([ApiSubset::Base, ApiSubset::Wdf, ApiSubset::Storage])?;
|
||||
trace!(header_contents = ?header_contents);
|
||||
|
||||
let bindgen_builder = {
|
||||
let mut builder = bindgen::Builder::wdk_default(config)?
|
||||
.with_codegen_config((CodegenConfig::TYPES | CodegenConfig::VARS).complement())
|
||||
.header_contents("storage-input.h", &header_contents);
|
||||
|
||||
// Only allowlist files in the storage-specific files to avoid
|
||||
// duplicate definitions
|
||||
for header_file in config.headers(ApiSubset::Storage)? {
|
||||
builder = builder.allowlist_file(format!("(?i).*{header_file}.*"));
|
||||
}
|
||||
builder
|
||||
};
|
||||
trace!(bindgen_builder = ?bindgen_builder);
|
||||
|
||||
let output_file_path = out_path.join("storage.rs");
|
||||
Ok(bindgen_builder
|
||||
.generate()
|
||||
.expect("Bindings should succeed to generate")
|
||||
.write_to_file(&output_file_path)
|
||||
.map_err(|source| IoError::with_path(output_file_path, source))?)
|
||||
}
|
||||
|
||||
#[cfg(feature = "usb")]
|
||||
fn generate_usb(out_path: &Path, config: &Config) -> Result<(), ConfigError> {
|
||||
info!("Generating bindings to WDK: usb.rs");
|
||||
|
||||
let header_contents =
|
||||
config.bindgen_header_contents([ApiSubset::Base, ApiSubset::Wdf, ApiSubset::Usb])?;
|
||||
trace!(header_contents = ?header_contents);
|
||||
|
||||
let bindgen_builder = {
|
||||
let mut builder = bindgen::Builder::wdk_default(config)?
|
||||
.with_codegen_config((CodegenConfig::TYPES | CodegenConfig::VARS).complement())
|
||||
.header_contents("usb-input.h", &header_contents);
|
||||
|
||||
// Only allowlist files in the usb-specific files to avoid
|
||||
// duplicate definitions
|
||||
for header_file in config.headers(ApiSubset::Usb)? {
|
||||
builder = builder.allowlist_file(format!("(?i).*{header_file}.*"));
|
||||
}
|
||||
builder
|
||||
};
|
||||
trace!(bindgen_builder = ?bindgen_builder);
|
||||
|
||||
let output_file_path = out_path.join("usb.rs");
|
||||
Ok(bindgen_builder
|
||||
.generate()
|
||||
.expect("Bindings should succeed to generate")
|
||||
.write_to_file(&output_file_path)
|
||||
.map_err(|source| IoError::with_path(output_file_path, source))?)
|
||||
}
|
||||
|
||||
/// Generates a `wdf_function_count.rs` file in `OUT_DIR` which contains the
|
||||
/// definition of the function `get_wdf_function_count()`. This is required to
|
||||
/// be generated here since the size of the table is derived from either a
|
||||
/// global symbol that newer WDF versions expose, or an enum that older versions
|
||||
/// use.
|
||||
fn generate_wdf_function_count(out_path: &Path, config: &Config) -> Result<(), IoError> {
|
||||
const MINIMUM_MINOR_VERSION_TO_GENERATE_WDF_FUNCTION_COUNT: u8 = 25;
|
||||
|
||||
let generated_file_path = out_path.join("wdf_function_count.rs");
|
||||
let mut generated_file = File::create(&generated_file_path)
|
||||
.map_err(|source| IoError::with_path(&generated_file_path, source))?;
|
||||
|
||||
let is_wdf_function_count_generated = match *config {
|
||||
Config {
|
||||
driver_config:
|
||||
DriverConfig::Kmdf(KmdfConfig {
|
||||
kmdf_version_major,
|
||||
target_kmdf_version_minor,
|
||||
..
|
||||
}),
|
||||
..
|
||||
} => {
|
||||
kmdf_version_major >= 1
|
||||
&& target_kmdf_version_minor >= MINIMUM_MINOR_VERSION_TO_GENERATE_WDF_FUNCTION_COUNT
|
||||
}
|
||||
|
||||
Config {
|
||||
driver_config:
|
||||
DriverConfig::Umdf(UmdfConfig {
|
||||
umdf_version_major,
|
||||
target_umdf_version_minor,
|
||||
..
|
||||
}),
|
||||
..
|
||||
} => {
|
||||
umdf_version_major >= 2
|
||||
&& target_umdf_version_minor >= MINIMUM_MINOR_VERSION_TO_GENERATE_WDF_FUNCTION_COUNT
|
||||
}
|
||||
|
||||
_ => {
|
||||
unreachable!(
|
||||
"generate_wdf_function_table is only called with WDF driver configurations"
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let wdf_function_table_count_snippet = WDF_FUNCTION_COUNT_FUNCTION_TEMPLATE.replace(
|
||||
WDF_FUNCTION_COUNT_PLACEHOLDER,
|
||||
if is_wdf_function_count_generated {
|
||||
WDF_FUNCTION_COUNT_DECLARATION_EXTERNAL_SYMBOL
|
||||
} else {
|
||||
WDF_FUNCTION_COUNT_DECLARATION_TABLE_INDEX
|
||||
},
|
||||
);
|
||||
|
||||
generated_file
|
||||
.write_all(wdf_function_table_count_snippet.as_bytes())
|
||||
.map_err(|source| IoError::with_path(generated_file_path, source))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Generates a `macros.rs` file in `OUT_DIR` which contains a
|
||||
/// `call_unsafe_wdf_function_binding!` macro that redirects to the
|
||||
/// `wdk_macros::call_unsafe_wdf_function_binding` `proc_macro` . This is
|
||||
/// required in order to add an additional argument with the path to the file
|
||||
/// containing generated types. There is currently no other way to pass
|
||||
/// `OUT_DIR` of `wdk-sys` to the `proc_macro`.
|
||||
fn generate_call_unsafe_wdf_function_binding_macro(out_path: &Path) -> Result<(), IoError> {
|
||||
let generated_file_path = out_path.join("call_unsafe_wdf_function_binding.rs");
|
||||
let mut generated_file = File::create(&generated_file_path)
|
||||
.map_err(|source| IoError::with_path(&generated_file_path, source))?;
|
||||
generated_file
|
||||
.write_all(
|
||||
CALL_UNSAFE_WDF_BINDING_TEMPLATE
|
||||
.replace(
|
||||
OUT_DIR_PLACEHOLDER,
|
||||
out_path.join("types.rs").to_str().expect(
|
||||
"path to file with generated type information should successfully convert \
|
||||
to a str",
|
||||
),
|
||||
)
|
||||
.as_bytes(),
|
||||
)
|
||||
.map_err(|source| IoError::with_path(generated_file_path, source))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Generates a `test_stubs.rs` file in `OUT_DIR` which contains stubs required
|
||||
/// for tests to compile. This should only generate the stubs whose names are
|
||||
/// dependent on the WDK configuration, and would otherwise be impossible to
|
||||
/// just include in `src/test_stubs.rs` directly.
|
||||
fn generate_test_stubs(out_path: &Path, config: &Config) -> Result<(), IoError> {
|
||||
let stubs_file_path = out_path.join("test_stubs.rs");
|
||||
let mut stubs_file = File::create(&stubs_file_path)
|
||||
.map_err(|source| IoError::with_path(&stubs_file_path, source))?;
|
||||
stubs_file
|
||||
.write_all(
|
||||
TEST_STUBS_TEMPLATE
|
||||
.replace(
|
||||
WDFFUNCTIONS_SYMBOL_NAME_PLACEHOLDER,
|
||||
&config.compute_wdffunctions_symbol_name().expect(
|
||||
"KMDF and UMDF configs should always have a computable WdfFunctions \
|
||||
symbol name",
|
||||
),
|
||||
)
|
||||
.as_bytes(),
|
||||
)
|
||||
.map_err(|source| IoError::with_path(stubs_file_path, source))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Starts parallel bindgen tasks for generating binding files.
|
||||
fn start_bindgen_tasks<'scope>(
|
||||
thread_scope: &'scope thread::Scope<'scope, '_>,
|
||||
out_path: &'scope Path,
|
||||
config: &'scope Config,
|
||||
thread_join_handles: &mut Vec<thread::ScopedJoinHandle<'scope, Result<(), ConfigError>>>,
|
||||
) {
|
||||
info_span!("bindgen generation").in_scope(|| {
|
||||
for (file_name, generate_function) in BINDGEN_FILE_GENERATORS_TUPLES {
|
||||
let current_span = Span::current();
|
||||
|
||||
thread_join_handles.push(
|
||||
thread::Builder::new()
|
||||
.name(format!("bindgen {file_name} generator"))
|
||||
.spawn_scoped(thread_scope, move || {
|
||||
// Parent span must be manually set since spans do not persist across thread boundaries: https://github.com/tokio-rs/tracing/issues/1391
|
||||
info_span!(parent: ¤t_span, "worker thread", generated_file_name = file_name).in_scope(|| generate_function(out_path, config))
|
||||
})
|
||||
.expect("Scoped Thread should spawn successfully"),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Starts a task that compiles a C shim to expose WDF symbols hidden by
|
||||
/// `__declspec(selectany)`.
|
||||
fn start_wdf_symbol_export_tasks<'scope>(
|
||||
thread_scope: &'scope thread::Scope<'scope, '_>,
|
||||
out_path: &'scope Path,
|
||||
config: &'scope Config,
|
||||
thread_join_handles: &mut Vec<thread::ScopedJoinHandle<'scope, Result<(), ConfigError>>>,
|
||||
) {
|
||||
let current_span = Span::current();
|
||||
|
||||
// Compile a c library to expose symbols that are not exposed because of
|
||||
// __declspec(selectany)
|
||||
thread_join_handles.push(
|
||||
thread::Builder::new()
|
||||
.name("wdf.c cc compilation".to_string())
|
||||
.spawn_scoped(thread_scope, move || {
|
||||
// Parent span must be manually set since spans do not persist across thread boundaries: https://github.com/tokio-rs/tracing/issues/1391
|
||||
info_span!(parent: current_span, "cc").in_scope(|| {
|
||||
info!("Compiling wdf.c");
|
||||
|
||||
// Write all included headers into wdf.c (existing file, if present
|
||||
// (i.e. incremental rebuild), is truncated)
|
||||
let wdf_c_file_path = out_path.join("wdf.c");
|
||||
{
|
||||
let mut wdf_c_file = File::create(&wdf_c_file_path)
|
||||
.map_err(|source| IoError::with_path(&wdf_c_file_path, source))?;
|
||||
wdf_c_file
|
||||
.write_all(
|
||||
config
|
||||
// This should include the entirety of the `ENABLED_API_SUBSETS`, but this is currently blocked by issues with mutually exclusive headers: https://github.com/microsoft/windows-drivers-rs/issues/515
|
||||
.bindgen_header_contents([
|
||||
ApiSubset::Base,
|
||||
ApiSubset::Wdf,
|
||||
#[cfg(feature = "hid")]
|
||||
ApiSubset::Hid,
|
||||
#[cfg(feature = "spb")]
|
||||
ApiSubset::Spb,
|
||||
])?
|
||||
.as_bytes(),
|
||||
)
|
||||
.map_err(|source| IoError::with_path(&wdf_c_file_path, source))?;
|
||||
|
||||
// Explicitly sync_all to surface any IO errors (File::drop
|
||||
// silently ignores close errors)
|
||||
wdf_c_file
|
||||
.sync_all()
|
||||
.map_err(|source| IoError::with_path(&wdf_c_file_path, source))?;
|
||||
}
|
||||
|
||||
let mut cc_builder = cc::Build::new();
|
||||
for (key, value) in config.preprocessor_definitions() {
|
||||
cc_builder.define(&key, value.as_deref());
|
||||
}
|
||||
|
||||
cc_builder
|
||||
.includes(config.include_paths()?)
|
||||
.file(wdf_c_file_path)
|
||||
.compile("wdf");
|
||||
Ok::<(), ConfigError>(())
|
||||
})
|
||||
})
|
||||
.expect("Scoped Thread should spawn successfully"),
|
||||
);
|
||||
}
|
||||
|
||||
/// Starts generation/compilation tasks for WDF-specific artifacts for driver
|
||||
/// configurations.
|
||||
///
|
||||
/// Uses the `start_*_tasks` naming convention: dispatches work to scoped
|
||||
/// threads and returns after scheduling.
|
||||
fn start_wdf_artifact_tasks<'scope>(
|
||||
thread_scope: &'scope thread::Scope<'scope, '_>,
|
||||
out_path: &'scope Path,
|
||||
config: &'scope Config,
|
||||
thread_join_handles: &mut Vec<thread::ScopedJoinHandle<'scope, Result<(), ConfigError>>>,
|
||||
) -> anyhow::Result<()> {
|
||||
if let DriverConfig::Kmdf(_) | DriverConfig::Umdf(_) = config.driver_config {
|
||||
start_wdf_symbol_export_tasks(thread_scope, out_path, config, thread_join_handles);
|
||||
|
||||
info_span!("wdf_function_count.rs generation")
|
||||
.in_scope(|| generate_wdf_function_count(out_path, config))?;
|
||||
|
||||
info_span!("call_unsafe_wdf_function_binding.rs generation")
|
||||
.in_scope(|| generate_call_unsafe_wdf_function_binding_macro(out_path))?;
|
||||
|
||||
info_span!("test_stubs.rs generation")
|
||||
.in_scope(|| generate_test_stubs(out_path, config))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Joins all worker threads and collects their results
|
||||
fn join_worker_threads(
|
||||
thread_join_handles: Vec<thread::ScopedJoinHandle<'_, Result<(), ConfigError>>>,
|
||||
) -> anyhow::Result<()> {
|
||||
for join_handle in thread_join_handles {
|
||||
let thread_name = join_handle.thread().name().unwrap_or("UNNAMED").to_string();
|
||||
|
||||
match join_handle.join() {
|
||||
// Forward panics to the main thread
|
||||
Err(panic_payload) => {
|
||||
panic::resume_unwind(panic_payload);
|
||||
}
|
||||
|
||||
Ok(thread_result) => {
|
||||
thread_result.with_context(|| {
|
||||
format!(r#""{thread_name}" thread failed to exit successfully"#)
|
||||
})?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
initialize_tracing()?;
|
||||
|
||||
configure_wdk_library_build_and_then(|config| {
|
||||
let out_path = PathBuf::from(
|
||||
env::var("OUT_DIR").expect("OUT_DIR should be exist in Cargo build environment"),
|
||||
);
|
||||
|
||||
thread::scope(|thread_scope| {
|
||||
let mut thread_join_handles = Vec::new();
|
||||
|
||||
start_bindgen_tasks(thread_scope, &out_path, &config, &mut thread_join_handles);
|
||||
start_wdf_artifact_tasks(thread_scope, &out_path, &config, &mut thread_join_handles)?;
|
||||
|
||||
join_worker_threads(thread_join_handles)
|
||||
})?;
|
||||
|
||||
Ok::<(), anyhow::Error>(())
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// License: MIT OR Apache-2.0
|
||||
|
||||
//! Direct FFI bindings to GPIO APIs from the Windows Driver Kit (WDK)
|
||||
//!
|
||||
//! This module contains all bindings to functions, constants, methods,
|
||||
//! constructors and destructors in the following headers: `gpio.h`,
|
||||
//! `gpioclx.h`. Types are not included in this module, but are available in the
|
||||
//! top-level `wdk_sys` module.
|
||||
|
||||
#[allow(
|
||||
missing_docs,
|
||||
reason = "most items in the WDK headers have no inline documentation, so bindgen is unable to \
|
||||
generate documentation for their bindings"
|
||||
)]
|
||||
mod bindings {
|
||||
#[allow(
|
||||
clippy::wildcard_imports,
|
||||
reason = "the underlying c code relies on all type definitions being in scope, which \
|
||||
results in the bindgen generated code relying on the generated types being in \
|
||||
scope as well"
|
||||
)]
|
||||
#[allow(
|
||||
unused_imports,
|
||||
reason = "in certain versions of the WDK, there are no functions related to GPIO that can \
|
||||
be generated by bindgen, so these types are unused"
|
||||
)]
|
||||
use crate::types::*;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/gpio.rs"));
|
||||
}
|
||||
#[allow(
|
||||
unused_imports,
|
||||
reason = "in certain versions of the WDK, there are no functions related to GPIO that can be \
|
||||
generated by bindgen, so the `bindings` module is empty"
|
||||
)]
|
||||
pub use bindings::*;
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// License: MIT OR Apache-2.0
|
||||
|
||||
//! Direct FFI bindings to HID APIs from the Windows Driver Kit (WDK)
|
||||
//!
|
||||
//! This module contains all bindings to functions, constants, methods,
|
||||
//! constructors and destructors in the following headers: `hidpddi.h`,
|
||||
//! `hidport.h`, `HidSpiCx/1.0/hidspicx.h`, `kbdmou.h`, `ntdd8042.h`,
|
||||
//! `hidclass.h`, `hidsdi.h`, `hidpi.h`, `vhf.h`. Types are not included in this
|
||||
//! module, but are available in the top-level `wdk_sys` module.
|
||||
|
||||
#[allow(
|
||||
missing_docs,
|
||||
reason = "most items in the WDK headers have no inline documentation, so bindgen is unable to \
|
||||
generate documentation for their bindings"
|
||||
)]
|
||||
mod bindings {
|
||||
#[allow(
|
||||
clippy::wildcard_imports,
|
||||
reason = "the underlying c code relies on all type definitions being in scope, which \
|
||||
results in the bindgen generated code relying on the generated types being in \
|
||||
scope as well"
|
||||
)]
|
||||
use crate::types::*;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/hid.rs"));
|
||||
}
|
||||
pub use bindings::*;
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// License: MIT OR Apache-2.0
|
||||
|
||||
//! Direct FFI bindings to IddCx APIs from the Windows Driver Kit (WDK)
|
||||
//!
|
||||
//! This module contains all bindings to functions, constants, methods,
|
||||
//! constructors and destructors in the following headers: `iddcx/1.10/IddCx.h`. Types are not included in this module, but are available in the
|
||||
//! top-level `wdk_sys` module.
|
||||
|
||||
#[allow(
|
||||
missing_docs,
|
||||
reason = "most items in the WDK headers have no inline documentation, so bindgen is unable to \
|
||||
generate documentation for their bindings"
|
||||
)]
|
||||
mod bindings {
|
||||
#[allow(
|
||||
clippy::wildcard_imports,
|
||||
reason = "the underlying c code relies on all type definitions being in scope, which \
|
||||
results in the bindgen generated code relying on the generated types being in \
|
||||
scope as well"
|
||||
)]
|
||||
#[allow(
|
||||
unused_imports,
|
||||
reason = "in certain versions of the WDK, there are no functions related to IddCx that can \
|
||||
be generated by bindgen, so these types are unused"
|
||||
)]
|
||||
use crate::types::*;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/iddcx.rs"));
|
||||
}
|
||||
#[allow(
|
||||
unused_imports,
|
||||
reason = "in certain versions of the WDK, there are no functions related to IddCx that can be \
|
||||
generated by bindgen, so the `bindings` module is empty"
|
||||
)]
|
||||
pub use bindings::*;
|
||||
+242
@@ -0,0 +1,242 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// License: MIT OR Apache-2.0
|
||||
|
||||
//! Direct bindings to APIs available in the Windows Development Kit (WDK)
|
||||
|
||||
#![no_std]
|
||||
|
||||
#[cfg(any(
|
||||
driver_model__driver_type = "WDM",
|
||||
driver_model__driver_type = "KMDF",
|
||||
driver_model__driver_type = "UMDF"
|
||||
))]
|
||||
#[doc(hidden)]
|
||||
pub use wdk_macros as __proc_macros;
|
||||
|
||||
#[cfg(any(
|
||||
driver_model__driver_type = "WDM",
|
||||
driver_model__driver_type = "KMDF",
|
||||
driver_model__driver_type = "UMDF"
|
||||
))]
|
||||
pub use crate::{constants::*, types::*};
|
||||
|
||||
#[cfg(any(driver_model__driver_type = "WDM", driver_model__driver_type = "KMDF"))]
|
||||
pub mod ntddk;
|
||||
|
||||
#[cfg(driver_model__driver_type = "UMDF")]
|
||||
pub mod windows;
|
||||
|
||||
#[cfg(any(driver_model__driver_type = "KMDF", driver_model__driver_type = "UMDF"))]
|
||||
pub mod wdf;
|
||||
|
||||
#[cfg(all(
|
||||
any(
|
||||
driver_model__driver_type = "WDM",
|
||||
driver_model__driver_type = "KMDF",
|
||||
driver_model__driver_type = "UMDF"
|
||||
),
|
||||
feature = "gpio"
|
||||
))]
|
||||
pub mod gpio;
|
||||
|
||||
#[cfg(all(
|
||||
any(
|
||||
driver_model__driver_type = "WDM",
|
||||
driver_model__driver_type = "KMDF",
|
||||
driver_model__driver_type = "UMDF"
|
||||
),
|
||||
feature = "hid"
|
||||
))]
|
||||
pub mod hid;
|
||||
|
||||
#[cfg(all(
|
||||
any(
|
||||
driver_model__driver_type = "WDM",
|
||||
driver_model__driver_type = "KMDF",
|
||||
driver_model__driver_type = "UMDF"
|
||||
),
|
||||
feature = "parallel-ports"
|
||||
))]
|
||||
pub mod parallel_ports;
|
||||
|
||||
#[cfg(all(
|
||||
any(
|
||||
driver_model__driver_type = "WDM",
|
||||
driver_model__driver_type = "KMDF",
|
||||
driver_model__driver_type = "UMDF"
|
||||
),
|
||||
feature = "spb"
|
||||
))]
|
||||
pub mod spb;
|
||||
|
||||
#[cfg(all(
|
||||
any(
|
||||
driver_model__driver_type = "WDM",
|
||||
driver_model__driver_type = "KMDF",
|
||||
driver_model__driver_type = "UMDF"
|
||||
),
|
||||
feature = "storage"
|
||||
))]
|
||||
pub mod storage;
|
||||
|
||||
#[cfg(all(
|
||||
any(
|
||||
driver_model__driver_type = "WDM",
|
||||
driver_model__driver_type = "KMDF",
|
||||
driver_model__driver_type = "UMDF"
|
||||
),
|
||||
feature = "usb"
|
||||
))]
|
||||
pub mod usb;
|
||||
|
||||
#[cfg(all(driver_model__driver_type = "UMDF", feature = "iddcx"))]
|
||||
pub mod iddcx;
|
||||
|
||||
#[cfg(feature = "test-stubs")]
|
||||
pub mod test_stubs;
|
||||
|
||||
#[cfg(any(
|
||||
driver_model__driver_type = "WDM",
|
||||
driver_model__driver_type = "KMDF",
|
||||
driver_model__driver_type = "UMDF"
|
||||
))]
|
||||
mod constants;
|
||||
#[cfg(any(
|
||||
driver_model__driver_type = "WDM",
|
||||
driver_model__driver_type = "KMDF",
|
||||
driver_model__driver_type = "UMDF"
|
||||
))]
|
||||
mod types;
|
||||
|
||||
#[cfg(any(
|
||||
driver_model__driver_type = "WDM",
|
||||
driver_model__driver_type = "KMDF",
|
||||
driver_model__driver_type = "UMDF"
|
||||
))]
|
||||
mod macros;
|
||||
|
||||
// This is fine because we don't actually have any floating point instruction in
|
||||
// our binary, thanks to our target defining soft-floats. fltused symbol is
|
||||
// necessary due to LLVM being too eager to set it: it checks the LLVM IR for
|
||||
// floating point instructions - even if soft-float is enabled!
|
||||
#[allow(missing_docs)]
|
||||
// SAFETY: _fltused is a required Windows linker symbol for floating point support.
|
||||
// No other symbols in this crate export this name, preventing linker conflicts.
|
||||
#[unsafe(no_mangle)]
|
||||
pub static _fltused: () = ();
|
||||
|
||||
// FIXME: Is there any way to avoid these stubs? See https://github.com/rust-lang/rust/issues/101134
|
||||
#[cfg(panic = "abort")]
|
||||
#[allow(missing_docs)]
|
||||
// SAFETY: __CxxFrameHandler3 is a required Windows C++ exception handler symbol.
|
||||
// No other symbols in this crate export this name, preventing linker conflicts.
|
||||
#[unsafe(no_mangle)]
|
||||
pub const extern "system" fn __CxxFrameHandler3() -> i32 {
|
||||
0
|
||||
}
|
||||
|
||||
#[cfg(panic = "abort")]
|
||||
#[allow(missing_docs)]
|
||||
// SAFETY: __CxxFrameHandler4 is a required Windows C++ exception handler symbol.
|
||||
// No other symbols in this crate export this name, preventing linker conflicts.
|
||||
#[unsafe(no_mangle)]
|
||||
pub const extern "system" fn __CxxFrameHandler4() -> i32 {
|
||||
// This is a stub for the C++ exception handling frame handler. It's never
|
||||
// called but it needs to be distinct from __CxxFrameHandler3 to not confuse
|
||||
// binary analysis tools. We return a different value to prevent folding.
|
||||
1
|
||||
}
|
||||
|
||||
#[cfg(panic = "abort")]
|
||||
#[allow(missing_docs)]
|
||||
// SAFETY: __GSHandlerCheck_EH4 is a required Windows C++ exception handler symbol.
|
||||
// No other symbols in this crate export this name, preventing linker conflicts.
|
||||
#[unsafe(no_mangle)]
|
||||
pub const extern "system" fn __GSHandlerCheck_EH4() -> i32 {
|
||||
// This is a stub for the C++ exception handling frame handler. It's never
|
||||
// called but it needs to be distinct from __CxxFrameHandler3 and
|
||||
// __CxxFrameHandler4 to not confuse binary analysis tools. We return a
|
||||
// different value to prevent folding.
|
||||
2
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
driver_model__driver_type = "WDM",
|
||||
driver_model__driver_type = "KMDF",
|
||||
driver_model__driver_type = "UMDF"
|
||||
))]
|
||||
#[must_use]
|
||||
#[allow(non_snake_case)]
|
||||
/// Evaluates to TRUE if the return value specified by `nt_status` is a success
|
||||
/// type (0 − 0x3FFFFFFF) or an informational type (0x40000000 − 0x7FFFFFFF).
|
||||
/// This function is taken from ntdef.h in the WDK.
|
||||
///
|
||||
/// See the [NTSTATUS reference](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/87fba13e-bf06-450e-83b1-9241dc81e781) and
|
||||
/// [Using NTSTATUS values](https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/using-ntstatus-values) for details.
|
||||
pub const fn NT_SUCCESS(nt_status: NTSTATUS) -> bool {
|
||||
nt_status >= 0
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
driver_model__driver_type = "WDM",
|
||||
driver_model__driver_type = "KMDF",
|
||||
driver_model__driver_type = "UMDF"
|
||||
))]
|
||||
#[must_use]
|
||||
#[allow(non_snake_case)]
|
||||
#[allow(clippy::cast_sign_loss)]
|
||||
/// Evaluates to TRUE if the return value specified by `nt_status` is an
|
||||
/// informational type (0x40000000 − 0x7FFFFFFF). This function is taken from
|
||||
/// ntdef.h in the WDK.
|
||||
///
|
||||
/// See the [NTSTATUS reference](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/87fba13e-bf06-450e-83b1-9241dc81e781) and
|
||||
/// [Using NTSTATUS values](https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/using-ntstatus-values) for details.
|
||||
pub const fn NT_INFORMATION(nt_status: NTSTATUS) -> bool {
|
||||
(nt_status as u32 >> 30) == 1
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
driver_model__driver_type = "WDM",
|
||||
driver_model__driver_type = "KMDF",
|
||||
driver_model__driver_type = "UMDF"
|
||||
))]
|
||||
#[must_use]
|
||||
#[allow(non_snake_case)]
|
||||
#[allow(clippy::cast_sign_loss)]
|
||||
/// Evaluates to TRUE if the return value specified by `nt_status` is a warning
|
||||
/// type (0x80000000 − 0xBFFFFFFF). This function is taken from ntdef.h in the
|
||||
/// WDK.
|
||||
///
|
||||
/// See the [NTSTATUS reference](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/87fba13e-bf06-450e-83b1-9241dc81e781) and
|
||||
/// [Using NTSTATUS values](https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/using-ntstatus-values) for details.
|
||||
pub const fn NT_WARNING(nt_status: NTSTATUS) -> bool {
|
||||
(nt_status as u32 >> 30) == 2
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
driver_model__driver_type = "WDM",
|
||||
driver_model__driver_type = "KMDF",
|
||||
driver_model__driver_type = "UMDF"
|
||||
))]
|
||||
#[must_use]
|
||||
#[allow(non_snake_case)]
|
||||
#[allow(clippy::cast_sign_loss)]
|
||||
/// Evaluates to TRUE if the return value specified by `nt_status` is an error
|
||||
/// type (0xC0000000 - 0xFFFFFFFF). This function is taken from ntdef.h in the
|
||||
/// WDK.
|
||||
///
|
||||
/// See the [NTSTATUS reference](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/87fba13e-bf06-450e-83b1-9241dc81e781) and
|
||||
/// [Using NTSTATUS values](https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/using-ntstatus-values) for details.
|
||||
pub const fn NT_ERROR(nt_status: NTSTATUS) -> bool {
|
||||
(nt_status as u32 >> 30) == 3
|
||||
}
|
||||
|
||||
#[cfg(any(driver_model__driver_type = "WDM", driver_model__driver_type = "KMDF"))]
|
||||
#[allow(missing_docs)]
|
||||
#[macro_export]
|
||||
#[allow(non_snake_case)]
|
||||
macro_rules! PAGED_CODE {
|
||||
() => {
|
||||
debug_assert!(unsafe { $crate::ntddk::KeGetCurrentIrql() <= $crate::APC_LEVEL as u8 });
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// License: MIT OR Apache-2.0
|
||||
|
||||
//! Macros for use in the `wdk-sys` crate. This is especially useful for
|
||||
//! interacting with WDK apis which are inlined, and so are impossible to
|
||||
//! generate with [bindgen](https://docs.rs/bindgen/latest/bindgen/).
|
||||
|
||||
#[cfg(any(driver_model__driver_type = "KMDF", driver_model__driver_type = "UMDF"))]
|
||||
mod wdf {
|
||||
include!(concat!(
|
||||
env!("OUT_DIR"),
|
||||
"/call_unsafe_wdf_function_binding.rs"
|
||||
));
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// License: MIT OR Apache-2.0
|
||||
|
||||
//! Direct FFI bindings to NTDDK APIs from the Windows Driver Kit (WDK)
|
||||
//!
|
||||
//! This module contains all bindings to functions, constants, methods,
|
||||
//! constructors and destructors in `ntddk.h`. Types are not included in this
|
||||
//! module, but are available in the top-level `wdk_sys` module.
|
||||
|
||||
pub use bindings::*;
|
||||
|
||||
#[allow(missing_docs)]
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
mod bindings {
|
||||
#[allow(
|
||||
clippy::wildcard_imports,
|
||||
reason = "the underlying c code relies on all type definitions being in scope, which \
|
||||
results in the bindgen generated code relying on the generated types being in \
|
||||
scope as well"
|
||||
)]
|
||||
use crate::types::*;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/ntddk.rs"));
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// License: MIT OR Apache-2.0
|
||||
|
||||
//! Direct FFI bindings to Parallel Ports APIs from the Windows Driver Kit (WDK)
|
||||
//!
|
||||
//! This module contains all bindings to functions, constants, methods,
|
||||
//! constructors and destructors in the following headers: `ntddpar.h`,
|
||||
//! `ntddser.h`, `parallel.h`. Types are not included in this module, but are
|
||||
//! available in the top-level `wdk_sys` module.
|
||||
|
||||
#[allow(
|
||||
missing_docs,
|
||||
reason = "most items in the WDK headers have no inline documentation, so bindgen is unable to \
|
||||
generate documentation for their bindings"
|
||||
)]
|
||||
mod bindings {
|
||||
#[allow(
|
||||
clippy::wildcard_imports,
|
||||
reason = "the underlying c code relies on all type definitions being in scope, which \
|
||||
results in the bindgen generated code relying on the generated types being in \
|
||||
scope as well"
|
||||
)]
|
||||
#[allow(
|
||||
unused_imports,
|
||||
reason = "in certain versions of the WDK, there are no functions related to SPB that can \
|
||||
be generated by bindgen, so these types are unused"
|
||||
)]
|
||||
use crate::types::*;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/parallel_ports.rs"));
|
||||
}
|
||||
#[allow(
|
||||
unused_imports,
|
||||
reason = "in certain versions of the WDK, there are no functions related to SPB that can be \
|
||||
generated by bindgen, so the `bindings` module is empty"
|
||||
)]
|
||||
pub use bindings::*;
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// License: MIT OR Apache-2.0
|
||||
|
||||
//! Direct FFI bindings to SPB APIs from the Windows Driver Kit (WDK)
|
||||
//!
|
||||
//! This module contains all bindings to functions, constants, methods,
|
||||
//! constructors and destructors in the following headers: `spb.h`, `spbcx.h`,
|
||||
//! `reshub.h`, `pwmutil.h`. Types are not included in this module, but are
|
||||
//! available in the top-level `wdk_sys` module.
|
||||
|
||||
#[allow(
|
||||
missing_docs,
|
||||
reason = "most items in the WDK headers have no inline documentation, so bindgen is unable to \
|
||||
generate documentation for their bindings"
|
||||
)]
|
||||
mod bindings {
|
||||
#[allow(
|
||||
clippy::wildcard_imports,
|
||||
reason = "the underlying c code relies on all type definitions being in scope, which \
|
||||
results in the bindgen generated code relying on the generated types being in \
|
||||
scope as well"
|
||||
)]
|
||||
#[allow(
|
||||
unused_imports,
|
||||
reason = "in certain versions of the WDK, there are no functions related to SPB that can \
|
||||
be generated by bindgen, so these types are unused"
|
||||
)]
|
||||
use crate::types::*;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/spb.rs"));
|
||||
}
|
||||
#[allow(
|
||||
unused_imports,
|
||||
reason = "in certain versions of the WDK, there are no functions related to SPB that can be \
|
||||
generated by bindgen, so the `bindings` module is empty"
|
||||
)]
|
||||
pub use bindings::*;
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// License: MIT OR Apache-2.0
|
||||
|
||||
//! Direct FFI bindings to Storage APIs from the Windows Driver Kit (WDK)
|
||||
//!
|
||||
//! This module contains all bindings to functions, constants, methods,
|
||||
//! constructors and destructors for Storage headers. Types are not included in
|
||||
//! this module, but are available in the top-level `wdk_sys` module.
|
||||
|
||||
#[allow(
|
||||
missing_docs,
|
||||
reason = "most items in the WDK headers have no inline documentation, so bindgen is unable to \
|
||||
generate documentation for their bindings"
|
||||
)]
|
||||
mod bindings {
|
||||
#[allow(
|
||||
clippy::wildcard_imports,
|
||||
reason = "the underlying c code relies on all type definitions being in scope, which \
|
||||
results in the bindgen generated code relying on the generated types being in \
|
||||
scope as well"
|
||||
)]
|
||||
#[allow(
|
||||
unused_imports,
|
||||
reason = "in certain configurations of the WDK (ex. UMDF), there are no functions related \
|
||||
to Storage that can be generated by bindgen, so these types are unused"
|
||||
)]
|
||||
use crate::types::*;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/storage.rs"));
|
||||
}
|
||||
#[allow(
|
||||
unused_imports,
|
||||
reason = "in certain configurations of the WDK (ex. UMDF), there are no functions related to \
|
||||
Storage that can be generated by bindgen, so the `bindings` module is empty"
|
||||
)]
|
||||
pub use bindings::*;
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// License: MIT OR Apache-2.0
|
||||
|
||||
//! Any library dependency that depends on `wdk-sys` requires these stubs to
|
||||
//! provide symbols to successfully compile and run tests.
|
||||
//!
|
||||
//! These stubs can be brought into scope by introducing `wdk-sys` with the
|
||||
//! `test-stubs` feature in the `dev-dependencies` of the crate's `Cargo.toml`
|
||||
|
||||
#[cfg(any(driver_model__driver_type = "KMDF", driver_model__driver_type = "UMDF"))]
|
||||
pub use wdf::*;
|
||||
|
||||
#[cfg(any(
|
||||
driver_model__driver_type = "WDM",
|
||||
driver_model__driver_type = "KMDF",
|
||||
driver_model__driver_type = "UMDF"
|
||||
))]
|
||||
use crate::{DRIVER_OBJECT, NTSTATUS, PCUNICODE_STRING};
|
||||
|
||||
/// Stubbed version of `DriverEntry` Symbol so that test targets will compile
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function should never be called, so its safety is irrelevant
|
||||
#[cfg(any(
|
||||
driver_model__driver_type = "WDM",
|
||||
driver_model__driver_type = "KMDF",
|
||||
driver_model__driver_type = "UMDF"
|
||||
))]
|
||||
// SAFETY: "DriverEntry" is the required symbol name for Windows driver entry points.
|
||||
// No other function in this compilation unit exports this name, preventing symbol conflicts.
|
||||
#[unsafe(export_name = "DriverEntry")] // WDF expects a symbol with the name DriverEntry
|
||||
pub const unsafe extern "system" fn driver_entry_stub(
|
||||
_driver: &mut DRIVER_OBJECT,
|
||||
_registry_path: PCUNICODE_STRING,
|
||||
) -> NTSTATUS {
|
||||
0
|
||||
}
|
||||
|
||||
#[cfg(any(driver_model__driver_type = "KMDF", driver_model__driver_type = "UMDF"))]
|
||||
mod wdf {
|
||||
use crate::ULONG;
|
||||
|
||||
/// Stubbed version of `WdfFunctionCount` Symbol so that test targets will
|
||||
/// compile
|
||||
// SAFETY: WdfFunctionCount 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 WdfFunctionCount: ULONG = 0;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/test_stubs.rs"));
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// License: MIT OR Apache-2.0
|
||||
|
||||
pub use bindings::*;
|
||||
|
||||
#[allow(missing_docs)]
|
||||
#[allow(non_upper_case_globals)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#[allow(non_snake_case)]
|
||||
#[rustversion::attr(
|
||||
any(
|
||||
all(not(nightly), since(1.88)),
|
||||
all(nightly, since(2025-04-25)),
|
||||
),
|
||||
allow(unnecessary_transmutes)
|
||||
)]
|
||||
#[allow(unsafe_op_in_unsafe_fn)]
|
||||
#[allow(clippy::cast_lossless)]
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
#[allow(clippy::doc_markdown)]
|
||||
#[allow(clippy::default_trait_access)]
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[rustversion::attr(
|
||||
any(
|
||||
all(not(nightly), before(1.74)),
|
||||
all(nightly, before(2023-09-13)),
|
||||
),
|
||||
allow(clippy::incorrect_clone_impl_on_copy_type)
|
||||
)]
|
||||
#[rustversion::attr(
|
||||
any(
|
||||
all(not(nightly), since(1.74)),
|
||||
all(nightly, since(2023-09-13)),
|
||||
),
|
||||
allow(clippy::non_canonical_clone_impl)
|
||||
)]
|
||||
#[allow(clippy::missing_const_for_fn)]
|
||||
#[allow(clippy::missing_safety_doc)]
|
||||
#[allow(clippy::module_name_repetitions)]
|
||||
#[allow(clippy::multiple_unsafe_ops_per_block)]
|
||||
#[allow(clippy::must_use_candidate)]
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
#[allow(clippy::ptr_as_ptr)]
|
||||
#[allow(clippy::ptr_offset_with_cast)]
|
||||
#[rustversion::attr(
|
||||
any(
|
||||
all(not(nightly), since(1.77)),
|
||||
all(nightly, since(2024-01-11)),
|
||||
),
|
||||
allow(clippy::pub_underscore_fields)
|
||||
)]
|
||||
#[rustversion::attr(
|
||||
any(
|
||||
all(not(nightly), since(1.78)),
|
||||
all(nightly, since(2024-02-09)),
|
||||
),
|
||||
allow(clippy::ref_as_ptr)
|
||||
)]
|
||||
#[allow(clippy::semicolon_if_nothing_returned)]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
#[allow(clippy::too_many_lines)]
|
||||
#[allow(clippy::transmute_ptr_to_ptr)]
|
||||
#[allow(clippy::undocumented_unsafe_blocks)]
|
||||
#[allow(clippy::unnecessary_cast)]
|
||||
#[allow(clippy::unreadable_literal)]
|
||||
#[allow(clippy::used_underscore_binding)]
|
||||
#[allow(clippy::useless_transmute)]
|
||||
#[allow(clippy::use_self)]
|
||||
mod bindings {
|
||||
include!(concat!(env!("OUT_DIR"), "/types.rs"));
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// License: MIT OR Apache-2.0
|
||||
|
||||
//! Direct FFI bindings to USB APIs from the Windows Driver Kit (WDK)
|
||||
//!
|
||||
//! This module contains all bindings to functions, constants, methods,
|
||||
//! constructors and destructors for USB headers. Types are not included in this
|
||||
//! module, but are available in the top-level `wdk_sys` module.
|
||||
|
||||
#[allow(
|
||||
missing_docs,
|
||||
reason = "most items in the WDK headers have no inline documentation, so bindgen is unable to \
|
||||
generate documentation for their bindings"
|
||||
)]
|
||||
mod bindings {
|
||||
#[allow(
|
||||
clippy::wildcard_imports,
|
||||
reason = "the underlying c code relies on all type definitions being in scope, which \
|
||||
results in the bindgen generated code relying on the generated types being in \
|
||||
scope as well"
|
||||
)]
|
||||
use crate::types::*;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/usb.rs"));
|
||||
}
|
||||
pub use bindings::*;
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// License: MIT OR Apache-2.0
|
||||
|
||||
//! Direct FFI bindings to WDF APIs from the Windows Driver Kit (WDK)
|
||||
//!
|
||||
//! This module contains all bindings to functions, constants, methods,
|
||||
//! constructors and destructors in `wdf.h`. Types are not included in this
|
||||
//! module, but are available in the top-level `wdk_sys` module.
|
||||
|
||||
pub use bindings::*;
|
||||
|
||||
#[allow(missing_docs)]
|
||||
#[allow(clippy::unreadable_literal)]
|
||||
mod bindings {
|
||||
#[allow(
|
||||
clippy::wildcard_imports,
|
||||
reason = "the underlying c code relies on all type definitions being in scope, which \
|
||||
results in the bindgen generated code relying on the generated types being in \
|
||||
scope as well"
|
||||
)]
|
||||
use crate::types::*;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/wdf.rs"));
|
||||
}
|
||||
|
||||
// This is a workaround to expose the generated function count to the
|
||||
// `call_unsafe_wdf_function_binding` proc-macro, so that the macro-generated
|
||||
// code can determine the slice size at runtime. When we are able to
|
||||
// conditionally compile based off a cfg range for WDF version, this module
|
||||
// can be removed and the runtime check can be replaced with a conditional
|
||||
// compilation: https://github.com/microsoft/windows-drivers-rs/issues/276
|
||||
#[doc(hidden)]
|
||||
pub mod __private {
|
||||
include!(concat!(env!("OUT_DIR"), "/wdf_function_count.rs"));
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// License: MIT OR Apache-2.0
|
||||
|
||||
//! Direct FFI bindings to WIN32 APIs from the Windows Driver Kit (WDK)
|
||||
//!
|
||||
//! This module contains all bindings to functions, constants, methods,
|
||||
//! constructors and destructors in `windows.h`. Types are not included in this
|
||||
//! module, but are available in the top-level `wdk_sys` module.
|
||||
|
||||
pub use bindings::*;
|
||||
|
||||
#[allow(missing_docs)]
|
||||
mod bindings {
|
||||
#[allow(
|
||||
clippy::wildcard_imports,
|
||||
reason = "the underlying c code relies on all type definitions being in scope, which \
|
||||
results in the bindgen generated code relying on the generated types being in \
|
||||
scope as well"
|
||||
)]
|
||||
use crate::types::*;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/windows.rs"));
|
||||
}
|
||||
@@ -22,5 +22,8 @@ wdk-build.workspace = true
|
||||
|
||||
[dependencies]
|
||||
wdk.workspace = true
|
||||
wdk-sys.workspace = true
|
||||
# `iddcx` feature → wdk-sys runs the IddCx bindgen pass (generate_iddcx) + compiles `wdk_sys::iddcx`.
|
||||
# This is the M1 make-or-break: does IddCx.h bindgen in wdk-sys's config without a header conflict, and
|
||||
# do its WDF/DXGI types resolve to wdk-sys's (so the generated module compiles)?
|
||||
wdk-sys = { workspace = true, features = ["iddcx"] }
|
||||
pf-vdisplay-proto.workspace = true
|
||||
|
||||
Reference in New Issue
Block a user