rust: generate bindings via cbindgen
When compiling Git with Rust enabled we replace our C implementation of the varint encoding with a Rust implementation. A prerequisite for doing so is of course that the interfaces for both implementations are exactly the same. If they aren't, then we risk subtle runtime errors.
We don't really have a way to detect such interface mismatches though: the code will happily compile if we change either of the implementations without adjusting the other implementation in the same spirit. The risk of divergence is low right now as we only replace a single subsystem. But it is expected that we'll grow more reimplementations over time, so it is bound to increase.
A related issue is that we don't have an easy way to implement features exclusively in Rust and make them available to our C library. Again, we don't have such features yet, but there are work-in-progress patch series that will eventually add them.
Both of these issues can be addressed by generating C bindings via the
cbindgen(1) tool: given a Rust crate, it extracts all functions marked
with extern "C"
and creates a C declaration for them. These are then
written into a header file that we can include.
Set up this infrastructure in both our Makefile and in Meson. To demonstrate its use, the generated "c-bindings.h" header is included in "varint.h". If we now adapt "varint.rs" to have a different function signature than the C code we'll now get a compiler error:
In file included from ../read-cache.c:39:
../varint.h:6:9: error: conflicting types for 'encode_varint'
6 | uint8_t encode_varint(uint64_t, unsigned char *);
| ^
./c-bindings-generated.h:18:9: note: previous declaration is here
18 | uint8_t encode_varint(uint32_t value, uint8_t *buf);
Note that the headers are split into two:
-
"c-bindings-generated.h" is the header generated by cbindgen(1). This header should never be excluded directly, as it may be missing in non-Rust builds.
-
"c-bindings.h" is the header that should be included by code. The header uses an
#ifdef WITH_RUST
include guard so that it can be included even when building without Rust.
Signed-off-by: Patrick Steinhardt ps@pks.im