KEMBAR78
Improve `windows-bindgen` dependency targeting consistency and flexibility by kennykerr · Pull Request #3763 · microsoft/windows-rs · GitHub
Skip to content

Conversation

@kennykerr
Copy link
Collaborator

Today it can be a little hard to manage your dependencies when windows-bindgen introduces dependencies in generated code. Although --no-deps is useful for raw or sys-style bindings to limit or eliminate dependencies, it is not so easy to limit or eliminate dependencies for the default richer bindings generated by windows-bindgen and required for more convenient access to COM and WinRT APIs.

This update does two things:

  1. Improve consistency and convenience by default when windows-core is required to avoid a growing set of dependencies by using windows-core uniformly for most dependencies where feasible.

  2. Allow for more granular and specific dependency targeting and avoid the windows-core dependency unless required with the new --specific-deps option.

Let's say for example you generate bindings for the IsCharLowerA function

windows_bindgen::bindgen([
    "--out",
    "src/bindings.rs",
    "--filter",
    "IsCharLowerA",
    "--flat",
])
.unwrap();

Today the resulting bindings look something like this:

// before
#[inline]
pub unsafe fn IsCharLowerA(ch: i8) -> windows_core::Result<()> {
    windows_link::link!("user32.dll" "system" fn IsCharLowerA(ch : i8) -> windows_core::BOOL);
    unsafe { IsCharLowerA(ch).ok() }
}

Here you'll need to add dependencies for both the windows-core and windows-link crates.

Following this change, the generated bindings will use windows-core exclusively to avoid the need for the extra explicit dependency:

// after
#[inline]
pub unsafe fn IsCharLowerA(ch: i8) -> windows_core::Result<()> {
    windows_core::link!("user32.dll" "system" fn IsCharLowerA(ch : i8) -> windows_core::BOOL);
    unsafe { IsCharLowerA(ch).ok() }
}

As you can see, only the windows-core crate is assumed by the generated bindings. Note that this is merely a convenience to simplify dependency and version management. You will still get a dependency on the windows-link crate in both cases. You just don't need to manage this dependency yourself in the latter case.

On the other hand, you may want to avoid a dependency on the windows-core crate entirely because it is non-trivial and only really required for COM support. In such cases, you can opt in to manage your dependencies more directly with the new --specific-deps option that will instruct windows-bindgen to use the most specific crate dependencies where feasible.

Take for example the WindowsStringHasEmbeddedNull function. As before, this would previously require a dependency on both the windows-core and windows-link crates:

// before
#[inline]
pub unsafe fn WindowsStringHasEmbeddedNull(
    string: &windows_core::HSTRING,
) -> windows_core::Result<windows_core::BOOL> {
    windows_link::link!(<bla bla bla>);
    unsafe {
        let mut result__ = core::mem::zeroed();
        WindowsStringHasEmbeddedNull(core::mem::transmute_copy(string), &mut result__)
            .map(|| result__)
    }
}

Following this change, it will by default only require the windows-core crate:

// after (default)
#[inline]
pub unsafe fn WindowsStringHasEmbeddedNull(
    string: &windows_core::HSTRING,
) -> windows_core::Result<windows_core::BOOL> {
    windows_core::link!(<bla bla bla>);
    unsafe {
        let mut result__ = core::mem::zeroed();
        WindowsStringHasEmbeddedNull(core::mem::transmute_copy(string), &mut result__)
            .map(|| result__)
    }
}

To avoid a dependency on the windows-core crate entirely and instead target the specific - and much smaller - crates directly you only need to add the new --specific-deps option to produce the following:

// --specific-deps
#[inline]
pub unsafe fn WindowsStringHasEmbeddedNull(
    string: &windows_strings::HSTRING,
) -> windows_result::Result<windows_result::BOOL> {
    windows_link::link!(<bla bla bla>);
    unsafe {
        let mut result__ = core::mem::zeroed();
        WindowsStringHasEmbeddedNull(core::mem::transmute_copy(string), &mut result__)
            .map(|| result__)
    }
}

As you can see, the bindings now directly reference the windows-strings, windows-result, and windows-link crates. This option is not the default because this level of control is not for everyone but if that's you then enjoy!

@kennykerr kennykerr merged commit b3547dd into master Sep 19, 2025
28 checks passed
@kennykerr kennykerr deleted the specific-deps branch September 19, 2025 18:02
@MarijnS95
Copy link
Contributor

Thanks for the detailed outline! I haven't tried this out yet but will keep a list of crates to test this out on when the next update lands on crates.io. Two things:

  1. This PR doesn't update the argument table nor examples in the module-doc of crates/libs/bindgen/src/lib.rs, making your elaborate description get lost and this argument harder to find;
  2. I've only briefly mentioned it in Add most common windows-bindgen options to readme #3514 (comment), but have you considered a similar case or argument for when windows is already required (for references), but some of the generated bindings still require windows_core despite possibly being able to reference that via windows::core::?

MarijnS95 added a commit to MarijnS95/generator-rs that referenced this pull request Sep 26, 2025
…indows-result`

https://github.com/Microsoft/windows-rs/releases/70

As highlighted in Xudong-Huang#76 we couldn't use the non-`sys` bindings without
pulling in `windows-core` with all its COM support (that this
crate doesn't need) and significant version-churn cadence like the
`windows` crate itself.  Fortunately since then `windows-bindgen`
was updated with a new `--specific-deps` configuration option
in microsoft/windows-rs#3763 that allows
it to prefer using the "special crates" like `windows-link` and
`windows-result` over their relative reexports from `windows-core`.
Xudong-Huang pushed a commit to Xudong-Huang/generator-rs that referenced this pull request Sep 29, 2025
…indows-result`

https://github.com/Microsoft/windows-rs/releases/70

As highlighted in #76 we couldn't use the non-`sys` bindings without
pulling in `windows-core` with all its COM support (that this
crate doesn't need) and significant version-churn cadence like the
`windows` crate itself.  Fortunately since then `windows-bindgen`
was updated with a new `--specific-deps` configuration option
in microsoft/windows-rs#3763 that allows
it to prefer using the "special crates" like `windows-link` and
`windows-result` over their relative reexports from `windows-core`.
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.

2 participants