Closed dansgithubuser closed 4 years ago
bindgen generate the lv2-sys crate. This generate the rust equivalent of the standard LV2 C API. In general, these equivalences are only valid for one particular platform, that why bindgen is run as least one time for each new project.
Oh -- how often does the LV2 C API change? Would it make sense to keep the generation step as a script in the repo, but outside the build? Like a deploy step for example, run every time the crate is published to crates.io, but devs who depend on the crate don't need clang.
Yes, bindgen
is necessary, unfortunately: The problem is that the C headers have different meanings on different the platforms. For example, while u32
in Rust is always an unsigned, 32-bit wide integer, an int
in C may be 16- to 64-bit wide, signed or unsigned; The standard doesn't pin one meaning. Also, alignments of structs are different for different architectures: Some may require fields to be aligned to 64-bit, but some only to 32-bit.
While C is rather exact in it's meaning, Rust is even more exact. The bindings that were generated and are compatible to hosts on a x86-64 Windows may be completely different and incompatible to those generated for a Raspberry Pi.
We shouldn't limit ourselves to only a handful of platforms, since LV2 doesn't too, but even manually generating bindings for stable, beta and nightly Rust on tier 1 platforms would lead to 21(!) completely different versions of the same crate. If we want to add tier 2 support, we would end up with 216(!!!) versions!
Therefore, @prokopyl and I have decided to generate the bindings using bindgen
at build time, which is also what bindgen
recommends. I know, it's a drag that you have to have clang installed and it takes a lot of time to build, but there aren't any better options, I'm afraid.
@Janonard , technically, is it possible to pre-generate lv2-sys for the most popular platform and only use bindgen on other platform? I think it's possible but i don't know if it easily maintainable.
It's possible, sure. There is also a CLI version of bindgen that can generate bindings. In theory, you could create a separate project with a build system that runs bindgen
on all headers for all targets and who's output is a Rust crate that can be published. However, there are also some things that need to be implemented manually too.
If someone comes up with an alternative way of binding generation that
bindgen
as a build dependency is the way to go.EDIT: Made point 5 clearer.
@Janonard This is insightful!
Looking through LV2 headers, I find they are pretty careful about using types with consistent sizes. I notice there is one use of #ifdef _WIN32
in lv2.h. Does the problem boil down to that? Am I missing some usage of variable-acrosss-platform-sized types?
Points 1-4 are clear and fair requirements, I'm unclear about 5. Are you saying "new build must be quicker than old build" or "new build + new deploy must be quicker than old build"?
Does the problem boil down to that? Am I missing some usage of variable-acrosss-platform-sized types?
There are other problems too: For example, C enums are represented as i32
on Windows, but as u32
on Linux and MacOS. Struct layouts are also different on completely different platforms: In the early days of lv2rs (one of the precursor projects), I've used bindings that we're pre-generated on an x86_64 Linux. However, all alignment and size checks that are generated by bindgen failed on my Raspberry Pi (ARMv6 Linux). C definitions simply have a different meaning on different platforms and we have to cope with that.
Points 1-4 are clear and fair requirements, I'm unclear about 5. Are you saying "new build must be quicker than old build" or "new build + new deploy must be quicker than old build"?
If the new rust-lv2
requires a new deployment, it must be separate to the rust-lv2
project, since the lv2-sys
crate would need to be deployed first. This deployment, however, may take as long as it requires, my specifications only include the time it takes to build the deployed crate.
The whole problem is that using bindgen
, building a simple plugin library takes a long time. This problem has to be solved by the new solution. I will update the requirements.
I'm unclear the value of the bindgen step -- looks like it generates a file that can be consumed by a rust host? Is it acceptable to add a way to opt out of this?
To my mind, the point of lv2 is to break down language barriers -- it's a standard interface that any language can adhere to, as a plugin or host. Compulsory bindgen seems like prescription of a Rust host.
All the best, Dan