Conversation
|
@riverar @ChrisDenton @wravery - would love your feedback. A few notes on housekeeping and changes. The undocumented and largely internal The MSRV for most crates has now moved to 1.74 to avoid some compiler bugs in previous versions. 94e1288 The The lib generator now detects import functions that aren't available on x86. e5c2492 The "bindgen" tool/test crates now provide a much simpler way to test code generation. The older "standalone" tool/test still exists but will be phased out. e9772d6 |
Hmm, am concerned about this being the default behavior. It isn't easy to discover what's needed for a complete interface projection. (I haven't run the new bindgen yet, perhaps there's already a warning that is output?) |
@riverar if its any consolation this never worked before - it would blindly add all methods and then produce invalid code gen unless you manually chase down all the dependencies. We can add such an option but my attempts showed that it would be too expensive to do by default e.g. any method that mentions Xaml in any way can easily add a million lines of code... 😉 As it stands, its pretty easy to see what methods are omitted since the vtable slots are named and padded so you can tell the "Status" method is missing. |
|
I've been trying it out and so far it works great, though I've not yet tried all the new features. Only minor issue is that the output sort order appears to have changed. E.g. here's the diff when updating the standard library to the new bindgen: rust-lang/rust@1d83a16. That said, it's not a big deal if it's a one time thing with this update. Also, if |
|
Yes, I've been fiddling with the sort order. Its a little awkward as its primarily based on the Yes, falling back to |
|
@ChrisDenton you should now find that it is closer to what you had before in terms of sort order. The functions are no longer sorted by library so that might be noticeable but expected. If you have types with different |
|
OK, I've addressed the Check out the "reference" and "reference_client" test crates. I'll do some more testing and probably write a few more samples but let me know if you have any more issues in the mean time. |
|
@kennykerr small question: We used to have a Now that we updated to Can we enable root stripping? You seem to have added that option for |
|
I decided against adding such an option because you can easily use Rust itself to achieve this. |
|
@kennykerr right, I thought you might have used something similar to generate the EDIT: That requires Having a simple |
|
Yes, I don't think you need to use |
|
Yeah it's now done with |
This update introduces the next major update to the
windows-bindgencrate, having been overhauled to provide first-class support for custom code generation. Historically, thewindows-bindgencrate was written to generate thewindowscrate and then thewindows-syscrate. This was then further extended to support other scenarios, primarily standalone code generation. This was somewhat awkward as thewindows-bindgencrate could not easily handle this and thus required some gymnastics to pull it off. This has made it difficult to fix various issues and support new scenarios.Well this update aims to address these issues with a rewrite of the crate with an emphasis on general-purpose code generation that supports standalone code generation just as well or better than the generation of the
windowsandwindows-syscrates. Indeed, the generation of these crates is really just a special application of the general-purpose code generator. Let's walk through a few examples to illustrate what this looks like. Consider the following build script:This represents the general usage of the
bindgenfunction. You'll notice that it no longer returns aResultand will simply panic with a clear message describing any issues with the arguments or environment. This highlights the fact that this is meant to be used as a build tool and so a build error makes the most sense.The
bindgenfunction supports various options but three are required.--incan indicate a .winmd file or directory containing .winmd files. Alternatively, the special "default" input can be used to use the particular .winmd files that ship with thewindows-bindgencrate. Previously this "default" metadata was included using a crate feature, but this new approach should be far less error-prone and predictable. If no input is provided then the "default" input is assumed.--outindicates where thebindgenfunction will write the bindings. This is typically a source file likesrc/bindings.rsbut can also point to a directory when generating a crate likewindowsorwindows-sys.--filterindicates what bindings to include or exclude as it's unusual to generate bindings for everything described by the input .winmd files.The next thing you'll notice, at least if you've used previous versions of the
windows-bindgencrate, is that theCoCreateGuidfunction or filter simply includes the function name and nothing more. In previous versions you had to spell it out in order for thebindgenfunction to find the metadata.This continues to work but is often meaningless to many projects that don't care about the namespace hierarchy used by the .winmd files. This saves developers from having to figure out what these paths might be. If you happen to know the name of the function or type that you need then you can usually just type it in and see if the bindings can be generated correctly. Either way, the bindings will be generated the same way. There are however cases where a name might be ambiguous and then you may have to spell things out to resolve the ambiguity.
Here's what it might look like for the example above:
As you can see, the bindings still default to using the namespace-to-module mapping but it's easy to turn that off as well simply by using the
--flatoption:Previously, this flat output required both of the wordier
"--config", "flatten"arguments and didn't work too well in more complex scenarios. And here's the resulting flat output:You can also control whether the bindings include the comment and allow attribute with the
--no-commentand--no-allowoptions.The other interesting option is
--syswhich instructs thebindgenfunction to generate raw, commonly known as sys-style, Rust bindings. Previously, this output required both of the wordier"--config", "sys"arguments.Here's how the
CoCreateGuidfunction is generated in this case:You'll notice that the bindings are simpler as there's no wrapper function and "core" types like
GUIDandHRESULTare now provided by thewindows_sys::coremodule rather than the richerwindows_coremodule that is used by thewindowscrate. This illustrates another difference that was difficult to reconcile in the previous version of thewindows-bindgencrate. Previously, you could have references to thewindowscrate but not to thewindows-syscrate. This caused all kinds of problems for sys-style bindings of custom or private APIs. Of course, there may still be cases where a dependency on either thewindowsorwindows-syscrates are undesirable. For that you have two options. The first is to use the new--no-coreoption as follows:This instructs the
bindgenfunction to avoid dependencies for these "core" types and instead include them directly in the generated bindings. Here's what the resulting output looks like:As you can see, the
bindgenfunction detects that theCoCreateGuidfunction depends onGUIDandHRESULTand includes their definitions directly. At this point, the--no-coreoption requires the--sysoption. I may revisit this in future but the richer non-sys core type definitions are not very easy to inline.The other option, which applies equally well to sys and non-sys style bindings is to leverage the Rust language to inject your own definitions for such core types. Let's remove the
--no-coreoption as follows:The resulting bindings thus once again look like this:
The simplest thing to do here is to add a dependency for the
windows-targetscrate as well as thewindows-syscrate and then these bindings will compile just fine. Alternatively, you can provide a local definition ofwindows_systhat redirects to a local definition for these core types. You can do this in various ways but one simple approach is to create an alias forwindows_sysin yourlib.rsfile as follows:Here I've simply defined a mini
coremodule with the necessary type definitions and an alias forwindows_systhat points right back to the current crate. You can do something similar to avoid a dependency on thewindows_targetscrate if so desired.Previous versions of the
windows-bindgencrate were not able to track down dependencies reliably under specific conditions. In the mode that generated crates likewindowsandwindows-sysit was assumed that dependencies would be discovered at compile time in other modules depending on the inclusion of Cargo features. In the mode that generated standalone bindings it would generate dependencies but only if certain other options lined up just right. The new version of thewindows-bindgencrate should now reliably tracks down all dependencies in all cases and regardless of the kind of output it produces.Let's consider a struct example first and generate bindings for the
InkTrailPointstruct.I didn't include the
--flatoption so the output looks like this:You can observe that the
InkTrailPointstruct was defined in the "Windows.UI.Composition" namespace in the input .winmd file and that it has aPointfield whose type is defined in the "Windows.Foundation" namespace. Thebindgenfunctions is careful to generate both module hierarchies and thesuper::super::path to refer from the one to the other. All this happened despite the fact that thebindgenfilter only mentioned "InkTrailPoint". We can of course use the--flatoption to ignore the hierarchy:Now the output looks like this:
Dependencies get a lot more interesting when it comes to COM or WinRT style interfaces and classes and particularly class or interface hierarchies as those dependencies can quickly add up. Often however those dependencies can be unrelated or at least uninteresting to a given project and added burden of that cascade of dependencies can be undesirable. As such, the
bindgenfunction will only include interface methods whose signatures refer to types that are themselves included in the--filteroption.Consider the following example using the
IAsyncInfointerface:Now the
IAsyncInfointerface actually has five methods namelyId,Status,ErrorCode,Cancel, andClosebut the resulting output omits theStatusmethod. Here's a simplified version of the output for clarity:The methods that are included are those that don't depend on anything other than intrinsics or core types. Other methods are simply omitted. But what if you need the
Statusmethod? Simply include the types needed by that method in the--filteroption as follows:And just like that the extra
Statusmethod appears as its dependency onAsyncStatusis now available.In some cases you may not want to generate the dependencies directly but instead defer to some other crate (or module) to provide those definitions. That's where the new
--referenceoption comes in handy. Previously, thewindows-bindgencrate would only allow dependencies on thewindowscrate. Now this is completely controlled by the--referenceoption. Let's imagine thatAsyncStatusis super complicated and you'd rather get that dependency from thewindowscrate. This is a silly example but you can easily imagine how this can be applied to larger dependencies like Direct3D or third-party dependencies. Instead of simply includingAsyncStatusin the--filteroption, you can instead use the--referenceoption to indicate where and how to resolve the type. Here's an example:This is a rather powerful feature with a great deal of flexibility so it may seem a little confusing at first but its actually quite simple. Here we're saying that the
windowscrate should resolve any references to theAsyncStatustype using the "skip-root" path style. The reason for this should quickly become apparent. Here's what the output looks like now:As you can see, the
Statusmethod now refers toAsyncStatusas defined in theFoundationmodule within thewindowscrate. Theskip-rootpath style is in reference to the fact that both thewindowsandwindows-syscrates skip the root "Windows" namespace or module when generating their type hierarchies. Depending on how the target crate was generated you may also use the "full" or "flat" path styles instead. Obviously, you can use the--referenceoption to generate dependencies to crates of your own. Conversely, you can use the newwindows-bindgencrate to generate those crates!Naturally, you can use the
--referenceoption to generate references to entire namespaces and not just specific types. The following option will work just as well and also resolve references to any other types coming from the given "Windows.Foundation" namespace.Now let's look at a few more new options and features supported by the
windows-bindgencrate.The
--deriveoption allows you to indicate extra traits that you would like specific types to derive. Imagine you need theRectFandRectInt32structs so you generate them as follows:The resulting output look like this:
Now you'd like to have the
RectInt32struct implement theEqandPartialEqtraits while theRectFstruct should only implement thePartialEqtrait since it contains floating point fields and those can't be derived. Here's how you might do that with the new--deriveoption:And the resulting output looks like this:
The
--rustfmtoption allows you to override the default Rust formatting as follows:The formatting options can be found here: https://rust-lang.github.io/rustfmt
Well there's a lot more I could say about this update but I think I'll stop before this becomes too long to read. 😉