Skip to content

feat: add PE resource version + metadata generation - #661

Open
Alan632 wants to merge 31 commits into
microsoft:mainfrom
Alan632:driver_file_versioning
Open

feat: add PE resource version + metadata generation#661
Alan632 wants to merge 31 commits into
microsoft:mainfrom
Alan632:driver_file_versioning

Conversation

@Alan632

@Alan632 Alan632 commented May 22, 2026

Copy link
Copy Markdown
Contributor

Summary

Currently driver PE resource metadata and versioning do not get populated (the version in the *.inf does) and makes issue and post-mortem troubleshooting/tracing difficult.

This PR adds the functionality to populate the PE resource metadata automatically.

wdk-build/src/lib.rs

  • Adds a new variant to ConfigError
  • Extends configure_binary_build to initiate *.rc generation, compilation to *.res, and linker directive emission

wdk-build/src/resource_compile.rs

  • Entry point via compile_version_resource called from configure_binary_build
  • Grabs the driver version from the environment variable STAMPINF_VERSION, falling back to CARGO_PKG_VERSION set by Cargo
  • Pulls other PE Property values from Cargo.toml, defaulting to Cargo environment variables if missing
  • Generates an *.rc file and runs rc.exe to compile to a *.res and emits linker directives

wdk-build/src/metadata/mod.rs

  • Changes parsing functions for wdk metadata to allow other sections to coexist in the Cargo.toml (eg. new [package.metadata.wdk.version-resource]), keeps strict serde validation of Wdk/DriverConfig (eg. [package.metadata.wdk.driver-model])
  • Adds additional unit tests

Validation

Local testing with in production driver in the following scenarios: missing version-resource metadata, populated version-resource metadata, and STAMPINF_VERSION set.

Tested with sample drivers kmdf/wdm/umdf.

WDM sample driver with [package.metadata.wdk.version-resource] info filled in:

image

UMDF sample driver without [package.metadata.wdk.version-resource] info:

image

@Alan632 Alan632 self-assigned this May 22, 2026
Copilot AI lite review requested due to automatic review settings May 22, 2026 23:29

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds automatic generation and compilation of Windows PE VERSIONINFO resources for driver binaries built with wdk-build, so that file version and descriptive metadata are embedded directly into the produced .sys / .dll artifacts (not just the .inf).

Changes:

  • Introduces resource_compile module to generate a .rc, compile it via rc.exe to a .res, and emit linker args to embed it into the driver binary.
  • Extends ConfigError and Config::configure_binary_build to run the version-resource compilation step during build script configuration.
  • Updates WDK metadata parsing so [package.metadata.wdk.*] sections (e.g., version-resource) can coexist while still strictly validating the driver-model configuration, plus adds unit tests.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
crates/wdk-build/src/resource_compile.rs New module implementing version/metadata resolution, .rc generation, rc.exe invocation, and link-arg emission, with unit tests.
crates/wdk-build/src/metadata/mod.rs Narrows WDK configuration deserialization to metadata.wdk.driver-model while permitting other metadata.wdk.* sections; adds tests.
crates/wdk-build/src/lib.rs Exposes the new module, adds a ConfigError variant, and invokes resource compilation from configure_binary_build.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread crates/wdk-build/src/resource_compile.rs Outdated
Comment thread crates/wdk-build/src/resource_compile.rs
Comment thread crates/wdk-build/src/resource_compile.rs Dismissed
@codecov-commenter

Codecov Comments Bot (codecov-commenter) commented May 23, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.84995% with 71 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.25%. Comparing base (f11b762) to head (087679d).

Files with missing lines Patch % Lines
crates/wdk-build/src/resource_compile.rs 92.46% 47 Missing and 21 partials ⚠️
crates/wdk-build/src/metadata/mod.rs 96.59% 1 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #661      +/-   ##
==========================================
+ Coverage   80.47%   82.25%   +1.77%     
==========================================
  Files          26       27       +1     
  Lines        5720     6693     +973     
  Branches     5720     6693     +973     
==========================================
+ Hits         4603     5505     +902     
- Misses        989     1037      +48     
- Partials      128      151      +23     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

…tness for different dev environment setups
Copilot AI review requested due to automatic review settings May 27, 2026 18:47

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

