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 staticlibs are linked into C/C++ code via target_link_libraries() and the linker is invoked by CMake. For rust cdylibs and bins, 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 cdylibs and bins 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++ or libc++ (depending on the compiler), so we must either specify the library on the link line or use a c++ compiler as the linker driver.
  • Rustcs default linker selection currently is not so great. For a number of platforms rustc will fallback to cc 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.