What does corrosion do?
The specifics of what corrosion does should be regarded as an implementation detail and not relied on when writing user code. However, a basic understanding of what corrosion does may be helpful when investigating issues.
FindRust
Corrosion maintains a CMake module FindRust
which is executed when Corrosion is loaded, i.e. at the time
of find_package(corrosion)
, FetchContent_MakeAvailable(corrosion)
or add_subdirectory(corrosion)
depending
on the method used to include Corrosion.
FindRust
will search for installed rust toolchains, respecting the options prefixed with Rust_
documented in
the Usage chapter.
It will select one Rust toolchain to be used for the compilation of Rust code. Toolchains managed by rustup
will be resolved and corrosion will always select a specific toolchain, not a rustup
proxy.
Importing Rust crates
Corrosion's main function is corrosion_import_crate
, which internally will call cargo metadata
to provide
structured information based on the Cargo.toml
manifest.
Corrosion will then iterate over all workspace and/or package members and find all rust crates that are either
a static (staticlib
) or shared (cdylib
) library or a bin
target and create CMake targets matching the
crate name. Additionally, a build target is created for each imported target, containing the required build
command to create the imported artifact. This build command can be influenced by various arguments to
corrosion_import_crate
as well as corrosion specific target properties which are documented int the
Usage chapter.
Corrosion adds the necessary dependencies and also copies the target artifacts out of the cargo build tree
to standard CMake locations, even respecting OUTPUT_DIRECTORY
target properties if set.
Linking
Depending on the type of the crate the linker will either be invoked by CMake or by rustc
.
Rust staticlib
s are linked into C/C++ code via target_link_libraries()
and the linker is
invoked by CMake.
For rust cdylib
s and bin
s, the linker is invoked via rustc
and CMake just gets the final artifact.
CMake invokes the linker
When CMake invokes the linker, everything is as usual. CMake will call the linker with
the compiler as the linker driver and users can just use the regular CMake functions to
modify linking behaviour. corrosion_set_linker()
has no effect.
As a convenience, corrosion_link_libraries()
will forward its arguments to target_link_libraries()
.
Rustc invokes the linker
Rust cdylib
s and bin
s are linked via rustc
. Corrosion provides several helper functions
to influence the linker invocation for such targets.
corrosion_link_libraries()
is a limited version of target_link_libraries()
for rust cdylib
or bin
targets.
Under the hood this function passes -l
and -L
flags to the linker invocation and
ensures the linked libraries are built first.
Much of the advanced functionality available in target_link_libraries()
is not implemented yet,
but pull-requests are welcome! In the meantime, users may want to use
corrosion_add_target_local_rustflags()
to pass customized linking flags.
corrosion_set_linker()
can be used to specify a custom linker, in case the default one
chosen by corrosion is not what you want.
Corrosion currently instructs rustc
to use the C/C++ compiler as the linker driver.
This is done because:
- For C++ code we must link with
libstdc++
orlibc++
(depending on the compiler), so we must either specify the library on the link line or use ac++
compiler as the linker driver. Rustc
s default linker selection currently is not so great. For a number of platformsrustc
will fallback tocc
as the linker driver. When cross-compiling, this leads to linking failures, since the linker driver is for the host architecture. Corrosion avoids this by specifying the C/C++ compiler as the linker driver.
In some cases, especially in older rust versions (pre 1.68), the linker flavor detection
of rustc
is also not correct, so when setting a custom linker you may want to pass the
-C linker-flavor
rustflag via corrosion_add_target_local_rustflags()
.
FFI bindings
For interaction between Rust and other languages there need to be some FFI bindings of some sort. For simple cases manually defining the interfaces may be sufficient, but in many cases users wish to use tools like bindgen, cbindgen, cxx or autocxx to automate the generating of bindings.
In principle there are two different ways to generate the bindings:
- use a
build.rs
script to generate the bindings when cargo is invoked, using library versions of the tools to generate the bindings. - use the cli versions of the tools and setup custom CMake targets/commands to generate the bindings. This approach should be preferred if the bindings are needed by the C/C++ side.
Corrosion currently provides 2 experimental functions to integrate cbindgen and cxx into the build process. They are not 100% production ready yet, but should work well as a template on how to integrate generating bindings into your build process.
Todo: expand this documentation and link to other resources.