Comment thread crates/wdk-build/src/resource_compile.rs
Comment thread crates/wdk-build/src/resource_compile.rs Outdated
Comment thread crates/wdk-build/src/resource_compile.rs Outdated
Comment thread crates/wdk-build/src/resource_compile.rs Outdated
@Alan632
Alan632 marked this pull request as ready for review May 27, 2026 20:13
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Alan632 <aln.noda7@gmail.com>
Copilot AI review requested due to automatic review settings May 27, 2026 20:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

Comment thread crates/wdk-build/src/resource_compile.rs Outdated
Comment thread crates/wdk-build/src/resource_compile.rs
Comment thread crates/wdk-build/src/lib.rs Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Alan632 <aln.noda7@gmail.com>
Copilot AI review requested due to automatic review settings May 27, 2026 21:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

Comment thread crates/wdk-build/src/lib.rs
Comment thread crates/wdk-build/src/resource_compile.rs
Comment thread crates/wdk-build/src/resource_compile.rs Outdated
Copilot AI review requested due to automatic review settings May 27, 2026 22:38

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

Comment thread crates/wdk-build/src/resource_compile.rs
Comment thread crates/wdk-build/src/resource_compile.rs
Comment thread crates/wdk-build/src/lib.rs
…ary rerun directive (CI builds are fresh), fix formatting in .typos.toml
DriverConfig::Umdf(_) => ("VFT_DLL", "VFT2_UNKNOWN"),
};

let mut rc = String::with_capacity(1024);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you're writing into a string anyways, I think this chunk would be a lot more readable and easier to grok the RC file contents if it did a template with string replacement similar to

