Skip to content

Combating version churn #1720

@Jake-Shadle

Description

@Jake-Shadle

First of all I just want to thank the maintainers/Microsoft for making these crates, having a set of maintained bindings that can supplant winapi and be confident will be maintained in the future has been really great.

Problem

That being said, I think the current velocity of version changes in this repo is a bit problematic for the ecosystem, especially as more crates adopt windows or windows-sys over winapi. This is because, for the past several months, the crates in this repo have have had their minor version bumped on average every couple of weeks, essentially guaranteeing that with enough transitive dependencies on one of the crates in this repo, a project's crate graph will include multiple versions of one or more windows crates. Duplicate versions can be fine for short periods of time as various crates catch up to newer releases, however the velocity of this repo is far greater than many crates in the ecosystem, especially in the windows-sys crate case of being low level system bindings.

For a simple example, let's take parking_lot.

  • parking_lot currently depends on windows-sys:0.34, which is around 1.5 months old
  • Someone helpfully added a PR to bump to windows-sys:0.35 (22 days old) about a week ago
  • windows-sys was bumped to 0.36 a few hours ago

parking_lot is now in a conundrum. It could accept the 0.35 PR, and cut a release, but there's already a newer version, so they could bump directly to 0.36 instead, skipping 0.35 entirely. However, depending on what other crates you have in your graph, either decision is (or the none option of just staying on 0.34) almost guaranteed to result in multiple versions of windows-sys as

  • Some crates will have transitioned to 0.35 sometime since it was released, but might take several days/weeks/months to move to 0.36
  • Some crates will be on 0.34 (or even older) versions like parking_lot
  • Some crates might move to 0.36 quite quickly, which could mean you're depending on up to 3! different versions of windows-sys simultaneously

The real kicker is that parking_lot uses a grand total of 3 function bindings and a few type/constant bindings which, beyond fundamental changes such as #1439, are...."never" going to change, thanks to Windows' backwards compatibility guarantees.

If we take a step back I see there being multiple reasons for this version churn

  • All (or at least all the "user facing" ones) of crates in this repo share a single version. On the one hand this is nice since versioning is internally consistent and makes perusing version history more easy etc. However, it's also a very big hammer, particularly in the case of windows-sys, as it means that any change in any crate in this repo, regardless of the downstream usage, results in a new version.
  • The Windows API surface is positively massive, and due to how the windows/-sys crates are organized via feature flags, any breaking change to one sub-API is technically a breaking change to the crate as a whole. This is despite the fact that an overwhelming majority of downstream users will use an incredibly small fraction of that massive API surface, meaning (again, other than fundamental changes such as Don't specialize HANDLE #1439) that they're very unlikely to actually observe such a breaking change in practice.
  • Reiterating from above, the release cadence of this repo is just much higher than most other crates in the ecosystem, but because the bindings in windows/-sys are essentially the libc of Windows, many crates depend (or will, once they transition from eg. winapi) on them which coupled together mean multiple versions of one or more crates in this repo become almost inevitable

Possible Solutions

Below are several options that I can see that could solve, or at least alleviate, this problem. Obviously it's up to the maintainers on what they think is best (or if it will be considered a problem at all), so these are just some thoughts.

  • Stabilize and use patches. The crates in this repo are still early days so I doubt this could happen anytime soon, but having a model similar to libc, where they've been on a 0.2 minor version for years and only ever bump the patch version, means semver compatibility across the ecosystem. libc obviously has a bit of a simpler problem since the API surface is orders of magnitude smaller than Windows, but it is a proven model.
  • windows-sys in particular (maybe not windows?) could be more lenient about breaking semver. What I mean be this is, in an overwhelming majority of use cases, a crate using windows-sys will use an incredibly small fraction of the API surface exposed by it. This means that (again, beyond fundamental changes like Don't specialize HANDLE #1439) that a breaking change in windows-sys, such as a moving constants or functions to a different location, are not going to be observed by the downstream crate at all unless they were using those exact functions/constants. Speaking for myself, this kind of breakage would be entirely acceptable if it was clearly stated in the release notes, or even just as a general caveat clearly stated in the README as it is trivial to find where a function/constant was moved to in a newer version and change it to the new location/feature flag. This is unfortunately not a super viable method for transitive dependencies however, I just thought I would mention it.
  • Make windows-bindgen a first class citizen (related windows-bindgen needs documentation #1407). At least in my use cases, and I believe many others, using Windows bindings is a fairly "write once" operation that generally doesn't change much past the initial implementation. For this kind of use case, having a convenient way to do "generate functions x, y, and z, and these constants to this output file" would be frankly amazing. For example, here's a recent PR I made to add minidump writing. In grand total, this uses 5 functions, ~6 constants, and ~6 types. These will most likely never change again, and by generating only the bindings I need, once, and just including them as a single source file directly in the project, I could get rid of the windows-sys dependency altogether, avoiding the problem of multiple versions now and in the future. If we go back to the parking_lot case above, it's already manually creating its own bindings to Nt* functions that are not part of Win32 metadata, and could do the same for the few functions/constants that it is using from windows-sys, but having that functionality exposed in a friendly way by a windows-bindgen tool would mean generating the bindings once and never having to worry about version churn in the future, because again, these functions/constants/types are not going to change

Closing

I'm sure the maintainers have probably thought about this issue already, but I'm opening this issue because I couldn't find anything relevant that was already open and want to foster a discussion in the open about this, since I'm sure we're not the only ones that find the current situation problematic.

Sorry this was a bit of a braindump I've just been thinking about this the last few days and wanted to finally just write it down.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions