From 026710ec7e795a9c462ce179c587b6b24e1c90e3 Mon Sep 17 00:00:00 2001 From: Melvin Wang Date: Mon, 23 Oct 2023 14:18:09 -0700 Subject: [PATCH 1/7] fix: add missing cpu-arch macro defintions --- crates/wdk-build/src/bindgen.rs | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/crates/wdk-build/src/bindgen.rs b/crates/wdk-build/src/bindgen.rs index 7c7cf8b8..9a0cc9be 100644 --- a/crates/wdk-build/src/bindgen.rs +++ b/crates/wdk-build/src/bindgen.rs @@ -48,13 +48,22 @@ impl BuilderExt for Builder { .expect("Non Unicode paths are not supported") ) })) - .clang_arg(format!( - "--define-macro={}", + .clang_args( match config.cpu_architecture { - CPUArchitecture::AMD64 => "_AMD64_", - CPUArchitecture::ARM64 => "_ARM64EC_", + // Definitions sourced from `Program Files\Windows + // Kits\10\build\10.0.22621.0\WindowsDriver.x64.props` + CPUArchitecture::AMD64 => { + vec!["_WIN64", "_AMD64_", "AMD64"] + } + // Definitions sourced from `Program Files\Windows + // Kits\10\build\10.0.22621.0\WindowsDriver.arm64.props` + CPUArchitecture::ARM64 => { + vec!["_ARM64_", "ARM64", "_USE_DECLSPECS_FOR_SAL=1", "STD_CALL"] + } } - )) + .iter() + .map(|preprocessor_definition| format!("--define-macro={preprocessor_definition}")), + ) .clang_args( match config.driver_config { // FIXME: Add support for KMDF_MINIMUM_VERSION_REQUIRED and @@ -100,6 +109,9 @@ impl BuilderExt for Builder { // below and if there are any non-blocklisted function definitions, it will throw a // -WDeprecated warning .clang_arg("--warn-=no-deprecated-declarations") + // Windows SDK & DDK contain unnecessary token pasting (ex. &##_variable: `&` and + // `_variable` are seperate tokens already, and don't need `##` to concatenate them) + .clang_arg("--warn-=no-invalid-token-paste") .clang_arg("-fms-extensions") .blocklist_item("ExAllocatePoolWithTag") // Deprecated .blocklist_item("ExAllocatePoolWithQuotaTag") // Deprecated From a50ca0a3f11b4a7ff296f76993cd4a088194c677 Mon Sep 17 00:00:00 2001 From: Melvin Wang Date: Mon, 23 Oct 2023 14:20:26 -0700 Subject: [PATCH 2/7] fix: fix wrong instruction used for arm64 breakpoint --- crates/wdk/src/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/wdk/src/lib.rs b/crates/wdk/src/lib.rs index 21dd37d6..ecdc3533 100644 --- a/crates/wdk/src/lib.rs +++ b/crates/wdk/src/lib.rs @@ -33,7 +33,9 @@ pub use print::_print; pub use wdk_sys::{NT_SUCCESS as nt_success, PAGED_CODE as paged_code}; pub mod wdf; -/// Trigger a breakpoint in debugger via architecture-specific inline assembly +/// Trigger a breakpoint in debugger via architecture-specific inline assembly. +/// +/// Implementations derived from details outlined in [MSVC `__debugbreak` intrinsic documentation](https://learn.microsoft.com/en-us/cpp/intrinsics/debugbreak?view=msvc-170#remarks) /// /// # Panics /// Will Panic if called on an unsupported architecture @@ -42,7 +44,7 @@ pub fn dbg_break() { unsafe { #[cfg(target_arch = "aarch64")] { - core::arch::asm!("int 3"); + core::arch::asm!("brk #0xF000"); return; } From 7a718219f9157f0e0aebb58be6048024280a4224 Mon Sep 17 00:00:00 2001 From: Melvin Wang Date: Fri, 3 Nov 2023 16:53:18 -0700 Subject: [PATCH 3/7] feat: cargo-make argument forwarding --- .../workflows/github-dependency-review.yaml | 5 +- Cargo.lock | 387 +++++++++++----- Makefile.toml | 1 + README.md | 38 +- crates/wdk-build/Cargo.toml | 2 + crates/wdk-build/src/cargo_make.rs | 416 ++++++++++++++++++ crates/wdk-build/src/lib.rs | 2 + rust-driver-makefile.toml | 87 +++- 8 files changed, 825 insertions(+), 113 deletions(-) create mode 100644 Makefile.toml create mode 100644 crates/wdk-build/src/cargo_make.rs diff --git a/.github/workflows/github-dependency-review.yaml b/.github/workflows/github-dependency-review.yaml index 77d7ed9c..31983e70 100644 --- a/.github/workflows/github-dependency-review.yaml +++ b/.github/workflows/github-dependency-review.yaml @@ -19,7 +19,10 @@ jobs: - name: Dependency Review uses: actions/dependency-review-action@v3 with: - allow-licenses: MIT, Apache-2.0 + # AND combinations are currently bugged and must be listed separately: https://github.com/actions/dependency-review-action/issues/263 + allow-licenses: MIT, Apache-2.0, ISC, Unicode-DFS-2016, (MIT OR Apache-2.0) AND Unicode-DFS-2016 + # anstyle is licensed as (MIT OR Apache-2.0), but the Github api fails to detect it: https://github.com/rust-cli/anstyle/tree/main/crates/anstyle + allow-dependencies-licenses: 'pkg:cargo/anstyle@1.0.4' comment-summary-in-pr: on-failure # Explicit refs required for merge_group and push triggers: # https://github.com/actions/dependency-review-action/issues/456 diff --git a/Cargo.lock b/Cargo.lock index 84bab0a5..39b782af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,54 @@ dependencies = [ "memchr", ] +[[package]] +name = "anstream" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" + +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + [[package]] name = "anyhow" version = "1.0.79" @@ -19,9 +67,9 @@ checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" [[package]] name = "basic-toml" -version = "0.1.4" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bfc506e7a2370ec239e1d072507b2a80c833083699d3c6fa176fbb4de8448c6" +checksum = "2db21524cad41c5591204d22d75e1970a2d1f71060214ca931dc7d5afe2c14e5" dependencies = [ "serde", ] @@ -51,18 +99,9 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.4.0" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" - -[[package]] -name = "cc" -version = "1.0.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" [[package]] name = "cexpr" @@ -81,15 +120,71 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clang-sys" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" +checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" dependencies = [ "glob", "libc", "libloading", ] +[[package]] +name = "clap" +version = "4.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap-cargo" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38ae55615695e768a76899c8411b4ebacfbe525e964f94fd24f0007b10b45cd3" +dependencies = [ + "anstyle", + "clap", +] + +[[package]] +name = "clap_builder" +version = "4.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + [[package]] name = "diff" version = "0.1.13" @@ -104,23 +199,12 @@ checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "errno" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ - "cc", "libc", + "windows-sys 0.52.0", ] [[package]] @@ -129,20 +213,26 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "home" -version = "0.5.5" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" dependencies = [ - "windows-sys", + "windows-sys 0.52.0", ] [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "lazy_static" @@ -161,25 +251,25 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.149" +version = "0.2.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" +checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" [[package]] name = "libloading" -version = "0.7.4" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" dependencies = [ "cfg-if", - "winapi", + "windows-sys 0.48.0", ] [[package]] name = "linux-raw-sys" -version = "0.4.10" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "log" @@ -212,9 +302,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.6.3" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "minimal-lexical" @@ -244,9 +334,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "overload" @@ -280,9 +370,9 @@ checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "prettyplease" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" +checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" dependencies = [ "proc-macro2", "syn", @@ -290,32 +380,32 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.74" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2de98502f212cfcea8d0bb305bd0f49d7ebdd75b64ba0a68f937d888f4e0d6db" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] [[package]] name = "regex" -version = "1.9.5" +version = "1.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.3.8", - "regex-syntax 0.7.5", + "regex-automata 0.4.4", + "regex-syntax 0.8.2", ] [[package]] @@ -329,13 +419,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.8" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795" +checksum = "3b7fa1134405e2ec9353fd416b17f8dacd46c473d7d3fd1cf202706a14eb792a" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.5", + "regex-syntax 0.8.2", ] [[package]] @@ -346,9 +436,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.5" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "rustc-hash" @@ -358,15 +448,15 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustix" -version = "0.38.19" +version = "0.38.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "745ecfa778e66b2b63c88a61cb36e0eea109e803b0b86bf9879fbc77c70e86ed" +checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -377,9 +467,9 @@ checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" [[package]] name = "sample-kmdf-driver" @@ -397,18 +487,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.193" +version = "1.0.195" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.193" +version = "1.0.195" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" dependencies = [ "proc-macro2", "quote", @@ -417,9 +507,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.109" +version = "1.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb0652c533506ad7a2e353cce269330d6afd8bdfb6d75e0ace5b35aacbd7b9e9" +checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" dependencies = [ "itoa", "ryu", @@ -428,9 +518,9 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.4" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ "lazy_static", ] @@ -443,9 +533,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "smallvec" -version = "1.11.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" [[package]] name = "spin" @@ -459,11 +549,17 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "syn" -version = "2.0.32" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", @@ -472,27 +568,27 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.2.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] [[package]] name = "thiserror" -version = "1.0.55" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e3de26b0965292219b4287ff031fcba86837900fe9cd2b34ea8ad893c0953d2" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.55" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "268026685b2be38d7103e9e507c938a1fcb3d7e6eb15e87870b617bf37b6d581" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" dependencies = [ "proc-macro2", "quote", @@ -511,20 +607,19 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "pin-project-lite", "tracing-core", ] [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", "valuable", @@ -532,20 +627,20 @@ dependencies = [ [[package]] name = "tracing-log" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" dependencies = [ - "lazy_static", "log", + "once_cell", "tracing-core", ] [[package]] name = "tracing-subscriber" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "matchers", "nu-ansi-term", @@ -561,9 +656,9 @@ dependencies = [ [[package]] name = "trybuild" -version = "1.0.86" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8419ecd263363827c5730386f418715766f584e2f874d32c23c5b00bd9727e7e" +checksum = "9a9d3ba662913483d6722303f619e75ea10b7855b0f8e0d72799cf8621bb488f" dependencies = [ "basic-toml", "glob", @@ -576,9 +671,15 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "utf8parse" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "valuable" @@ -606,6 +707,8 @@ name = "wdk-build" version = "0.1.0" dependencies = [ "bindgen", + "clap", + "clap-cargo", "rustversion", "serde", "serde_json", @@ -677,9 +780,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ "winapi", ] @@ -697,7 +800,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9" dependencies = [ "windows-core", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -706,7 +809,7 @@ version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -715,7 +818,16 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", ] [[package]] @@ -724,13 +836,28 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] @@ -739,38 +866,80 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" diff --git a/Makefile.toml b/Makefile.toml new file mode 100644 index 00000000..4392852e --- /dev/null +++ b/Makefile.toml @@ -0,0 +1 @@ +extend = "./rust-driver-makefile.toml" diff --git a/README.md b/README.md index 676c9240..8cda0858 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@ # 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. @@ -148,7 +147,44 @@ The crates in this repository are available from [`crates.io`](https://crates.io A `DriverCertificate.cer` file will be generated, and a signed driver package will be available at `target//package` +## 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 arguements 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 ` + +For release builds: + +`cargo make default --release` or `cargo make default --profile release` + +To specify specific features: + +`cargo make default --feature ` + +To specify a specific rust toolchain: + +`cargo make default +` + +To display help and see the full list of supported CLI args to forward to Cargo: + +`cargo make help` + ## 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 diff --git a/crates/wdk-build/Cargo.toml b/crates/wdk-build/Cargo.toml index 062703ec..3471cc76 100644 --- a/crates/wdk-build/Cargo.toml +++ b/crates/wdk-build/Cargo.toml @@ -13,6 +13,8 @@ categories = ["development-tools::build-utils", "development-tools::ffi"] bindgen.workspace = true serde.workspace = true serde_json.workspace = true +clap = { version = "4.4.7", features = ["derive"] } +clap-cargo = "0.13.0" thiserror = "1.0.55" windows = { version = "0.51.1", features = [ "Win32_Foundation", diff --git a/crates/wdk-build/src/cargo_make.rs b/crates/wdk-build/src/cargo_make.rs new file mode 100644 index 00000000..8c12f50d --- /dev/null +++ b/crates/wdk-build/src/cargo_make.rs @@ -0,0 +1,416 @@ +// Copyright (c) Microsoft Corporation +// License: MIT OR Apache-2.0 + +//! This module provides argument parsing functionality used by +//! `rust-driver-makefile.toml` to validate and forward arguments common to +//! cargo commands. It uses a combination of `clap` and `clap_cargo` to provide +//! a CLI very close to cargo's own, but only exposes the arguments supported by +//! `rust-driver-makefile.toml`. Help text and other `clap::Arg` + +use clap::{Args, Parser}; + +/// The name of the environment variable that cargo-make uses during `cargo +/// build` and `cargo test` commands +const CARGO_MAKE_CARGO_BUILD_TEST_FLAGS_ENV_VAR: &str = "CARGO_MAKE_CARGO_BUILD_TEST_FLAGS"; + +const CARGO_MAKE_PROFILE_ENV_VAR: &str = "CARGO_MAKE_PROFILE"; +const CARGO_MAKE_CARGO_PROFILE_ENV_VAR: &str = "CARGO_MAKE_CARGO_PROFILE"; +const CARGO_MAKE_RUST_DEFAULT_TOOLCHAIN_ENV_VAR: &str = "CARGO_MAKE_RUST_DEFAULT_TOOLCHAIN"; + +/// `clap` uses an exit code of 2 for usage errors: +const CLAP_USAGE_EXIT_CODE: i32 = 2; + +trait ParseCargoArg { + fn parse_cargo_arg(&self); +} + +#[derive(Parser, Debug)] +struct CommandLineInterface { + #[command(flatten)] + base: BaseOptions, + + #[command(flatten)] + #[command(next_help_heading = "Package Selection")] + workspace: clap_cargo::Workspace, + + #[command(flatten)] + #[command(next_help_heading = "Feature Selection")] + features: clap_cargo::Features, + + #[command(flatten)] + compilation_options: CompilationOptions, + + #[command(flatten)] + manifest_options: ManifestOptions, +} + +#[derive(Args, Debug)] +struct BaseOptions { + #[arg(long, help = "Do not print cargo log messages")] + quiet: bool, + + #[arg(short, long, action = clap::ArgAction::Count, help = "Use verbose output (-vv very verbose/build.rs output)")] + verbose: u8, +} + +#[derive(Args, Debug)] +#[command(next_help_heading = "Compilation Options")] +struct CompilationOptions { + #[arg( + short, + long, + help = "Build artifacts in release mode, with optimizations" + )] + release: bool, + + #[arg( + long, + value_name = "PROFILE-NAME", + help = "Build artifacts with the specified profile" + )] + profile: Option, + + #[arg( + short, + long, + value_name = "N", + allow_negative_numbers = true, + help = "Number of parallel jobs, defaults to # of CPUs." + )] + jobs: Option, + + // TODO: support building multiple targets at once + #[arg(long, value_name = "TRIPLE", help = "Build for a target triple")] + target: Option, + + #[allow(clippy::option_option)] // This is how clap_derive expects "optional value for optional argument" args + #[arg( + long, + value_name = "FMTS", + require_equals = true, + help = "Timing output formats (unstable) (comma separated): html, json" + )] + timings: Option>, +} + +#[derive(Args, Debug)] +#[command(next_help_heading = "Manifest Options")] +struct ManifestOptions { + #[arg(long, help = "Require Cargo.lock and cache are up to date")] + frozen: bool, + + #[arg(long, help = "Require Cargo.lock is up to date")] + locked: bool, + + #[arg(long, help = "Run without accessing the network")] + offline: bool, +} + +impl ParseCargoArg for BaseOptions { + fn parse_cargo_arg(&self) { + if self.quiet && self.verbose > 0 { + eprintln!("Cannot specify both --quiet and --verbose"); + std::process::exit(CLAP_USAGE_EXIT_CODE); + } + + if self.quiet { + append_to_space_delimited_env_var(CARGO_MAKE_CARGO_BUILD_TEST_FLAGS_ENV_VAR, "--quiet"); + } + + if self.verbose > 0 { + append_to_space_delimited_env_var( + CARGO_MAKE_CARGO_BUILD_TEST_FLAGS_ENV_VAR, + format!("-{}", "v".repeat(self.verbose.into())).as_str(), + ); + } + } +} + +impl ParseCargoArg for clap_cargo::Workspace { + fn parse_cargo_arg(&self) { + if !self.package.is_empty() { + append_to_space_delimited_env_var( + CARGO_MAKE_CARGO_BUILD_TEST_FLAGS_ENV_VAR, + self.package + .iter() + .fold( + String::with_capacity({ + const MINIMUM_PACKAGE_SPEC_LENGTH: usize = 1; + const MINIMUM_PACKAGE_ARG_LENGTH: usize = + "--package ".len() + MINIMUM_PACKAGE_SPEC_LENGTH + " ".len(); + self.package.len() * MINIMUM_PACKAGE_ARG_LENGTH + }), + |mut package_args, package_spec| { + package_args.push_str("--package "); + package_args.push_str(package_spec); + package_args.push(' '); + package_args + }, + ) + .trim_end(), + ); + } + + if self.workspace { + append_to_space_delimited_env_var( + CARGO_MAKE_CARGO_BUILD_TEST_FLAGS_ENV_VAR, + "--workspace", + ); + } + + if !self.exclude.is_empty() { + if !self.workspace { + eprintln!("--exclude can only be used together with --workspace"); + std::process::exit(CLAP_USAGE_EXIT_CODE); + } + + append_to_space_delimited_env_var( + CARGO_MAKE_CARGO_BUILD_TEST_FLAGS_ENV_VAR, + self.exclude + .iter() + .fold( + String::with_capacity({ + const MINIMUM_PACKAGE_SPEC_LENGTH: usize = 1; + const MINIMUM_EXCLUDE_ARG_LENGTH: usize = + "--exclude ".len() + MINIMUM_PACKAGE_SPEC_LENGTH + " ".len(); + self.package.len() * MINIMUM_EXCLUDE_ARG_LENGTH + }), + |mut exclude_args, package_spec| { + exclude_args.push_str("--exclude "); + exclude_args.push_str(package_spec); + exclude_args.push(' '); + exclude_args + }, + ) + .trim_end(), + ); + } + + if self.all { + append_to_space_delimited_env_var(CARGO_MAKE_CARGO_BUILD_TEST_FLAGS_ENV_VAR, "--all"); + } + } +} + +impl ParseCargoArg for clap_cargo::Features { + fn parse_cargo_arg(&self) { + if self.all_features { + append_to_space_delimited_env_var( + CARGO_MAKE_CARGO_BUILD_TEST_FLAGS_ENV_VAR, + "--all-features", + ); + } + + if self.no_default_features { + append_to_space_delimited_env_var( + CARGO_MAKE_CARGO_BUILD_TEST_FLAGS_ENV_VAR, + "--no-default-features", + ); + } + + if !self.features.is_empty() { + append_to_space_delimited_env_var( + CARGO_MAKE_CARGO_BUILD_TEST_FLAGS_ENV_VAR, + self.features + .iter() + .fold( + String::with_capacity({ + const MINIMUM_FEATURE_NAME_LENGTH: usize = 1; + const MINIMUM_FEATURE_ARG_LENGTH: usize = + "--features ".len() + MINIMUM_FEATURE_NAME_LENGTH + " ".len(); + self.features.len() * MINIMUM_FEATURE_ARG_LENGTH + }), + |mut feature_args: String, feature| { + feature_args.push_str("--features "); + feature_args.push_str(feature); + feature_args.push(' '); + feature_args + }, + ) + .trim_end(), + ); + } + } +} + +impl ParseCargoArg for CompilationOptions { + fn parse_cargo_arg(&self) { + if self.release && self.profile.is_some() { + eprintln!("the `--release` flag should not be specified with the `--profile` flag"); + std::process::exit(CLAP_USAGE_EXIT_CODE); + } + match std::env::var(CARGO_MAKE_PROFILE_ENV_VAR) + .unwrap_or_else(|_| panic!("{CARGO_MAKE_PROFILE_ENV_VAR} should be set by cargo-make.")) + .as_ref() + { + "release" => { + // cargo-make release profile sets the `--profile release` flag + if let Some(profile) = &self.profile { + if profile != "release" { + eprintln!( + "Specifying `--profile release` for cargo-make conflicts with the \ + setting `--profile {profile}` to forward to tasks" + ); + std::process::exit(CLAP_USAGE_EXIT_CODE); + } + } + + append_to_space_delimited_env_var( + CARGO_MAKE_CARGO_BUILD_TEST_FLAGS_ENV_VAR, + "--profile release", + ); + } + _ => { + // All other cargo-make profiles do not set a specific cargo profile. Cargo + // profiles set by --release, --profile , or -p (after the + // cargo-make task name) are forwarded to cargo commands + if self.release { + println!("{CARGO_MAKE_CARGO_PROFILE_ENV_VAR}=release"); + append_to_space_delimited_env_var( + CARGO_MAKE_CARGO_BUILD_TEST_FLAGS_ENV_VAR, + "--release", + ); + } else if let Some(profile) = &self.profile { + println!("{CARGO_MAKE_CARGO_PROFILE_ENV_VAR}={profile}"); + append_to_space_delimited_env_var( + CARGO_MAKE_CARGO_BUILD_TEST_FLAGS_ENV_VAR, + format!("--profile {profile}").as_str(), + ); + } + } + } + + if let Some(jobs) = &self.jobs { + append_to_space_delimited_env_var( + CARGO_MAKE_CARGO_BUILD_TEST_FLAGS_ENV_VAR, + format!("--jobs {jobs}").as_str(), + ); + } + + if let Some(target) = &self.target { + println!("CARGO_MAKE_CRATE_TARGET_TRIPLE={target}"); + append_to_space_delimited_env_var( + CARGO_MAKE_CARGO_BUILD_TEST_FLAGS_ENV_VAR, + format!("--target {target}").as_str(), + ); + } + + if let Some(timings_option) = &self.timings { + timings_option.as_ref().map_or_else( + || { + append_to_space_delimited_env_var( + CARGO_MAKE_CARGO_BUILD_TEST_FLAGS_ENV_VAR, + "--timings", + ); + }, + |timings_value| { + append_to_space_delimited_env_var( + CARGO_MAKE_CARGO_BUILD_TEST_FLAGS_ENV_VAR, + format!("--timings {timings_value}").as_str(), + ); + }, + ); + } + } +} + +impl ParseCargoArg for ManifestOptions { + fn parse_cargo_arg(&self) { + if self.frozen { + append_to_space_delimited_env_var( + CARGO_MAKE_CARGO_BUILD_TEST_FLAGS_ENV_VAR, + "--frozen", + ); + } + + if self.locked { + append_to_space_delimited_env_var( + CARGO_MAKE_CARGO_BUILD_TEST_FLAGS_ENV_VAR, + "--locked", + ); + } + + if self.offline { + append_to_space_delimited_env_var( + CARGO_MAKE_CARGO_BUILD_TEST_FLAGS_ENV_VAR, + "--offline", + ); + } + } +} + +/// Parses the command line arguments, validates that they are supported by +/// `rust-driver-makefile.toml`, and forwards them to `cargo-make` by printing +/// them to stdout. +/// +/// # Panics +/// +/// This function will panic if there's an internal error (i.e. bug) in its +/// argument processing. +pub fn validate_and_forward_args() { + const TOOLCHAIN_ARG_POSITION: usize = 1; + + let mut env_args = std::env::args_os().collect::>(); + + // + is a special argument that can't currently be handled by clap parsing: https://github.com/clap-rs/clap/issues/2468 + let toolchain_arg = if env_args + .get(TOOLCHAIN_ARG_POSITION) + .is_some_and(|arg| arg.to_string_lossy().starts_with('+')) + { + Some( + env_args + .remove(TOOLCHAIN_ARG_POSITION) + .to_string_lossy() + .strip_prefix('+') + .expect("Toolchain arg should have a + prefix") + .to_owned(), + ) + } else { + None + }; + + let command_line_interface: CommandLineInterface = + CommandLineInterface::parse_from(env_args.iter()); + // This print signifies the start of the forwarding and signals to the + // `rust-env-update` plugin that it should forward args. This is also used to + // signal that the auto-generated help from `clap` was not executed. + println!("FORWARDING ARGS TO CARGO-MAKE:"); + + if let Some(toolchain) = toolchain_arg { + println!("{CARGO_MAKE_RUST_DEFAULT_TOOLCHAIN_ENV_VAR}={toolchain}"); + } + + command_line_interface.base.parse_cargo_arg(); + command_line_interface.workspace.parse_cargo_arg(); + command_line_interface.features.parse_cargo_arg(); + command_line_interface.compilation_options.parse_cargo_arg(); + command_line_interface.manifest_options.parse_cargo_arg(); + + forward_env_var_to_cargo_make(CARGO_MAKE_CARGO_BUILD_TEST_FLAGS_ENV_VAR); +} + +fn append_to_space_delimited_env_var>(env_var_name: S, string_to_append: S) { + let env_var_name = env_var_name.as_ref(); + let string_to_append = string_to_append.as_ref(); + + let mut env_var_value = std::env::var(env_var_name).unwrap_or_default(); + env_var_value.push(' '); + env_var_value.push_str(string_to_append); + std::env::set_var(env_var_name, env_var_value.trim()); +} + +fn forward_env_var_to_cargo_make>(env_var_name: S) { + let env_var_name = env_var_name.as_ref(); + + // Since this executes in a child proccess to cargo-make, we need to forward the + // values we want to change to duckscript, in order to get it to modify the + // parent process (ie. cargo-make) + if let Some(env_var_value) = std::env::var_os(env_var_name) { + println!( + "{env_var_name}={}", + env_var_value + .to_str() + .expect("env var value should be valid UTF-8") + ); + } +} diff --git a/crates/wdk-build/src/lib.rs b/crates/wdk-build/src/lib.rs index e86108c3..8cdd7600 100644 --- a/crates/wdk-build/src/lib.rs +++ b/crates/wdk-build/src/lib.rs @@ -33,6 +33,8 @@ mod bindgen; mod utils; +pub mod cargo_make; + use std::{env, path::PathBuf}; pub use bindgen::BuilderExt; diff --git a/rust-driver-makefile.toml b/rust-driver-makefile.toml index 0b63edd1..b8f278eb 100644 --- a/rust-driver-makefile.toml +++ b/rust-driver-makefile.toml @@ -3,13 +3,96 @@ # FIXME: replace all script blocks with cargo-make commands: "Favor commands over scripts, as commands support more features such as automatic dependencies installation, argument functions, and more..." # FIXME: this flow is based on the signing process of a KMDF PNP driver. There should be different flows availabe for different types of drivers as outlined in https://learn.microsoft.com/en-us/windows-hardware/drivers/install/test-signing-driver-packages +[config] +min_version = "0.37.3" +init_task = "wdk-build-init" +default_to_workspace = 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 = "" + VC_BUILD_DIR = "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Auxiliary\\Build\\vcvarsamd64_x86.bat" + # FIXME: add --locked for CI builds using CARGO_MAKE_PR and CARGO_MAKE_CI -CARGO_MAKE_CARGO_BUILD_TEST_FLAGS = "--profile ${CARGO_MAKE_CARGO_PROFILE}" # Cargo puts "dev" profile builds in the "debug" target folder: https://doc.rust-lang.org/cargo/guide/build-cache.html#build-cache. This supports cargo-make profile values of both "development" and "dev" -OUTPUT_DIR = { source = "${CARGO_MAKE_CARGO_PROFILE}", default_value = "${CARGO_MAKE_CRATE_TARGET_DIRECTORY}\\${CARGO_MAKE_CARGO_PROFILE}", mapping = { "dev" = "${CARGO_MAKE_CRATE_TARGET_DIRECTORY}\\debug" } } +OUTPUT_DIR = { source = "${CARGO_MAKE_CARGO_PROFILE}", default_value = "${CARGO_MAKE_CRATE_CUSTOM_TRIPLE_TARGET_DIRECTORY}\\${CARGO_MAKE_CARGO_PROFILE}", mapping = { "dev" = "${CARGO_MAKE_CRATE_CUSTOM_TRIPLE_TARGET_DIRECTORY}\\debug" } } + +[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}" + +# Execute rust-script +taskjson = json_parse ${task.as_json} +filepath = set "./target/cargo-make-script/${task.name}/main.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 +cli_args = array_join ${flow.cli.args} " " +trigger_help = get_env TRIGGER_HELP +if not is_empty ${trigger_help} + cli_args = concat ${cli_args} " --help" +end +out = exec --fail-on-error rust-script --base-path ${taskjson.env.CARGO_MAKE_CURRENT_TASK_INITIAL_MAKEFILE_DIRECTORY} ./target/cargo-make-script/${task.name}/main.rs %{cli_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 ./target/cargo-make-script/${task.name}/main.rs" + +# 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 + stdout_first_line = array_get ${script_output_array} 0 + assert_eq ${stdout_first_line} "FORWARDING ARGS TO CARGO-MAKE:" "[tasks.${task.name}]'s script output did not begin with \"FORWARDING ARGS TO CARGO-MAKE:\". Was `--help` passed as one of the arguments?\nstdout:\n${out.stdout}\nstderr:\n${out.stderr}\nThe temporary rust-script file is located at ./target/cargo-make-script/${task.name}/main.rs" + array_remove ${script_output_array} 0 + for line in ${script_output_array} + parts = split ${line} = + key = array_get ${parts} 0 + value = array_get ${parts} 1 + set_env ${key} ${value} + end +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 = "./crates/wdk-build", version = "0.1.0" } +//! ``` +#![allow(unused_doc_comments)] + +wdk_build::cargo_make::validate_and_forward_args(); +''' + +[tasks.help] +workspace = false +env = { "TRIGGER_HELP" = "1" } +run_task = "wdk-build-init" [tasks.rename-dll-to-sys] dependencies = ["build"] From e60375ec2cff70ec7c5bfd14f297036f3a33acc3 Mon Sep 17 00:00:00 2001 From: Melvin Wang Date: Sat, 11 Nov 2023 19:42:22 -0800 Subject: [PATCH 4/7] build: update cargo-make tasks with arch-specific tools --- .gitignore | 2 - CONTRIBUTING.md | 2 + README.md | 4 +- crates/sample-kmdf-driver/Makefile.toml | 3 + crates/sample-kmdf-driver/README.md | 8 +- crates/wdk-build/Cargo.toml | 2 +- crates/wdk-build/src/cargo_make.rs | 174 ++++++++++++++++- crates/wdk-build/src/lib.rs | 57 +++++- crates/wdk-build/src/utils.rs | 10 +- rust-driver-makefile.toml | 249 ++++++++++++++++++++---- 10 files changed, 438 insertions(+), 73 deletions(-) diff --git a/.gitignore b/.gitignore index d92d5d4a..2f7896d1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1 @@ target/ -DriverCertificate.cer -.cargo-make-loadscripts/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a423238a..dc8cf46f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -98,6 +98,8 @@ The following tools should be installed as a part of the `windows-drivers-rs` de * To compile and open documentation: `cargo doc --locked --open` * To include nightly features: `cargo +nightly doc --locked --open --features nightly` + * To open docs for non-host architecture: `cargo doc --locked --open --target --workspace --exclude wdk-macros` + * `--target` is incompatible with `proc-macro` crates due to a [cargo bug](https://github.com/rust-lang/cargo/issues/10368) ### Policy on using Nightly/Unstable Features diff --git a/README.md b/README.md index 8cda0858..217b05d2 100644 --- a/README.md +++ b/README.md @@ -145,7 +145,7 @@ The crates in this repository are available from [`crates.io`](https://crates.io cargo make ``` -A `DriverCertificate.cer` file will be generated, and a signed driver package will be available at `target//package` +A signed driver package, including a `WDRLocalTestCert.cer` file, will be generated at `target//package`. If a specific target architecture was specified, the driver package will be generated at `target///package` ## Cargo Make @@ -159,7 +159,7 @@ When executing the default task, just `cargo make` make also works since the `de ### Argument Forwarding -`windows-drivers-rs` extends `cargo make` to forward specific arguements 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). +`windows-drivers-rs` extends `cargo make` to forward specific arguements 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 diff --git a/crates/sample-kmdf-driver/Makefile.toml b/crates/sample-kmdf-driver/Makefile.toml index eaeeafc1..91a7bc9e 100644 --- a/crates/sample-kmdf-driver/Makefile.toml +++ b/crates/sample-kmdf-driver/Makefile.toml @@ -1 +1,4 @@ extend = "../../rust-driver-makefile.toml" + +[env] +WDK_BUILD_ADDITIONAL_INFVERIF_FLAGS = "/msft" diff --git a/crates/sample-kmdf-driver/README.md b/crates/sample-kmdf-driver/README.md index d5bd1737..a9d6fe16 100644 --- a/crates/sample-kmdf-driver/README.md +++ b/crates/sample-kmdf-driver/README.md @@ -12,9 +12,11 @@ ## Install 1. Copy the following to the DUT (Device Under Test: the computer you want to test the driver on): - 1. [`.\target\x86_64-pc-windows-msvc\debug\package`](.\target\x86_64-pc-windows-msvc\debug\package) - 2. [`.\DriverCertificate.cer`](.\DriverCertificate.cer) - 3. The version of `devgen.exe` from the WDK Developer Tools that matches the archtecture of your DUT + 1. The driver `package` folder located in the [Cargo Output Directory](https://doc.rust-lang.org/cargo/guide/build-cache.html). The Cargo Output Directory changes based off of build profile, target architecture, etc. + * Ex. `\target\x86_64-pc-windows-msvc\debug\package`, `\target\x86_64-pc-windows-msvc\release\package`, `\target\aarch64-pc-windows-msvc\debug\package`, `\target\aarch64-pc-windows-msvc\release\package`, + `\target\debug\package`, + `\target\release\package` + 2. The version of `devgen.exe` from the WDK Developer Tools that matches the archtecture of your DUT * Ex. `C:\Program Files\Windows Kits\10\Tools\10.0.22621.0\x64\devgen.exe`. Note: This path will vary based off your WDK environment 2. Install the Certificate on the DUT: 1. Double click the certificate diff --git a/crates/wdk-build/Cargo.toml b/crates/wdk-build/Cargo.toml index 3471cc76..192f79c1 100644 --- a/crates/wdk-build/Cargo.toml +++ b/crates/wdk-build/Cargo.toml @@ -13,7 +13,7 @@ categories = ["development-tools::build-utils", "development-tools::ffi"] bindgen.workspace = true serde.workspace = true serde_json.workspace = true -clap = { version = "4.4.7", features = ["derive"] } +clap = { version = "4.4.11", features = ["derive"] } clap-cargo = "0.13.0" thiserror = "1.0.55" windows = { version = "0.51.1", features = [ diff --git a/crates/wdk-build/src/cargo_make.rs b/crates/wdk-build/src/cargo_make.rs index 8c12f50d..30416eb9 100644 --- a/crates/wdk-build/src/cargo_make.rs +++ b/crates/wdk-build/src/cargo_make.rs @@ -9,13 +9,24 @@ use clap::{Args, Parser}; +use crate::{ + utils::{detect_wdk_content_root, get_latest_windows_sdk_version, PathExt}, + CPUArchitecture, + ConfigError, +}; + +const PATH_ENV_VAR: &str = "Path"; + /// The name of the environment variable that cargo-make uses during `cargo /// build` and `cargo test` commands const CARGO_MAKE_CARGO_BUILD_TEST_FLAGS_ENV_VAR: &str = "CARGO_MAKE_CARGO_BUILD_TEST_FLAGS"; const CARGO_MAKE_PROFILE_ENV_VAR: &str = "CARGO_MAKE_PROFILE"; const CARGO_MAKE_CARGO_PROFILE_ENV_VAR: &str = "CARGO_MAKE_CARGO_PROFILE"; +const CARGO_MAKE_CRATE_CUSTOM_TRIPLE_TARGET_DIRECTORY_ENV_VAR: &str = + "CARGO_MAKE_CRATE_CUSTOM_TRIPLE_TARGET_DIRECTORY"; const CARGO_MAKE_RUST_DEFAULT_TOOLCHAIN_ENV_VAR: &str = "CARGO_MAKE_RUST_DEFAULT_TOOLCHAIN"; +const WDK_BUILD_OUTPUT_DIRECTORY_ENV_VAR: &str = "WDK_BUILD_OUTPUT_DIRECTORY"; /// `clap` uses an exit code of 2 for usage errors: const CLAP_USAGE_EXIT_CODE: i32 = 2; @@ -239,9 +250,9 @@ impl ParseCargoArg for CompilationOptions { eprintln!("the `--release` flag should not be specified with the `--profile` flag"); std::process::exit(CLAP_USAGE_EXIT_CODE); } - match std::env::var(CARGO_MAKE_PROFILE_ENV_VAR) + let cargo_make_cargo_profile = match std::env::var(CARGO_MAKE_PROFILE_ENV_VAR) .unwrap_or_else(|_| panic!("{CARGO_MAKE_PROFILE_ENV_VAR} should be set by cargo-make.")) - .as_ref() + .as_str() { "release" => { // cargo-make release profile sets the `--profile release` flag @@ -259,26 +270,33 @@ impl ParseCargoArg for CompilationOptions { CARGO_MAKE_CARGO_BUILD_TEST_FLAGS_ENV_VAR, "--profile release", ); + "release".to_string() } _ => { // All other cargo-make profiles do not set a specific cargo profile. Cargo // profiles set by --release, --profile , or -p (after the // cargo-make task name) are forwarded to cargo commands if self.release { - println!("{CARGO_MAKE_CARGO_PROFILE_ENV_VAR}=release"); append_to_space_delimited_env_var( CARGO_MAKE_CARGO_BUILD_TEST_FLAGS_ENV_VAR, "--release", ); + "release".to_string() } else if let Some(profile) = &self.profile { - println!("{CARGO_MAKE_CARGO_PROFILE_ENV_VAR}={profile}"); append_to_space_delimited_env_var( CARGO_MAKE_CARGO_BUILD_TEST_FLAGS_ENV_VAR, format!("--profile {profile}").as_str(), ); + profile.into() + } else { + std::env::var(CARGO_MAKE_CARGO_PROFILE_ENV_VAR).unwrap_or_else(|_| { + panic!("{CARGO_MAKE_CARGO_PROFILE_ENV_VAR} should be set by cargo-make.") + }) } } - } + }; + + println!("{CARGO_MAKE_CARGO_PROFILE_ENV_VAR}={cargo_make_cargo_profile}"); if let Some(jobs) = &self.jobs { append_to_space_delimited_env_var( @@ -295,6 +313,8 @@ impl ParseCargoArg for CompilationOptions { ); } + configure_wdf_build_output_dir(&self.target, &cargo_make_cargo_profile); + if let Some(timings_option) = &self.timings { timings_option.as_ref().map_or_else( || { @@ -363,7 +383,7 @@ pub fn validate_and_forward_args() { .to_string_lossy() .strip_prefix('+') .expect("Toolchain arg should have a + prefix") - .to_owned(), + .to_string(), ) } else { None @@ -387,18 +407,152 @@ pub fn validate_and_forward_args() { command_line_interface.manifest_options.parse_cargo_arg(); forward_env_var_to_cargo_make(CARGO_MAKE_CARGO_BUILD_TEST_FLAGS_ENV_VAR); + forward_env_var_to_cargo_make(WDK_BUILD_OUTPUT_DIRECTORY_ENV_VAR); } -fn append_to_space_delimited_env_var>(env_var_name: S, string_to_append: S) { - let env_var_name = env_var_name.as_ref(); - let string_to_append = string_to_append.as_ref(); +/// Prepends the path variable with the necessary paths to access WDK tools +/// +/// # Errors +/// +/// This function returns a [`ConfigError::WDKContentRootDetectionError`] if the +/// WDK content root directory could not be found. +/// Sets up the path for the WDK build environment. +/// +/// # Panics +/// +/// This function will panic if the CPU architecture cannot be determined from +/// `std::env::consts::ARCH` or if the PATH variable contains non-UTF8 +/// characters. +pub fn setup_path() -> Result<(), ConfigError> { + let Some(wdk_content_root) = detect_wdk_content_root() else { + return Err(ConfigError::WDKContentRootDetectionError); + }; + let version = get_latest_windows_sdk_version(&wdk_content_root.join("Lib"))?; + let host_arch = CPUArchitecture::try_from_cargo_str(std::env::consts::ARCH) + .expect("The rust standard library should always set std::env::consts::ARCH"); + + let wdk_bin_root = wdk_content_root + .join(format!("bin/{version}")) + .canonicalize()? + .strip_extended_length_path_prefix()?; + let host_windows_sdk_ver_bin_path = match host_arch { + CPUArchitecture::AMD64 => wdk_bin_root + .join(host_arch.as_windows_str()) + .canonicalize()? + .strip_extended_length_path_prefix()? + .to_str() + .expect("x64 host_windows_sdk_ver_bin_path should only contain valid UTF8") + .to_string(), + CPUArchitecture::ARM64 => wdk_bin_root + .join(host_arch.as_windows_str()) + .canonicalize()? + .strip_extended_length_path_prefix()? + .to_str() + .expect("ARM64 host_windows_sdk_ver_bin_path should only contain valid UTF8") + .to_string(), + }; + + // Some tools (ex. inf2cat) are only available in the x86 folder + let x86_windows_sdk_ver_bin_path = wdk_bin_root + .join("x86") + .canonicalize()? + .strip_extended_length_path_prefix()? + .to_str() + .expect("x86_windows_sdk_ver_bin_path should only contain valid UTF8") + .to_string(); + prepend_to_semicolon_delimited_env_var( + PATH_ENV_VAR, + // By putting host path first, host versions of tools are prioritized over + // x86 versions + format!("{host_windows_sdk_ver_bin_path};{x86_windows_sdk_ver_bin_path}",), + ); + + let wdk_tool_root = wdk_content_root + .join(format!("Tools/{version}")) + .canonicalize()? + .strip_extended_length_path_prefix()?; + let arch_specific_wdk_tool_root = wdk_tool_root + .join(host_arch.as_windows_str()) + .canonicalize()? + .strip_extended_length_path_prefix()?; + prepend_to_semicolon_delimited_env_var( + PATH_ENV_VAR, + arch_specific_wdk_tool_root + .to_str() + .expect("arch_specific_wdk_tool_root should only contain valid UTF8"), + ); + + forward_env_var_to_cargo_make(PATH_ENV_VAR); + Ok(()) +} - let mut env_var_value = std::env::var(env_var_name).unwrap_or_default(); +fn configure_wdf_build_output_dir(target_arg: &Option, cargo_make_cargo_profile: &str) { + let cargo_make_crate_custom_triple_target_directory = std::env::var( + CARGO_MAKE_CRATE_CUSTOM_TRIPLE_TARGET_DIRECTORY_ENV_VAR, + ) + .unwrap_or_else(|_| { + panic!( + "{CARGO_MAKE_CRATE_CUSTOM_TRIPLE_TARGET_DIRECTORY_ENV_VAR} should be set by \ + cargo-make." + ) + }); + + let wdk_build_output_directory = { + let mut output_dir = cargo_make_crate_custom_triple_target_directory; + + // Providing the "--target" flag causes the build output to go into a subdirectory: https://doc.rust-lang.org/cargo/guide/build-cache.html#build-cache + if let Some(target) = target_arg { + output_dir += "/"; + output_dir += target; + } + + if cargo_make_cargo_profile == "dev" { + // Cargo puts "dev" profile builds in the "debug" target folder: https://doc.rust-lang.org/cargo/guide/build-cache.html#build-cache. + // This also supports cargo-make profile of "development" since cargo-make maps + // CARGO_MAKE_PROFILE value of "development" to CARGO_MAKE_CARGO_PROFILE of + // "dev". + output_dir += "/debug"; + } else { + output_dir += "/"; + output_dir += &cargo_make_cargo_profile; + } + + output_dir + }; + std::env::set_var( + WDK_BUILD_OUTPUT_DIRECTORY_ENV_VAR, + wdk_build_output_directory, + ); +} + +fn append_to_space_delimited_env_var(env_var_name: S, string_to_append: T) +where + S: AsRef, + T: AsRef, +{ + let env_var_name: &str = env_var_name.as_ref(); + let string_to_append: &str = string_to_append.as_ref(); + + let mut env_var_value: String = std::env::var(env_var_name).unwrap_or_default(); env_var_value.push(' '); env_var_value.push_str(string_to_append); std::env::set_var(env_var_name, env_var_value.trim()); } +fn prepend_to_semicolon_delimited_env_var(env_var_name: S, string_to_prepend: T) +where + S: AsRef, + T: AsRef, +{ + let env_var_name = env_var_name.as_ref(); + let string_to_prepend = string_to_prepend.as_ref(); + + let mut env_var_value = string_to_prepend.to_string(); + env_var_value.push(';'); + env_var_value.push_str(std::env::var(env_var_name).unwrap_or_default().as_str()); + std::env::set_var(env_var_name, env_var_value); +} + fn forward_env_var_to_cargo_make>(env_var_name: S) { let env_var_name = env_var_name.as_ref(); diff --git a/crates/wdk-build/src/lib.rs b/crates/wdk-build/src/lib.rs index 8cdd7600..55b002dc 100644 --- a/crates/wdk-build/src/lib.rs +++ b/crates/wdk-build/src/lib.rs @@ -129,6 +129,13 @@ pub enum ConfigError { /// Error returned when a [`Config`] fails to be exported to the environment #[error(transparent)] ExportError(#[from] ExportError), + + /// Error returned when a [`Config`] fails to be serialized + #[error( + "WDKContentRoot should be able to be detected. Ensure that the WDK is installed, or that \ + the environment setup scripts in the eWDK have been run." + )] + WDKContentRootDetectionError, } /// Errors that could result from parsing a configuration from a [`wdk-build`] @@ -400,10 +407,10 @@ impl Config { .join(sdk_version) .join(match self.driver_config { DriverConfig::WDM() | DriverConfig::KMDF(_) => { - format!("km/{}", self.cpu_architecture.to_windows_str(),) + format!("km/{}", self.cpu_architecture.as_windows_str(),) } DriverConfig::UMDF(_) => { - format!("um/{}", self.cpu_architecture.to_windows_str(),) + format!("um/{}", self.cpu_architecture.as_windows_str(),) } }); if !windows_sdk_library_path.is_dir() { @@ -423,7 +430,7 @@ impl Config { DriverConfig::KMDF(kmdf_config) => { let kmdf_library_path = library_directory.join(format!( "wdf/kmdf/{}/{}.{}", - self.cpu_architecture.to_windows_str(), + self.cpu_architecture.as_windows_str(), kmdf_config.kmdf_version_major, kmdf_config.kmdf_version_minor )); @@ -441,7 +448,7 @@ impl Config { DriverConfig::UMDF(umdf_config) => { let umdf_library_path = library_directory.join(format!( "wdf/umdf/{}/{}.{}", - self.cpu_architecture.to_windows_str(), + self.cpu_architecture.as_windows_str(), umdf_config.umdf_version_major, umdf_config.umdf_version_minor )); @@ -653,12 +660,39 @@ impl CPUArchitecture { /// Converts [`CPUArchitecture`] to the string corresponding to what the /// architecture is typically referred to in Windows #[must_use] - pub const fn to_windows_str(&self) -> &str { + pub const fn as_windows_str(&self) -> &str { match self { Self::AMD64 => "x64", Self::ARM64 => "ARM64", } } + + /// Converts [`CPUArchitecture`] to the string corresponding to what the + /// architecture is typically referred to in Windows + #[deprecated( + since = "0.2.0", + note = "CPUArchitecture.to_windows_str() was mis-named when originally created, since the \ + conversion from CPUArchitecture to str is free. Use \ + CPUArchitecture.as_windows_str instead." + )] + #[must_use] + pub const fn to_windows_str(&self) -> &str { + self.as_windows_str() + } + + /// Converts from a cargo-provided [`std::str`] to a [`CPUArchitecture`]. + /// + /// # + #[must_use] + pub fn try_from_cargo_str>(cargo_str: S) -> Option { + // Specifically not using the [`std::convert::TryFrom`] trait to be more + // explicit in function name, since only arch strings from cargo are handled. + match cargo_str.as_ref() { + "x86_64" => Some(Self::AMD64), + "aarch64" => Some(Self::ARM64), + _ => None, + } + } } #[cfg(test)] @@ -821,4 +855,17 @@ mod tests { ); assert_eq!(config.cpu_architecture, CPUArchitecture::ARM64); } + + #[test] + fn test_try_from_cargo_str() { + assert_eq!( + CPUArchitecture::try_from_cargo_str("x86_64"), + Some(CPUArchitecture::AMD64) + ); + assert_eq!( + CPUArchitecture::try_from_cargo_str("aarch64"), + Some(CPUArchitecture::ARM64) + ); + assert_eq!(CPUArchitecture::try_from_cargo_str("arm"), None); + } } diff --git a/crates/wdk-build/src/utils.rs b/crates/wdk-build/src/utils.rs index d8fa6fcb..1ffd6e64 100644 --- a/crates/wdk-build/src/utils.rs +++ b/crates/wdk-build/src/utils.rs @@ -276,13 +276,9 @@ pub fn detect_cpu_architecture_in_build_script() -> CPUArchitecture { build.rs", ); - if target_arch == "x86_64" { - return CPUArchitecture::AMD64; - } else if target_arch == "aarch64" { - return CPUArchitecture::ARM64; - } - - panic!("The target architecture, {target_arch}, is currently not supported."); + CPUArchitecture::try_from_cargo_str(&target_arch).unwrap_or_else(|| { + panic!("The target architecture, {target_arch}, is currently not supported.") + }) } #[cfg(test)] diff --git a/rust-driver-makefile.toml b/rust-driver-makefile.toml index b8f278eb..9bc78db2 100644 --- a/rust-driver-makefile.toml +++ b/rust-driver-makefile.toml @@ -1,12 +1,9 @@ # This file can be leveraged to build downstream drivers. See examples at https://github.com/microsoft/Windows-rust-drivers-samples -# FIXME: replace all script blocks with cargo-make commands: "Favor commands over scripts, as commands support more features such as automatic dependencies installation, argument functions, and more..." # FIXME: this flow is based on the signing process of a KMDF PNP driver. There should be different flows availabe for different types of drivers as outlined in https://learn.microsoft.com/en-us/windows-hardware/drivers/install/test-signing-driver-packages - [config] min_version = "0.37.3" init_task = "wdk-build-init" -default_to_workspace = false [env] # This allows all workspace members to access this makefile @@ -14,15 +11,10 @@ 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 = "" - -VC_BUILD_DIR = "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Auxiliary\\Build\\vcvarsamd64_x86.bat" +CARGO_MAKE_CARGO_BUILD_TEST_FLAGS = { unset = true } # FIXME: add --locked for CI builds using CARGO_MAKE_PR and CARGO_MAKE_CI -# Cargo puts "dev" profile builds in the "debug" target folder: https://doc.rust-lang.org/cargo/guide/build-cache.html#build-cache. This supports cargo-make profile values of both "development" and "dev" -OUTPUT_DIR = { source = "${CARGO_MAKE_CARGO_PROFILE}", default_value = "${CARGO_MAKE_CRATE_CUSTOM_TRIPLE_TARGET_DIRECTORY}\\${CARGO_MAKE_CARGO_PROFILE}", mapping = { "dev" = "${CARGO_MAKE_CRATE_CUSTOM_TRIPLE_TARGET_DIRECTORY}\\debug" } } - [plugins.impl.rust-env-update] script = ''' assert ${task.has_script} "script is required for rust-env-update plugin" @@ -39,7 +31,7 @@ assert_eq ${out.code} 0 "[tasks.${task.name}]'s install_crate failed with exit c # Execute rust-script taskjson = json_parse ${task.as_json} -filepath = set "./target/cargo-make-script/${task.name}/main.rs" +filepath = set "${CARGO_MAKE_CRATE_CUSTOM_TRIPLE_TARGET_DIRECTORY}/cargo-make-script/${task.name}/main.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} @@ -51,19 +43,20 @@ else writefile ${filepath} ${taskjson.script} end cli_args = array_join ${flow.cli.args} " " +# rust-script will try to consume --help, so help must be passed via TRIGGER_HELP env var in order to provide clap help output trigger_help = get_env TRIGGER_HELP if not is_empty ${trigger_help} cli_args = concat ${cli_args} " --help" end -out = exec --fail-on-error rust-script --base-path ${taskjson.env.CARGO_MAKE_CURRENT_TASK_INITIAL_MAKEFILE_DIRECTORY} ./target/cargo-make-script/${task.name}/main.rs %{cli_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 ./target/cargo-make-script/${task.name}/main.rs" +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}/main.rs %{cli_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}/main.rs" # 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 stdout_first_line = array_get ${script_output_array} 0 - assert_eq ${stdout_first_line} "FORWARDING ARGS TO CARGO-MAKE:" "[tasks.${task.name}]'s script output did not begin with \"FORWARDING ARGS TO CARGO-MAKE:\". Was `--help` passed as one of the arguments?\nstdout:\n${out.stdout}\nstderr:\n${out.stderr}\nThe temporary rust-script file is located at ./target/cargo-make-script/${task.name}/main.rs" + assert_eq ${stdout_first_line} "FORWARDING ARGS TO CARGO-MAKE:" "[tasks.${task.name}]'s script output did not begin with \"FORWARDING ARGS TO CARGO-MAKE:\". Was `--help` passed as one of the arguments?\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}/main.rs" array_remove ${script_output_array} 0 for line in ${script_output_array} parts = split ${line} = @@ -87,6 +80,7 @@ script = ''' #![allow(unused_doc_comments)] wdk_build::cargo_make::validate_and_forward_args(); +wdk_build::cargo_make::setup_path()?; ''' [tasks.help] @@ -94,56 +88,225 @@ workspace = false env = { "TRIGGER_HELP" = "1" } run_task = "wdk-build-init" -[tasks.rename-dll-to-sys] +[tasks.copy-inx-to-output] +script_runner = "@rust" +script = ''' +use std::path::PathBuf; + +let crate_name = std::env::var("CARGO_MAKE_CRATE_FS_NAME").expect("CARGO_MAKE_CRATE_FS_NAME should be set by cargo-make"); +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 output_directory = std::env::var("WDK_BUILD_OUTPUT_DIRECTORY").expect("WDK_BUILD_OUTPUT_DIRECTORY should be set by cargo-make via the env section of rust-driver-makefile.toml"); + +let output_folder_path = PathBuf::from(&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 source_file = format!("{cargo_make_working_directory}/{crate_name}.inx"); +let destination_file = format!("{output_directory}/{crate_name}.inf"); +std::fs::copy(&source_file, &destination_file).expect(&format!("copy of '{source_file}' file to '{destination_file}' file should succeed")); +''' + +[tasks.generate-sys-file] dependencies = ["build"] +script_runner = "@rust" script = ''' -echo "%OUTPUT_DIR%" -cd "%OUTPUT_DIR%" -mkdir package -if exist package\%CARGO_MAKE_CRATE_FS_NAME%.sys ( - del package\%CARGO_MAKE_CRATE_FS_NAME%.sys -) -rename %CARGO_MAKE_CRATE_FS_NAME%.dll %CARGO_MAKE_CRATE_FS_NAME%.sys -copy %CARGO_MAKE_CRATE_FS_NAME%.sys package\%CARGO_MAKE_CRATE_FS_NAME%.sys +let crate_name = std::env::var("CARGO_MAKE_CRATE_FS_NAME").expect("CARGO_MAKE_CRATE_FS_NAME should be set by cargo-make"); +let output_directory = std::env::var("WDK_BUILD_OUTPUT_DIRECTORY").expect("WDK_BUILD_OUTPUT_DIRECTORY should be set by cargo-make via the env section of rust-driver-makefile.toml"); + +let source_file = format!("{output_directory}/{crate_name}.dll"); +let destination_file = format!("{output_directory}/{crate_name}.sys"); +std::fs::copy(&source_file, &destination_file).expect(&format!("copy of '{source_file}' file to '{destination_file}' file should succeed")); ''' [tasks.stampinf] -dependencies = ["build"] +dependencies = ["copy-inx-to-output"] +command = "stampinf" +args = [ + "-f", + "${WDK_BUILD_OUTPUT_DIRECTORY}/${CARGO_MAKE_CRATE_FS_NAME}.inf", + "-d", + "*", + "-a", + "amd64", + "-c", + "${CARGO_MAKE_CRATE_FS_NAME}.cat", + "-v", + "*", + "-k", + "1.33", +] + +[tasks.infverif] +dependencies = ["stampinf"] +command = "infverif" +args = [ + "/v", + "/w", + "@@split(WDK_BUILD_ADDITIONAL_INFVERIF_FLAGS, )", + "${WDK_BUILD_OUTPUT_DIRECTORY}/${CARGO_MAKE_CRATE_FS_NAME}.inf", +] + +[tasks.copy-sys-to-package] +dependencies = ["generate-sys-file"] +script_runner = "@rust" script = ''' -copy "%CARGO_MAKE_WORKING_DIRECTORY%\%CARGO_MAKE_CRATE_FS_NAME%.inx" "%OUTPUT_DIR%\package\%CARGO_MAKE_CRATE_FS_NAME%.inf" -stampinf.exe -f "%OUTPUT_DIR%\package\%CARGO_MAKE_CRATE_FS_NAME%.inf" -d * -a amd64 -c %CARGO_MAKE_CRATE_FS_NAME%.cat -v * -k 1.33 -n +use std::path::PathBuf; + +let crate_name = std::env::var("CARGO_MAKE_CRATE_FS_NAME").expect("CARGO_MAKE_CRATE_FS_NAME should be set by cargo-make"); +let output_directory = std::env::var("WDK_BUILD_OUTPUT_DIRECTORY").expect("WDK_BUILD_OUTPUT_DIRECTORY should be set by cargo-make via the env section of rust-driver-makefile.toml"); + +let package_folder_path = [output_directory.as_str(), "package"].iter().collect::(); +if !package_folder_path.exists() { + std::fs::create_dir(&package_folder_path).expect(&format!("creation of '{}' folder should succeed", package_folder_path.display())); +} + +let source_file = format!("{output_directory}/{crate_name}.sys"); +let destination_file = format!("{output_directory}/package/{crate_name}.sys"); +std::fs::copy(&source_file, &destination_file).expect(&format!("copy of '{source_file}' file to '{destination_file}' file should succeed")); ''' -[tasks.copypdb] +[tasks.copy-pdb-to-package] dependencies = ["build"] +script_runner = "@rust" script = ''' -cd "%OUTPUT_DIR%" -copy %CARGO_MAKE_CRATE_FS_NAME%.pdb package\%CARGO_MAKE_CRATE_FS_NAME%.pdb +use std::path::PathBuf; + +let crate_name = std::env::var("CARGO_MAKE_CRATE_FS_NAME").expect("CARGO_MAKE_CRATE_FS_NAME should be set by cargo-make"); +let output_directory = std::env::var("WDK_BUILD_OUTPUT_DIRECTORY").expect("WDK_BUILD_OUTPUT_DIRECTORY should be set by cargo-make via the env section of rust-driver-makefile.toml"); + +let package_folder_path = [output_directory.as_str(), "package"].iter().collect::(); +if !package_folder_path.exists() { + std::fs::create_dir(&package_folder_path).expect(&format!("creation of '{}' folder should succeed", package_folder_path.display())); +} + +let source_file = format!("{output_directory}/{crate_name}.pdb"); +let destination_file = format!("{output_directory}/package/{crate_name}.pdb"); +std::fs::copy(&source_file, &destination_file).expect(&format!("copy of '{source_file}' file to '{destination_file}' file should succeed")); ''' -[tasks.inf2cat] +[tasks.copy-inf-to-package] dependencies = ["stampinf"] +script_runner = "@rust" script = ''' -inf2cat.exe /driver:"%OUTPUT_DIR%\package" /os:10_NI_X64,10_VB_X64 /uselocaltime /verbose +use std::path::PathBuf; + +let crate_name = std::env::var("CARGO_MAKE_CRATE_FS_NAME").expect("CARGO_MAKE_CRATE_FS_NAME should be set by cargo-make"); +let output_directory = std::env::var("WDK_BUILD_OUTPUT_DIRECTORY").expect("WDK_BUILD_OUTPUT_DIRECTORY should be set by cargo-make via the env section of rust-driver-makefile.toml"); + +let package_folder_path = [output_directory.as_str(), "package"].iter().collect::(); +if !package_folder_path.exists() { + std::fs::create_dir(&package_folder_path).expect(&format!("creation of '{}' folder should succeed", package_folder_path.display())); +} + +let source_file = format!("{output_directory}/{crate_name}.inf"); +let destination_file = format!("{output_directory}/package/{crate_name}.inf"); +std::fs::copy(&source_file, &destination_file).expect(&format!("copy of '{source_file}' file to '{destination_file}' file should succeed")); ''' -[tasks.infverif] -dependencies = ["stampinf"] +[tasks.copy-map-to-package] +dependencies = ["build"] +script_runner = "@rust" +script = ''' +use std::path::PathBuf; + +let crate_name = std::env::var("CARGO_MAKE_CRATE_FS_NAME").expect("CARGO_MAKE_CRATE_FS_NAME should be set by cargo-make"); +let output_directory = std::env::var("WDK_BUILD_OUTPUT_DIRECTORY").expect("WDK_BUILD_OUTPUT_DIRECTORY should be set by cargo-make via the env section of rust-driver-makefile.toml"); + +let package_folder_path = [output_directory.as_str(), "package"].iter().collect::(); +if !package_folder_path.exists() { + std::fs::create_dir(&package_folder_path).expect(&format!("creation of '{}' folder should succeed", package_folder_path.display())); +} + +let source_file = format!("{output_directory}/deps/{crate_name}.map"); +let destination_file = format!("{output_directory}/package/{crate_name}.map"); +std::fs::copy(&source_file, &destination_file).expect(&format!("copy of '{source_file}' file to '{destination_file}' file should succeed")); +''' + +[tasks.inf2cat] +dependencies = ["copy-sys-to-package", "copy-inf-to-package"] +command = "inf2cat" +args = [ + "/driver:${WDK_BUILD_OUTPUT_DIRECTORY}/package", + "/os:10_NI_X64,10_VB_X64", # TODO: this should be a parameter + "/uselocaltime", +] + +[tasks.generate-certificate-if-needed] +# This script can't be in a `condition_script` block because of https://github.com/sagiegurari/cargo-make/issues/987 +script_runner = "@duckscript" script = ''' -"%WDKToolRoot%\%Platform%\infverif.exe" /v /w "%OUTPUT_DIR%\package\%CARGO_MAKE_CRATE_FS_NAME%.inf" /msft +out = exec certmgr.exe -put -s WDRTestCertStore -c -n WDRLocalTestCert ${WDK_BUILD_OUTPUT_DIRECTORY}/WDRLocalTestCert.cer +if not eq ${out.code} 0 + echo WDRLocalTestCert not found in WDRTestCertStore. Generating new certificate. + cm_run_task generate-certificate +end ''' -[tasks.sign] -dependencies = ["rename-dll-to-sys", "inf2cat", "infverif"] +[tasks.generate-certificate] +private = true +command = "makecert" +args = [ + "-r", + "-pe", + "-a", + "SHA256", + "-eku", + "1.3.6.1.5.5.7.3.3", + "-ss", + "WDRTestCertStore", # TODO: this should be a parameter + "-n", + "CN=WDRLocalTestCert", # TODO: this should be a parameter + "${WDK_BUILD_OUTPUT_DIRECTORY}/WDRLocalTestCert.cer", +] + +[tasks.copy-certificate-to-package] +dependencies = ["generate-certificate-if-needed"] +script_runner = "@rust" script = ''' -call "%VC_BUILD_DIR%" -if not exist DriverCertificate.cer ( - makecert -r -pe -ss PrivateCertStore -n CN=DriverCertificate DriverCertificate.cer -) else ( - echo Certificate already exists. -) -signtool sign /a /v /s PrivateCertStore /n DriverCertificate /fd certHash /t http://timestamp.digicert.com "%OUTPUT_DIR%\package\%CARGO_MAKE_CRATE_FS_NAME%.cat" +use std::path::PathBuf; + +let output_directory = std::env::var("WDK_BUILD_OUTPUT_DIRECTORY").expect("WDK_BUILD_OUTPUT_DIRECTORY should be set by cargo-make via the env section of rust-driver-makefile.toml"); + +let package_folder_path = [output_directory.as_str(), "package"].iter().collect::(); +if !package_folder_path.exists() { + std::fs::create_dir(&package_folder_path).expect(&format!("creation of '{}' folder should succeed", package_folder_path.display())); +} + +let source_file = format!("{output_directory}/WDRLocalTestCert.cer"); +let destination_file = format!("{output_directory}/package/WDRLocalTestCert.cer"); +std::fs::copy(&source_file, &destination_file).expect(&format!("copy of '{source_file}' file to '{destination_file}' file should succeed")); ''' +[tasks.signtool] +dependencies = ["inf2cat", "generate-certificate-if-needed"] +command = "signtool" +args = [ + "sign", + "/v", + "/s", + "WDRTestCertStore", # TODO: this should be a parameter + "/n", + "WDRLocalTestCert", # TODO: this should be a parameter + "/t", + "http://timestamp.digicert.com", + "/fd", + "SHA256", + "${WDK_BUILD_OUTPUT_DIRECTORY}/package/${CARGO_MAKE_CRATE_FS_NAME}.cat", +] + +[tasks.package-driver] +dependencies = [ + "copy-sys-to-package", + "copy-pdb-to-package", + "copy-inf-to-package", + "copy-map-to-package", + "copy-certificate-to-package", + "signtool", + "infverif", +] + [tasks.default] -alias = "sign" +alias = "package-driver" + +# TODO: mark drivers From 82db40f8286b82d4faf971de4a010feecece1b1d Mon Sep 17 00:00:00 2001 From: Melvin Wang Date: Fri, 12 Jan 2024 13:12:54 -0800 Subject: [PATCH 5/7] ci: add support for different target architectures in pipelines --- .github/workflows/build.yaml | 12 +++++++---- .github/workflows/code-formatting-check.yaml | 2 +- .github/workflows/docs.yaml | 21 ++++++++++++++++++-- .github/workflows/lint.yaml | 15 +++++++++----- .github/workflows/test.yaml | 11 ++++++---- crates/sample-kmdf-driver/Cargo.toml | 2 ++ rust-driver-makefile.toml | 2 -- 7 files changed, 47 insertions(+), 18 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 0d9f1c4f..087269a4 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -25,6 +25,10 @@ jobs: - dev - release + target_triple: + - x86_64-pc-windows-msvc + - aarch64-pc-windows-msvc + steps: - name: Checkout Repository uses: actions/checkout@v4 @@ -44,15 +48,15 @@ jobs: uses: dtolnay/rust-toolchain@master with: toolchain: ${{ matrix.rust_toolchain }} + targets: ${{ matrix.target_triple }} - name: Run Cargo Build - run: cargo build --locked --profile ${{ matrix.cargo_profile }} --workspace + run: cargo +${{ matrix.rust_toolchain }} build --locked --profile ${{ matrix.cargo_profile }} --target ${{ matrix.target_triple }} --workspace - name: Install Cargo Make uses: taiki-e/install-action@v2 with: tool: cargo-make - - name: Build and Package Sample KMDF Driver - run: cargo make --cwd .\crates\sample-kmdf-driver --profile ${{ matrix.cargo_profile }} - continue-on-error: true # FIXME: Packaging tools in non-ewdk environments are not found + - name: Build and Package Sample Drivers + run: cargo make default +${{ matrix.rust_toolchain }} --locked --profile ${{ matrix.cargo_profile }} --target ${{ matrix.target_triple }} diff --git a/.github/workflows/code-formatting-check.yaml b/.github/workflows/code-formatting-check.yaml index 07d7d7ed..fe4ff92d 100644 --- a/.github/workflows/code-formatting-check.yaml +++ b/.github/workflows/code-formatting-check.yaml @@ -22,7 +22,7 @@ jobs: components: rustfmt - name: Run Cargo Format - run: cargo fmt --all -- --check + run: cargo +nightly fmt --all -- --check taplo-fmt: name: .toml Formatting Check diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index 86d31bce..7abf0af8 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -25,6 +25,10 @@ jobs: - dev - release + target_triple: + - x86_64-pc-windows-msvc + - aarch64-pc-windows-msvc + steps: - name: Checkout Repository uses: actions/checkout@v4 @@ -44,10 +48,23 @@ jobs: uses: dtolnay/rust-toolchain@master with: toolchain: ${{ matrix.rust_toolchain }} + targets: ${{ matrix.target_triple }} - name: Run Cargo Doc - run: cargo doc --locked --profile ${{ matrix.cargo_profile }} + # proc-macro crates must be excluded to avoid cargo doc bug: https://github.com/rust-lang/cargo/issues/10368 + run: cargo +${{ matrix.rust_toolchain }} doc --locked --profile ${{ matrix.cargo_profile }} --target ${{ matrix.target_triple }} --workspace --exclude wdk-macros - name: Run Cargo Doc (--features nightly) if: matrix.rust_toolchain == 'nightly' - run: cargo doc --locked --profile ${{ matrix.cargo_profile }} --features nightly + # proc-macro crates must be excluded to avoid cargo doc bug: https://github.com/rust-lang/cargo/issues/10368 + run: cargo +${{ matrix.rust_toolchain }} doc --locked --profile ${{ matrix.cargo_profile }} --target ${{ matrix.target_triple }} --workspace --exclude wdk-macros --features nightly + + - name: Run Cargo Doc w/ proc-macro crates + if: matrix.target_triple == 'x86_64-pc-windows-msvc' + # cargo doc can only generate documentation for proc-macro crates when --target is not specified due to a cargo doc bug: https://github.com/rust-lang/cargo/issues/7677 + run: cargo +${{ matrix.rust_toolchain }} doc --locked --profile ${{ matrix.cargo_profile }} + + - name: Run Cargo Doc w/ proc-macro crates (--features nightly) + if: ${{ matrix.target_triple == 'x86_64-pc-windows-msvc' && matrix.rust_toolchain == 'nightly' }} + # cargo doc can only generate documentation for proc-macro crates when --target is not specified due to a cargo doc bug: https://github.com/rust-lang/cargo/issues/7677 + run: cargo +${{ matrix.rust_toolchain }} doc --locked --profile ${{ matrix.cargo_profile }} --features nightly diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 1b41e18a..ad3e2be6 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -27,6 +27,10 @@ jobs: - dev - release + target_triple: + - x86_64-pc-windows-msvc + - aarch64-pc-windows-msvc + steps: - name: Checkout Repository uses: actions/checkout@v4 @@ -47,13 +51,14 @@ jobs: with: toolchain: ${{ matrix.rust_toolchain }} components: clippy + targets: ${{ matrix.target_triple }} - name: Run Cargo Clippy - run: cargo clippy --locked --profile ${{ matrix.cargo_profile }} --all-targets -- -D warnings + run: cargo +${{ matrix.rust_toolchain }} clippy --locked --profile ${{ matrix.cargo_profile }} --target ${{ matrix.target_triple }} --all-targets -- -D warnings - name: Run Cargo Clippy (--features nightly) if: matrix.rust_toolchain == 'nightly' - run: cargo clippy --locked --profile ${{ matrix.cargo_profile }} --all-targets --features nightly -- -D warnings + run: cargo +${{ matrix.rust_toolchain }} clippy --locked --profile ${{ matrix.cargo_profile }} --target ${{ matrix.target_triple }} --all-targets --features nightly -- -D warnings udeps: name: Detect Unused Cargo Dependencies @@ -79,8 +84,8 @@ jobs: } - name: Install Rust Toolchain (Nightly) - uses: dtolnay/rust-toolchain@nightly # Cargo udeps only supports running on nightly due to reliance on unstable dep-info feature: https://github.com/est31/cargo-udeps/issues/113, https://github.com/est31/cargo-udeps/issues/136 + uses: dtolnay/rust-toolchain@nightly - name: Install Cargo Udeps uses: taiki-e/install-action@v2 @@ -88,7 +93,7 @@ jobs: tool: cargo-udeps - name: Run Cargo Udeps - run: cargo udeps --locked --all-targets + run: cargo +nightly udeps --locked --all-targets - name: Run Cargo Udeps (--features nightly) - run: cargo udeps --locked --all-targets --features nightly + run: cargo +nightly udeps --locked --all-targets --features nightly diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index c168d7c3..c8414be7 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -25,6 +25,10 @@ jobs: - dev - release + target_triple: + - x86_64-pc-windows-msvc + # - aarch64-pc-windows-msvc FIXME: Add support for executing ARM64 tests. Maybe use target specific test runner in emulator: https://doc.rust-lang.org/cargo/reference/config.html#target + steps: - name: Checkout Repository uses: actions/checkout@v4 @@ -44,6 +48,7 @@ jobs: uses: dtolnay/rust-toolchain@master with: toolchain: ${{ matrix.rust_toolchain }} + targets: ${{ matrix.target_triple }} - name: Install Cargo Expand uses: taiki-e/install-action@v2 @@ -52,10 +57,8 @@ jobs: # FIXME: wdk-sys layout tests fail, but only on github hosted runner - name: Run Cargo Test - # Final driver crates must be excluded since theres no way to prevent linker args from being passed to their unit tests: https://github.com/rust-lang/cargo/issues/12663 - run: cargo test --locked --profile ${{ matrix.cargo_profile }} --workspace --exclude sample-* --exclude wdk-sys + run: cargo +${{ matrix.rust_toolchain }} test --locked --profile ${{ matrix.cargo_profile }} --target ${{ matrix.target_triple }} --workspace --exclude wdk-sys - name: Run Cargo Test (--features nightly) if: matrix.rust_toolchain == 'nightly' - # Final driver crates must be excluded since theres no way to prevent linker args from being passed to their unit tests: https://github.com/rust-lang/cargo/issues/12663 - run: cargo test --locked --profile ${{ matrix.cargo_profile }} --features nightly --workspace --exclude sample-* --exclude wdk-sys + run: cargo +${{ matrix.rust_toolchain }} test --locked --profile ${{ matrix.cargo_profile }} --target ${{ matrix.target_triple }} --workspace --exclude wdk-sys --features nightly diff --git a/crates/sample-kmdf-driver/Cargo.toml b/crates/sample-kmdf-driver/Cargo.toml index f35c4784..42fffe43 100644 --- a/crates/sample-kmdf-driver/Cargo.toml +++ b/crates/sample-kmdf-driver/Cargo.toml @@ -12,6 +12,8 @@ publish = false [lib] crate-type = ["cdylib"] +# Tests from root driver crates must be excluded since there's no way to prevent linker args from being passed to their unit tests: https://github.com/rust-lang/cargo/issues/12663 +test = false [dependencies] wdk.workspace = true diff --git a/rust-driver-makefile.toml b/rust-driver-makefile.toml index 9bc78db2..ce423e99 100644 --- a/rust-driver-makefile.toml +++ b/rust-driver-makefile.toml @@ -13,8 +13,6 @@ CARGO_MAKE_EXTEND_WORKSPACE_MAKEFILE = true # This is set to "" here to match the default behavior of Cargo. CARGO_MAKE_CARGO_BUILD_TEST_FLAGS = { unset = true } -# FIXME: add --locked for CI builds using CARGO_MAKE_PR and CARGO_MAKE_CI - [plugins.impl.rust-env-update] script = ''' assert ${task.has_script} "script is required for rust-env-update plugin" From 37782b62eff14e315c08e756ee9457f86adcfa95 Mon Sep 17 00:00:00 2001 From: Melvin Wang Date: Wed, 17 Jan 2024 14:49:41 -0800 Subject: [PATCH 6/7] feat: automatically determine whether driver packaging steps make sense to run on Cargo package --- README.md | 26 ++++++--- crates/sample-kmdf-driver/Cargo.toml | 2 + rust-driver-makefile.toml | 82 +++++++++++++++++++++++----- 3 files changed, 86 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 217b05d2..02876e72 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,13 @@ The crates in this repository are available from [`crates.io`](https://crates.io crate-type = ["cdylib"] ``` -4. Set crate panic strategy to `abort` in `Cargo.toml`: +4. Mark the crate as a driver with a wdk metadata section. This lets the cargo-make tasks know that the package is a driver and that the driver packaging steps need to run. + + ```toml + [package.metadata.wdk] + ``` + +5. Set crate panic strategy to `abort` in `Cargo.toml`: ```toml [profile.dev] @@ -66,7 +72,7 @@ The crates in this repository are available from [`crates.io`](https://crates.io lto = true # optional setting to enable Link Time Optimizations ``` -5. Create a `build.rs` and add the following snippet: +6. Create a `build.rs` and add the following snippet: ```rust fn main() -> Result<(), wdk_build::ConfigError> { @@ -75,13 +81,13 @@ The crates in this repository are available from [`crates.io`](https://crates.io } ``` -6. Mark your driver as `no_std` in `lib.rs`: +7. Mark your driver crate as `no_std` in `lib.rs`: ```rust #![no_std] ``` -7. Add a panic handler in `lib.rs`: +8. Add a panic handler in `lib.rs`: ```rust #[cfg(not(test))] @@ -89,7 +95,7 @@ The crates in this repository are available from [`crates.io`](https://crates.io ``` -8. Add a global allocator in `lib.rs`: +9. Optional: Add a global allocator in `lib.rs`: ```rust #[cfg(not(test))] @@ -100,7 +106,9 @@ The crates in this repository are available from [`crates.io`](https://crates.io static GLOBAL_ALLOCATOR: WDKAllocator = WDKAllocator; ``` -9. Add a DriverEntry in `lib.rs`: + 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. You are also free to use your own implementations of global allocators. + +10. Add a DriverEntry in `lib.rs`: ```rust use wdk_sys::{ @@ -118,7 +126,7 @@ The crates in this repository are available from [`crates.io`](https://crates.io } ``` -10. Add a `Makefile.toml`: +11. Add a `Makefile.toml`: ```toml extend = ".cargo-make-loadscripts/rust-driver-makefile.toml" @@ -137,9 +145,9 @@ The crates in this repository are available from [`crates.io`](https://crates.io """ ``` -11. Add an inx file that matches the name of your `cdylib` crate. +12. Add an inx file that matches the name of your `cdylib` crate. -12. Build the driver: +13. Build the driver: ```pwsh cargo make diff --git a/crates/sample-kmdf-driver/Cargo.toml b/crates/sample-kmdf-driver/Cargo.toml index 42fffe43..7711aab1 100644 --- a/crates/sample-kmdf-driver/Cargo.toml +++ b/crates/sample-kmdf-driver/Cargo.toml @@ -10,6 +10,8 @@ keywords = ["windows", "driver", "sample", "example", "wdf"] categories = ["hardware-support"] publish = false +[package.metadata.wdk] + [lib] crate-type = ["cdylib"] # Tests from root driver crates must be excluded since there's no way to prevent linker args from being passed to their unit tests: https://github.com/rust-lang/cargo/issues/12663 diff --git a/rust-driver-makefile.toml b/rust-driver-makefile.toml index ce423e99..cf85bf87 100644 --- a/rust-driver-makefile.toml +++ b/rust-driver-makefile.toml @@ -2,8 +2,9 @@ # FIXME: this flow is based on the signing process of a KMDF PNP driver. There should be different flows availabe for different types of drivers as outlined in https://learn.microsoft.com/en-us/windows-hardware/drivers/install/test-signing-driver-packages [config] -min_version = "0.37.3" +min_version = "0.37.8" init_task = "wdk-build-init" +reduce_output = false [env] # This allows all workspace members to access this makefile @@ -106,6 +107,7 @@ std::fs::copy(&source_file, &destination_file).expect(&format!("copy of '{source ''' [tasks.generate-sys-file] +private = true dependencies = ["build"] script_runner = "@rust" script = ''' @@ -118,6 +120,7 @@ std::fs::copy(&source_file, &destination_file).expect(&format!("copy of '{source ''' [tasks.stampinf] +private = true dependencies = ["copy-inx-to-output"] command = "stampinf" args = [ @@ -136,6 +139,7 @@ args = [ ] [tasks.infverif] +private = true dependencies = ["stampinf"] command = "infverif" args = [ @@ -165,6 +169,7 @@ std::fs::copy(&source_file, &destination_file).expect(&format!("copy of '{source ''' [tasks.copy-pdb-to-package] +private = true dependencies = ["build"] script_runner = "@rust" script = ''' @@ -184,6 +189,7 @@ std::fs::copy(&source_file, &destination_file).expect(&format!("copy of '{source ''' [tasks.copy-inf-to-package] +private = true dependencies = ["stampinf"] script_runner = "@rust" script = ''' @@ -203,6 +209,7 @@ std::fs::copy(&source_file, &destination_file).expect(&format!("copy of '{source ''' [tasks.copy-map-to-package] +private = true dependencies = ["build"] script_runner = "@rust" script = ''' @@ -222,6 +229,7 @@ std::fs::copy(&source_file, &destination_file).expect(&format!("copy of '{source ''' [tasks.inf2cat] +private = true dependencies = ["copy-sys-to-package", "copy-inf-to-package"] command = "inf2cat" args = [ @@ -230,19 +238,20 @@ args = [ "/uselocaltime", ] -[tasks.generate-certificate-if-needed] -# This script can't be in a `condition_script` block because of https://github.com/sagiegurari/cargo-make/issues/987 -script_runner = "@duckscript" -script = ''' +[tasks.generate-certificate] +private = true +condition_script = ''' +#!@duckscript + out = exec certmgr.exe -put -s WDRTestCertStore -c -n WDRLocalTestCert ${WDK_BUILD_OUTPUT_DIRECTORY}/WDRLocalTestCert.cer -if not eq ${out.code} 0 +if eq ${out.code} 0 + echo WDRLocalTestCert found in WDRTestCertStore. Skipping certificate generation. + exit 1 +else echo WDRLocalTestCert not found in WDRTestCertStore. Generating new certificate. - cm_run_task generate-certificate + exit 0 end ''' - -[tasks.generate-certificate] -private = true command = "makecert" args = [ "-r", @@ -259,7 +268,8 @@ args = [ ] [tasks.copy-certificate-to-package] -dependencies = ["generate-certificate-if-needed"] +private = true +dependencies = ["generate-certificate"] script_runner = "@rust" script = ''' use std::path::PathBuf; @@ -277,7 +287,8 @@ std::fs::copy(&source_file, &destination_file).expect(&format!("copy of '{source ''' [tasks.signtool] -dependencies = ["inf2cat", "generate-certificate-if-needed"] +private = true +dependencies = ["inf2cat", "generate-certificate"] command = "signtool" args = [ "sign", @@ -294,6 +305,7 @@ args = [ ] [tasks.package-driver] +private = true dependencies = [ "copy-sys-to-package", "copy-pdb-to-package", @@ -304,7 +316,47 @@ dependencies = [ "infverif", ] -[tasks.default] -alias = "package-driver" +[tasks.package-driver-flow] +# Only run flow if the current package is marked as a driver +condition_script = ''' +#!@duckscript + +# Execute Cargo Metadata to get Package information +out = exec --fail-on-error cargo metadata --no-deps --format-version 1 --manifest-path ${CARGO_MAKE_WORKING_DIRECTORY}/Cargo.toml +assert_eq ${out.code} 0 "cargo metadata failed with exit code: ${out.code}\nstdout:\n${out.stdout}\nstderr:\n${out.stderr}" + +manifest_metadata = json_parse --collection ${out.stdout} +packages = map_get ${manifest_metadata} packages +contains_wdk_metadata = set false + +for package in ${packages} + package_name = map_get ${package} name + + # Find metadata for the current package + if eq ${package_name} ${CARGO_MAKE_CRATE_NAME} + package_metadata = map_get ${package} metadata + + # Check if the package contains a metadata section + if is_map ${package_metadata} + + # Check if the package contains a package.metadata.wdk section + contains_wdk_metadata = map_contains_key ${package_metadata} wdk + end + end +end + +release --recursive ${manifest_metadata} + +# Run driver package-driver task if the package contains a package.metadata.wdk section +if ${contains_wdk_metadata} + echo Building and packaging driver: ${CARGO_MAKE_CRATE_NAME}... + exit 0 +else + echo ${CARGO_MAKE_CRATE_NAME} does not contain a package.metadata.wdk section in its manifest. Skipping package-driver task. + exit 1 +end +''' +run_task = "package-driver" -# TODO: mark drivers +[tasks.default] +alias = "package-driver-flow" From 790fbdd8330dd6b06b8cac2249373a55351aa568 Mon Sep 17 00:00:00 2001 From: Melvin Wang Date: Thu, 18 Jan 2024 14:36:47 -0800 Subject: [PATCH 7/7] feat: support multiple drivers (of same type) in same cargo workspace --- crates/wdk-build/src/cargo_make.rs | 76 +++++++++- rust-driver-makefile.toml | 224 ++++++++++++++++++----------- 2 files changed, 211 insertions(+), 89 deletions(-) diff --git a/crates/wdk-build/src/cargo_make.rs b/crates/wdk-build/src/cargo_make.rs index 30416eb9..334b9d9b 100644 --- a/crates/wdk-build/src/cargo_make.rs +++ b/crates/wdk-build/src/cargo_make.rs @@ -1,11 +1,14 @@ // Copyright (c) Microsoft Corporation // License: MIT OR Apache-2.0 -//! This module provides argument parsing functionality used by -//! `rust-driver-makefile.toml` to validate and forward arguments common to -//! cargo commands. It uses a combination of `clap` and `clap_cargo` to provide -//! a CLI very close to cargo's own, but only exposes the arguments supported by -//! `rust-driver-makefile.toml`. Help text and other `clap::Arg` +//! This module provides functions used in the rust scripts in +//! `rust-driver-makefile.toml`. This includes argument parsing functionality +//! used by `rust-driver-makefile.toml` to validate and forward arguments common +//! to cargo commands. It uses a combination of `clap` and `clap_cargo` to +//! provide a CLI very close to cargo's own, but only exposes the arguments +//! supported by `rust-driver-makefile.toml`. + +use std::path::{Path, PathBuf}; use clap::{Args, Parser}; @@ -26,6 +29,7 @@ const CARGO_MAKE_CARGO_PROFILE_ENV_VAR: &str = "CARGO_MAKE_CARGO_PROFILE"; const CARGO_MAKE_CRATE_CUSTOM_TRIPLE_TARGET_DIRECTORY_ENV_VAR: &str = "CARGO_MAKE_CRATE_CUSTOM_TRIPLE_TARGET_DIRECTORY"; const CARGO_MAKE_RUST_DEFAULT_TOOLCHAIN_ENV_VAR: &str = "CARGO_MAKE_RUST_DEFAULT_TOOLCHAIN"; +const CARGO_MAKE_CRATE_FS_NAME_ENV_VAR: &str = "CARGO_MAKE_CRATE_FS_NAME"; const WDK_BUILD_OUTPUT_DIRECTORY_ENV_VAR: &str = "WDK_BUILD_OUTPUT_DIRECTORY"; /// `clap` uses an exit code of 2 for usage errors: @@ -416,7 +420,6 @@ pub fn validate_and_forward_args() { /// /// This function returns a [`ConfigError::WDKContentRootDetectionError`] if the /// WDK content root directory could not be found. -/// Sets up the path for the WDK build environment. /// /// # Panics /// @@ -486,6 +489,67 @@ pub fn setup_path() -> Result<(), ConfigError> { Ok(()) } +/// Returns the path to the WDK build output directory for the current +/// cargo-make flow +/// +/// # Panics +/// +/// This function will panic if the `WDK_BUILD_OUTPUT_DIRECTORY` environment +/// variable is not set +#[must_use] +pub fn get_wdk_build_output_directory() -> PathBuf { + PathBuf::from( + std::env::var("WDK_BUILD_OUTPUT_DIRECTORY") + .expect("WDK_BUILD_OUTPUT_DIRECTORY should have been set by the wdk-build-init task"), + ) +} + +/// Returns the name of the current cargo package cargo-make is processing +/// +/// # Panics +/// +/// This function will panic if the `CARGO_MAKE_CRATE_FS_NAME` environment +/// variable is not set +#[must_use] +pub fn get_current_package_name() -> String { + std::env::var(CARGO_MAKE_CRATE_FS_NAME_ENV_VAR).unwrap_or_else(|_| { + panic!( + "{} should be set by cargo-make", + &CARGO_MAKE_CRATE_FS_NAME_ENV_VAR + ) + }) +} + +/// Copies the file or directory at `path_to_copy` to the Driver Package folder +/// +/// # Errors +/// +/// This function returns a [`ConfigError::IoError`] if the it encouters IO +/// errors while copying the file or creating the directory +/// +/// # Panics +/// +/// This function will panic if `path_to_copy` does end with a valid file or +/// directory name +pub fn copy_to_driver_package_folder>(path_to_copy: P) -> Result<(), ConfigError> { + let path_to_copy = path_to_copy.as_ref(); + + let package_folder_path = + get_wdk_build_output_directory().join(format!("{}_package", get_current_package_name())); + if !package_folder_path.exists() { + std::fs::create_dir(&package_folder_path)?; + } + + let destination_path = package_folder_path.join( + path_to_copy + .file_name() + .expect("path_to_copy should always end with a valid file or directory name"), + ); + std::fs::copy(path_to_copy, destination_path)?; + + Ok(()) +} + fn configure_wdf_build_output_dir(target_arg: &Option, cargo_make_cargo_profile: &str) { let cargo_make_crate_custom_triple_target_directory = std::env::var( CARGO_MAKE_CRATE_CUSTOM_TRIPLE_TARGET_DIRECTORY_ENV_VAR, diff --git a/rust-driver-makefile.toml b/rust-driver-makefile.toml index cf85bf87..c6e18c1f 100644 --- a/rust-driver-makefile.toml +++ b/rust-driver-makefile.toml @@ -82,41 +82,80 @@ wdk_build::cargo_make::validate_and_forward_args(); wdk_build::cargo_make::setup_path()?; ''' -[tasks.help] -workspace = false -env = { "TRIGGER_HELP" = "1" } -run_task = "wdk-build-init" - [tasks.copy-inx-to-output] +private = true script_runner = "@rust" +script_runner_args = [ + "--base-path", + "${CARGO_MAKE_CURRENT_TASK_INITIAL_MAKEFILE_DIRECTORY}", +] script = ''' -use std::path::PathBuf; - -let crate_name = std::env::var("CARGO_MAKE_CRATE_FS_NAME").expect("CARGO_MAKE_CRATE_FS_NAME should be set by cargo-make"); -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 output_directory = std::env::var("WDK_BUILD_OUTPUT_DIRECTORY").expect("WDK_BUILD_OUTPUT_DIRECTORY should be set by cargo-make via the env section of rust-driver-makefile.toml"); +//! ```cargo +//! [dependencies] +//! wdk-build = { path = "./crates/wdk-build", version = "0.1.0" } +//! ``` +#![allow(unused_doc_comments)] -let output_folder_path = PathBuf::from(&output_directory); +// 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 source_file = format!("{cargo_make_working_directory}/{crate_name}.inx"); -let destination_file = format!("{output_directory}/{crate_name}.inf"); -std::fs::copy(&source_file, &destination_file).expect(&format!("copy of '{source_file}' file to '{destination_file}' file should succeed")); +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::(); + +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-sys-file] private = true dependencies = ["build"] script_runner = "@rust" +script_runner_args = [ + "--base-path", + "${CARGO_MAKE_CURRENT_TASK_INITIAL_MAKEFILE_DIRECTORY}", +] script = ''' -let crate_name = std::env::var("CARGO_MAKE_CRATE_FS_NAME").expect("CARGO_MAKE_CRATE_FS_NAME should be set by cargo-make"); -let output_directory = std::env::var("WDK_BUILD_OUTPUT_DIRECTORY").expect("WDK_BUILD_OUTPUT_DIRECTORY should be set by cargo-make via the env section of rust-driver-makefile.toml"); +//! ```cargo +//! [dependencies] +//! wdk-build = { path = "./crates/wdk-build", version = "0.1.0" } +//! ``` +#![allow(unused_doc_comments)] -let source_file = format!("{output_directory}/{crate_name}.dll"); -let destination_file = format!("{output_directory}/{crate_name}.sys"); -std::fs::copy(&source_file, &destination_file).expect(&format!("copy of '{source_file}' file to '{destination_file}' file should succeed")); +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] @@ -150,82 +189,95 @@ args = [ ] [tasks.copy-sys-to-package] +private = true dependencies = ["generate-sys-file"] script_runner = "@rust" +script_runner_args = [ + "--base-path", + "${CARGO_MAKE_CURRENT_TASK_INITIAL_MAKEFILE_DIRECTORY}", +] script = ''' -use std::path::PathBuf; - -let crate_name = std::env::var("CARGO_MAKE_CRATE_FS_NAME").expect("CARGO_MAKE_CRATE_FS_NAME should be set by cargo-make"); -let output_directory = std::env::var("WDK_BUILD_OUTPUT_DIRECTORY").expect("WDK_BUILD_OUTPUT_DIRECTORY should be set by cargo-make via the env section of rust-driver-makefile.toml"); - -let package_folder_path = [output_directory.as_str(), "package"].iter().collect::(); -if !package_folder_path.exists() { - std::fs::create_dir(&package_folder_path).expect(&format!("creation of '{}' folder should succeed", package_folder_path.display())); -} +//! ```cargo +//! [dependencies] +//! wdk-build = { path = "./crates/wdk-build", version = "0.1.0" } +//! ``` +#![allow(unused_doc_comments)] -let source_file = format!("{output_directory}/{crate_name}.sys"); -let destination_file = format!("{output_directory}/package/{crate_name}.sys"); -std::fs::copy(&source_file, &destination_file).expect(&format!("copy of '{source_file}' file to '{destination_file}' file should succeed")); +wdk_build::cargo_make::copy_to_driver_package_folder( + wdk_build::cargo_make::get_wdk_build_output_directory().join(format!( + "{}.sys", + 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 = ''' -use std::path::PathBuf; - -let crate_name = std::env::var("CARGO_MAKE_CRATE_FS_NAME").expect("CARGO_MAKE_CRATE_FS_NAME should be set by cargo-make"); -let output_directory = std::env::var("WDK_BUILD_OUTPUT_DIRECTORY").expect("WDK_BUILD_OUTPUT_DIRECTORY should be set by cargo-make via the env section of rust-driver-makefile.toml"); - -let package_folder_path = [output_directory.as_str(), "package"].iter().collect::(); -if !package_folder_path.exists() { - std::fs::create_dir(&package_folder_path).expect(&format!("creation of '{}' folder should succeed", package_folder_path.display())); -} +//! ```cargo +//! [dependencies] +//! wdk-build = { path = "./crates/wdk-build", version = "0.1.0" } +//! ``` +#![allow(unused_doc_comments)] -let source_file = format!("{output_directory}/{crate_name}.pdb"); -let destination_file = format!("{output_directory}/package/{crate_name}.pdb"); -std::fs::copy(&source_file, &destination_file).expect(&format!("copy of '{source_file}' file to '{destination_file}' file should succeed")); +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 = ''' -use std::path::PathBuf; - -let crate_name = std::env::var("CARGO_MAKE_CRATE_FS_NAME").expect("CARGO_MAKE_CRATE_FS_NAME should be set by cargo-make"); -let output_directory = std::env::var("WDK_BUILD_OUTPUT_DIRECTORY").expect("WDK_BUILD_OUTPUT_DIRECTORY should be set by cargo-make via the env section of rust-driver-makefile.toml"); - -let package_folder_path = [output_directory.as_str(), "package"].iter().collect::(); -if !package_folder_path.exists() { - std::fs::create_dir(&package_folder_path).expect(&format!("creation of '{}' folder should succeed", package_folder_path.display())); -} +//! ```cargo +//! [dependencies] +//! wdk-build = { path = "./crates/wdk-build", version = "0.1.0" } +//! ``` +#![allow(unused_doc_comments)] -let source_file = format!("{output_directory}/{crate_name}.inf"); -let destination_file = format!("{output_directory}/package/{crate_name}.inf"); -std::fs::copy(&source_file, &destination_file).expect(&format!("copy of '{source_file}' file to '{destination_file}' file should succeed")); +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 = ''' -use std::path::PathBuf; - -let crate_name = std::env::var("CARGO_MAKE_CRATE_FS_NAME").expect("CARGO_MAKE_CRATE_FS_NAME should be set by cargo-make"); -let output_directory = std::env::var("WDK_BUILD_OUTPUT_DIRECTORY").expect("WDK_BUILD_OUTPUT_DIRECTORY should be set by cargo-make via the env section of rust-driver-makefile.toml"); - -let package_folder_path = [output_directory.as_str(), "package"].iter().collect::(); -if !package_folder_path.exists() { - std::fs::create_dir(&package_folder_path).expect(&format!("creation of '{}' folder should succeed", package_folder_path.display())); -} +//! ```cargo +//! [dependencies] +//! wdk-build = { path = "./crates/wdk-build", version = "0.1.0" } +//! ``` +#![allow(unused_doc_comments)] -let source_file = format!("{output_directory}/deps/{crate_name}.map"); -let destination_file = format!("{output_directory}/package/{crate_name}.map"); -std::fs::copy(&source_file, &destination_file).expect(&format!("copy of '{source_file}' file to '{destination_file}' file should succeed")); +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] @@ -233,8 +285,8 @@ private = true dependencies = ["copy-sys-to-package", "copy-inf-to-package"] command = "inf2cat" args = [ - "/driver:${WDK_BUILD_OUTPUT_DIRECTORY}/package", - "/os:10_NI_X64,10_VB_X64", # TODO: this should be a parameter + "/driver:${WDK_BUILD_OUTPUT_DIRECTORY}/${CARGO_MAKE_CRATE_FS_NAME}_package", + "/os:10_NI_X64,10_VB_X64", # TODO: this should be a parameter "/uselocaltime", ] @@ -271,19 +323,20 @@ args = [ private = true dependencies = ["generate-certificate"] script_runner = "@rust" +script_runner_args = [ + "--base-path", + "${CARGO_MAKE_CURRENT_TASK_INITIAL_MAKEFILE_DIRECTORY}", +] script = ''' -use std::path::PathBuf; - -let output_directory = std::env::var("WDK_BUILD_OUTPUT_DIRECTORY").expect("WDK_BUILD_OUTPUT_DIRECTORY should be set by cargo-make via the env section of rust-driver-makefile.toml"); - -let package_folder_path = [output_directory.as_str(), "package"].iter().collect::(); -if !package_folder_path.exists() { - std::fs::create_dir(&package_folder_path).expect(&format!("creation of '{}' folder should succeed", package_folder_path.display())); -} +//! ```cargo +//! [dependencies] +//! wdk-build = { path = "./crates/wdk-build", version = "0.1.0" } +//! ``` +#![allow(unused_doc_comments)] -let source_file = format!("{output_directory}/WDRLocalTestCert.cer"); -let destination_file = format!("{output_directory}/package/WDRLocalTestCert.cer"); -std::fs::copy(&source_file, &destination_file).expect(&format!("copy of '{source_file}' file to '{destination_file}' file should succeed")); +wdk_build::cargo_make::copy_to_driver_package_folder( + wdk_build::cargo_make::get_wdk_build_output_directory().join("WDRLocalTestCert.cer"), +); ''' [tasks.signtool] @@ -294,14 +347,14 @@ args = [ "sign", "/v", "/s", - "WDRTestCertStore", # TODO: this should be a parameter + "WDRTestCertStore", # TODO: this should be a parameter "/n", - "WDRLocalTestCert", # TODO: this should be a parameter + "WDRLocalTestCert", # TODO: this should be a parameter "/t", "http://timestamp.digicert.com", "/fd", "SHA256", - "${WDK_BUILD_OUTPUT_DIRECTORY}/package/${CARGO_MAKE_CRATE_FS_NAME}.cat", + "${WDK_BUILD_OUTPUT_DIRECTORY}/${CARGO_MAKE_CRATE_FS_NAME}_package/${CARGO_MAKE_CRATE_FS_NAME}.cat", ] [tasks.package-driver] @@ -358,5 +411,10 @@ end ''' run_task = "package-driver" +[tasks.help] +workspace = false +env = { "TRIGGER_HELP" = "1" } +run_task = "wdk-build-init" + [tasks.default] alias = "package-driver-flow"