static CALL_UNSAFE_WDF_BINDING_TEMPLATE: LazyLock<String> = LazyLock::new(|| {
.


let rc = generate_rc_content(version, &metadata, &config);

assert!(rc.contains("#pragma code_page(65001)"));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not necessarily required for this PR to merge, but I think some snapshot testing here would be better since the output is fairly complex. It would be worth looking into insta or snapbox

@@ -0,0 +1,1645 @@
// Copyright (c) Microsoft Corporation

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there should be an integration test asserting the version derived here matches the version in the inf. You can probably add that test coverage by piggybacking on some of the existing integration tests in cargo-wdk

fn resolve_version() -> Result<DriverVersion, ResourceCompileError> {
let version_str = env_var_non_empty(VERSION_ENV_VAR).map_or_else(
|| {
env::var("CARGO_PKG_VERSION").map_err(|_| ResourceCompileError::MetadataError {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is the current behavior here if there is not version defined (since cargo made version field optional)? Does it error out or does it default to 0.0.0?

Copilot AI review requested due to automatic review settings July 6, 2026 21:08

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Comment on lines +300 to +306
let metadata = cargo_metadata::MetadataCommand::new()
.manifest_path(&manifest_path)
.no_deps()
.exec()
.map_err(|e| ResourceCompileError::MetadataError {
detail: format!("cargo metadata failed: {e}"),
})?;
Copilot AI review requested due to automatic review settings July 20, 2026 16:39

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

crates/wdk-build/src/resource_compile.rs:303

  • cargo_metadata::MetadataCommand here is executed without setting current_dir. Elsewhere in wdk-build, metadata commands set current_dir to the manifest’s parent directory to ensure .cargo/config.toml overrides are honored. Without this, resource metadata extraction can differ from the rest of the build (e.g., custom registries/config), depending on the build script’s working directory.
    let manifest_path = Path::new(&manifest_dir).join("Cargo.toml");

    let metadata = cargo_metadata::MetadataCommand::new()
        .manifest_path(&manifest_path)
        .no_deps()
        .exec()

Comment on lines +423 to +428
/// Reads an environment variable, returning `None` for both unset and empty
/// values. eWDK/vcvars occasionally export variables with empty defaults that
/// should be treated as unset.
pub fn env_var_non_empty(key: &str) -> Option<String> {
env::var(key).ok().filter(|value| !value.is_empty())
}
Copilot AI review requested due to automatic review settings July 27, 2026 16:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

crates/wdk-build/src/resource_compile.rs:304

  • read_version_resource_metadata runs cargo_metadata without setting current_dir. Elsewhere in wdk-build you explicitly set current_dir to the manifest directory to ensure .cargo/config.toml overrides are respected (e.g., Config::from_env_auto in crates/wdk-build/src/lib.rs:446-453). Setting it here makes metadata resolution more robust when the build script’s working directory isn’t the manifest dir.
    let metadata = cargo_metadata::MetadataCommand::new()
        .manifest_path(&manifest_path)
        .no_deps()
        .exec()
        .map_err(|e| ResourceCompileError::MetadataError {

Comment thread .typos.toml
Comment on lines +6 to +10
[type.resource_compile]
extend-glob = ["resource_compile.rs"]

[type.resource_compile.extend-words]
fo = "fo" # rc.exe /fo (output file) switch
Copilot AI review requested due to automatic review settings August 7, 2026 19:05

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

Suppressed comments (1)

.typos.toml:10

  • typos file globs are matched against the file’s relative path (as evidenced by existing patterns like **/Cargo.lock). extend-glob = ["resource_compile.rs"] likely won’t match crates/wdk-build/src/resource_compile.rs, so the fo allowlist won’t take effect and the typos check can still fail.
[type.resource_compile]
extend-glob = ["resource_compile.rs"]

[type.resource_compile.extend-words]
fo = "fo" # rc.exe /fo (output file) switch

Copilot AI review requested due to automatic review settings August 11, 2026 17:55

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

Suppressed comments (1)

crates/wdk-build/src/resource_compile.rs:703

  • compile_version_resource_inner reads STAMPINF_VERSION (via resolve_version) but doesn’t emit a corresponding cargo:rerun-if-env-changed directive. Since Config::from_env_auto() already emits cargo:rerun-if-changed directives, Cargo will not rerun the build script when only STAMPINF_VERSION changes, leaving a stale embedded VERSIONINFO on incremental builds.
fn compile_version_resource_inner(config: &Config) -> Result<(), ResourceCompileError> {
    let version = resolve_version()?;
    let metadata = read_version_resource_metadata()?;

Alan Ngo added 2 commits August 11, 2026 11:30
…nv var set by `cargo` now, update documentation and unit tests to match
Copilot AI review requested due to automatic review settings August 11, 2026 18:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

Suppressed comments (5)

.typos.toml:7

  • extend-glob = ["resource_compile.rs"] likely won’t match crates/wdk-build/src/resource_compile.rs, so the allowlisted word fo may still trip typos in CI. Use a path/glob that matches the file under crates/.
extend-glob = ["resource_compile.rs"]

crates/wdk-build/src/resource_compile.rs:248

  • resolve_version() ignores STAMPINF_VERSION, but the PR description/validation claims the embedded PE version is sourced from STAMPINF_VERSION (with fallback to Cargo). As-is, setting STAMPINF_VERSION won’t affect the generated VERSIONINFO resource.
/// Determine the driver version to embed in the binary from the env var set by
/// `cargo`.
fn resolve_version() -> Result<DriverVersion, ResourceCompileError> {
    let version_str =
        env::var("CARGO_PKG_VERSION").map_err(|_| ResourceCompileError::MetadataError {
            detail: "CARGO_PKG_VERSION environment variable not set. This function must be called \
                     from a Cargo build script."
                .to_string(),
        })?;

    parse_version(&version_str)
}

crates/wdk-build/src/resource_compile.rs:943

  • If STAMPINF_VERSION is intended to drive the embedded VERSIONINFO, the unit tests should cover precedence and fallback (currently only CARGO_PKG_VERSION is exercised). This also helps prevent regressions where STAMPINF_VERSION is accidentally ignored.
        #[test]
        fn resolve_version_uses_cargo_pkg_version() {
            let version =
                with_env(&[("CARGO_PKG_VERSION", Some("1.2.3"))], resolve_version).unwrap();

            assert_eq!(
                version,
                DriverVersion {
                    major: 1,
                    minor: 2,
                    patch: 3,
                    revision: 0
                }
            );
        }

crates/wdk-build/src/resource_compile.rs:29

  • The module docs say the version always comes from CARGO_PKG_VERSION, but the PR description states STAMPINF_VERSION should take precedence (falling back to Cargo). Either update the docs or the implementation so they’re consistent.

This issue also appears in the following locations of the same file:

  • line 237
  • line 928
//! The version is read from `CARGO_PKG_VERSION`, which Cargo sets from the
//! package's `[package]` version.

crates/wdk-build/src/resource_compile.rs:1343

  • The create_include_subdirectories test helper treats entries like "km\\crt" as a single directory name on non-Windows platforms, which makes these tests OS-dependent (it won’t create km/crt, so resource_include_paths won’t find kernel include dirs). Split subdirectory strings on both \\ and / so the tests behave consistently across host OSes.
        fn create_include_subdirectories(include_directory: &Path, subdirectories: &[&str]) {
            for subdirectory in subdirectories {
                fs::create_dir_all(include_directory.join(subdirectory)).unwrap();
            }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants