FFI: Compile time configurability of a Rust library

Hi,

I have a hard time figuring how to solve this right now, and this also has to do a little bit to do with
how C/C++ libraries are configured at compile-time. There is also just not a lot of documentation available when it comes to the practice of FFI and real-world libraries..

So I have a C library, which uses a configure file to automatically pass some build system configuration into a header file, which is then included by the library to define the size of some structures.

Example C code:

	/**
	 * Data part of packet:
	 */
	union {
		uint8_t data[CSP_BUFFER_SIZE];
		uint16_t data16[CSP_BUFFER_SIZE / 2];
		uint32_t data32[CSP_BUFFER_SIZE / 4];
	};

and the CSP_BUFFER_SIZE comes from a config file:

#define CSP_BUFFER_SIZE 256

I auto-generate bindings to this library with bindgen, but bindgen just auto-replaces these constants with the actual numbers. This is a big problem. If someone uses theses structs with a compiled library where the configuration constant has another value.. things will probably go horribly wrong.

What I can do is that I create a constant in my library which I then use in the auto-generated union type:

const CSP_BUFFER_SIZE: usize = 256;

#[doc = " Data part of packet:"]
#[repr(C)]
#[derive(Copy, Clone)]
pub union csp_packet_s_data_union {
    pub data: [u8; CSP_BUFFER_SIZE],
    pub data16: [u16; CSP_BUFFER_SIZE / 2usize],
    pub data32: [u32; CSP_BUFFER_SIZE / 4usize],
}

now the last problem that remains is: How do I make this constant configurable? In a regular Rust library, I'd use something like a generic const or associated constant to deal with this, but I do not think I can do this here. I could provide some sort of template mechanism where the library constant get substituted based on a configuration also used to build the C library. But this is not really compatible with the regular library workflow, I now have to actually clone my library, perform some template substitutation, and only then is the library usable. Does anyone have a solution to solve this issue? Maybe I am also overlooking a really simple solution for this?

Thanks a lot in advance!

Kind Regards
Robin

Rust doesn't have such compile-time configurability.

  • You could try make it configurable from within the language via const generics: csp_packet_s_data_union<const CSP_BUFFER_SIZE: usize>.

  • You could use Cargo features for a selection of pre-defined values. Features are only booleans, so it'd be something like small-buffer or large-buffer. Cargo features must be additive, so the implementation would have to pick one if both are set.

  • You could use env vars and build.rs script to generate configuration at build time, and include a Rust file from OUT_DIR. However, Rust/Cargo doesn't have first-class tools to discover and manage such env vars.

Thanks for these suggestions, really useful.

I tried const generics.. I can not use them for the division for example, Rust doesn't seem to support this (yet?) and I'd prefer to limit the modification of the generated bindings.

The third could work.. but the second solution might be the most pragmatic solution here.

Kind Regards
Robin

Okay, there seems to be more config variables where configurability would be good. I think I have to look at option 3 again..

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.