Thanks for writing up a detailed ticket @ryankurte. I've done quite a lot of work with FFI and by far the most annoying step in making a *-sys
crate is getting the thing to build reliably.
I follow a process quite similar to @kornelski's Making a *-sys crate article and it works fairly well.
Pre-built bindgen
outputs often do not match target architecture sizes
Possible Mitigations
- tooling should build bindgen at compile time, with appropriate target arguments
- guide should specify that bindgen should be run at compile time
I can understand the appeal in running bindgen
at compile time, but I'd prefer to avoid it if possible. Adding a direct dependency on bindgen
means anyone wanting to use your crate will need to either have libclang
on their system, and given how *-sys
crates tend to be very deep in the dependency graph it means it'll affect a lot of crates.
As an alternate proposal, what if you could tell bindgen
to emit bindings for a selection of targets use conditional compilation to enable/disable items? It'd mean bindings files get significantly longer, but consumers now no longer need libclang
and the associated hassles when building or additional compile time.
Package discovery, compilation (and linking) typically doesn't work cross platform
This is a big one, but it's a bit too interrelated to easily split.
Package discovery is another can of worms entirely. The problem is that the various platforms each have their own way of installing something or reusing libraries.
For example, in Windows you'll often bundle the libraries you need with your program because there's no central, consistent place to store DLLs. *nix platforms use a package manager which will typically store system libraries in some sort of /lib
directory, setting things up so version conflicts are avoided.
About the only way you're going to get a consistent experience is if you compile from source during the build process, because then you've got access to any dynamic or static libraries you need.
Also, keep in mind there's only so much you can do from the Rust side. Unfortunately, C/C++ build systems are a massive mess and were designed before things like cross-platform and package managers became ubiquitous, so you've got an uphill battle ahead of you... cmake
and git submodules make things considerably easier, but even then it's nowhere near as seamless as cargo
or npm
.