Integrating Automatically Generated FFI Bindings
There are a number of tools to automatically generate bindings between Rust and different foreign languages.
bindgen
bindgen is a tool to automatically generate Rust bindings from C headers. As such, integrating bindgen via a build-script works well and their doesn't seem to be a need to create CMake rules for generating the bindings.
cbindgen integration
⚠️⚠️⚠️ EXPERIMENTAL ⚠️⚠️⚠️
cbindgen is a tool that generates C/C++ headers from Rust code. When compiling C/C++
code that #include
s such generated headers the buildsystem must be aware of the dependencies.
Generating the headers via a build-script is possible, but Corrosion offers no guidance here.
Instead, Corrosion offers an experimental function to add CMake rules using cbindgen to generate the headers. This is not available on a stable released version yet, and the details are subject to change.
A helper function which uses cbindgen to generate C/C++ bindings for a Rust crate.
If cbindgen
is not in PATH
the helper function will automatically try to download
cbindgen
and place the built binary into CMAKE_BINARY_DIR
. The binary is shared
between multiple invocations of this function.
The function comes with two different signatures. It's recommended to use the TARGET
based signature when possible.
Auto mode (With a Rust target imported by corrosion)
corrosion_experimental_cbindgen(
TARGET <imported_target_name>
HEADER_NAME <output_header_name>
[CBINDGEN_VERSION <version>]
[FLAGS <flag1> ... <flagN>]
)
Auto-mode specific Arguments
- TARGET: The name of an imported Rust library target, for which bindings should be generated.
If the target is not imported by Corrosion, because the crate only produces an
rlib
, you can instead use the second signature and manually passMANIFEST_DIRECTORY
,CARGO_PACKAGE
andBINDINGS_TARGET
Manual mode (Without a Rust target imported by corrosion)
corrosion_experimental_cbindgen(
MANIFEST_DIRECTORY <package_manifest_directory>
CARGO_PACKAGE <package_name>
BINDINGS_TARGET <cmake_library>
[TARGET_TRIPLE <rust_target_triple>]
HEADER_NAME <output_header_name>
[CBINDGEN_VERSION <version>]
[FLAGS <flag1> ... <flagN>]
)
Manual-mode specific Arguments
-
MANIFEST_DIRECTORY: Manual mode only. Directory of the package defining the library crate bindings should be generated for. If you want to avoid specifying
MANIFEST_DIRECTORY
you could add astaticlib
target to your package manifest as a workaround to make corrosion import the crate. -
CARGO_PACKAGE: Manual mode only. The name of the cargo package that bindings should be generated for. Note: This corresponds to the
cbindgen
--crate
option, which actually wants a package name. -
BINDINGS_TARGET: Manual mode only. Name of an
INTERFACE
CMake target that the generated bindings should be attached to. In auto mode, the generated headers will be attached to the imported rust CMake crate, and corrosion will take care of adding the necessary build dependencies. In manual mode, this target likely doesn't exist, so the user needs to specify an INTERFACE CMake target, which the header files should be attached to. The user must create this target themselves and ensure to add any necessary dependencies (e.g. viaadd_dependencies()
) to ensure that consumers of theINTERFACE
library are not linked before the Rust library has been built. -
TARGET_TRIPLE: Manual mode only. Rust target triple (e.g.
x86_64-unknown-linux-gnu
) that cbindgen should use when generating the bindings. Defaults to target triple that corrosion was confiured to compile for.
Common Arguments
- HEADER_NAME: The name of the generated header file. This will be the name which you include in your C/C++ code
(e.g.
#include "myproject/myheader.h" if you specify
HEADER_NAME "myproject/myheader.h"`. - CBINDGEN_VERSION: Version requirement for cbindgen. Exact semantics to be specified. Currently not implemented.
- FLAGS: Arbitrary other flags for
cbindgen
. Runcbindgen --help
to see the possible flags.
Current limitations
- Cbindgens (optional) macro expansion feature internally actually builds the crate / runs the build script. For this to work as expected in all cases, we probably need to set all the same environment variables as when corrosion builds the crate. However the crate is a library, so we would need to figure out which target builds it - and if there are multiple, potentially generate bindings per-target? Alternatively we could add support of setting some environment variables on rlibs, and pulling that information in when building the actual corrosion targets Alternatively we could restrict corrosions support of this feature to actual imported staticlib/cdylib targets.
cxx integration
⚠️⚠️⚠️ EXPERIMENTAL ⚠️⚠️⚠️
cxx is a tool which generates bindings for C++/Rust interop.
corrosion_add_cxxbridge(cxx_target
CRATE <imported_target_name>
REGEN_TARGET <regen_target_name>
[FILES <file1.rs> <file2.rs>]
)
Adds build-rules to create C++ bindings using the cxx crate.
Arguments:
cxxtarget
: Name of the C++ library target for the bindings, which corrosion will create.- FILES: Input Rust source file containing #[cxx::bridge].
- CRATE: Name of an imported Rust target. Note: Parameter may be renamed before release
- REGEN_TARGET: Name of a custom target that will regenerate the cxx bindings without recompiling. Note: Parameter may be renamed before release
Currently missing arguments
The following arguments to cxxbridge currently have no way to be passed by the user:
--cfg
--cxx-impl-annotations
--include
The created rules approximately do the following:
- Check which version of
cxx
the Rust crate specified by theCRATE
argument depends on. - Check if the exact same version of
cxxbridge-cmd
is installed (available inPATH
) - If not, create a rule to build the exact same version of
cxxbridge-cmd
. - Create rules to run
cxxbridge
and generate- The
rust/cxx.h
header - A header and source file for each of the files specified in
FILES
- The
- The generated sources (and header include directories) are added to the
cxxtarget
CMake library target.
Limitations
We currently require the CRATE
argument to be a target imported by Corrosion, however,
Corrosion does not import rlib
only libraries. As a workaround users can add
staticlib
to their list of crate kinds. In the future this may be solved more properly,
by either adding an option to also import Rlib targets (without build rules) or by
adding a MANIFEST_PATH
argument to this function, specifying where the crate is.
Contributing
Specifically some more realistic test / demo projects and feedback about limitations would be welcome.