Skip to content

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

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

feat: add PE resource version + metadata generation#661
Alan632 wants to merge 27 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 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-commenter commented May 23, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.09665% with 70 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.32%. Comparing base (a96fd81) to head (9c01467).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
crates/wdk-build/src/resource_compile.rs 92.74% 47 Missing and 20 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   79.93%   82.32%   +2.38%     
==========================================
  Files          26       27       +1     
  Lines        5633     6716    +1083     
  Branches     5633     6716    +1083     
==========================================
+ Hits         4503     5529    +1026     
- Misses       1002     1037      +35     
- Partials      128      150      +22     

☔ 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

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 1 comment.

Comment thread crates/wdk-build/src/resource_compile.rs
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 June 23, 2026 00:45

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 2 comments.

Comment thread crates/wdk-build/src/resource_compile.rs Outdated
Comment thread crates/wdk-build/src/resource_compile.rs Outdated
// Invoke rc.exe (expected to be on PATH via eWDK prompt or cargo-wdk setup)
let include_paths = resource_include_paths(config)?;

let mut cmd = Command::new("rc.exe");

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.

Was it an intentional choice not to use pre-existing crates for RC file generation and compilation, such as winresource, winres, or embed_resource, or were there other reasons?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It wasn't an intentional choice not to use an existing crate, just something carried over after looking at someone else's previous work (#243).

From my quick look it looks like winresource supersedes winres (winres doesn't support Rust >= v1.61). I think the benefit winresource brings is it handles the .rc file content generation automatically but we would still need the toolchain/resource path creation for it. And, embed_resource requires both (it needs a pre-generated .rc file). I'll take a further look into these crates but initially I'm thinking the extra complexity with integrating them doesn't gain us that much compared with the extra dependencies we'd pull in?

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.

just chiming in here. When I assigned this to Alan, I did intentionally tell Alan that the existing crates I surveyed previously either had long-standing bugs that affected their reliability, were unmaintained, or otherwise did not satisfy our requirements. Our goal here is to piggy-back off our existing metadata configuration system to avoid needing to manually an rc file that duplicates information we've provided elsewhere.

Alan Ngo added 2 commits June 23, 2026 17:10
- add a handler to deal with multiple authors cleanly
- move env_var_non_empty to utils.rs
- fix a cyclic error types with ResourceCompileError
Copilot AI review requested due to automatic review settings June 29, 2026 17:53

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 +1399 to +1402
fn create_include_subdirectories(include_directory: &Path, subdirectories: &[&str]) {
for subdirectory in subdirectories {
fs::create_dir_all(include_directory.join(subdirectory)).unwrap();
}
Comment thread .typos.toml
[files]
extend-exclude = ["**/Cargo.lock", "**/target/**"]

# Allowlist short words that collide with the typos dictionary but are

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.

nit: scope this down as much as possible since this could be a common typo. Something like this could work:

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Scoped down the rule further.

// Invoke rc.exe (expected to be on PATH via eWDK prompt or cargo-wdk setup)
let include_paths = resource_include_paths(config)?;

let mut cmd = Command::new("rc.exe");

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.

just chiming in here. When I assigned this to Alan, I did intentionally tell Alan that the existing crates I surveyed previously either had long-standing bugs that affected their reliability, were unmaintained, or otherwise did not satisfy our requirements. Our goal here is to piggy-back off our existing metadata configuration system to avoid needing to manually an rc file that duplicates information we've provided elsewhere.

/// `CARGO_PKG_VERSION` env var (emitted by cargo)
/// if env var is not present or empty.
fn resolve_version() -> Result<DriverVersion, ResourceCompileError> {
let version_str = env_var_non_empty(VERSION_ENV_VAR).map_or_else(

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.

VERSION_ENV_VAR corresponds with STAMPINF_VERSION that was previously added in order to get around cargo-wdk currently not having a flexible customization system. That system is being developed right now. I think perhaps we should avoid tying more functionality to that temporary workaround.

for (macro_name, macro_value) in [
("VER_FILEDESCRIPTION_STR", format!("\"{file_description}\"")),
("VER_PRODUCTNAME_STR", format!("\"{product_name}\"")),
("VER_FILEVERSION", version.as_rc_numeric()),

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 about PRODUCTVERSION? do both get set by default in a C driver?

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
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