There are two gn targets for building Rust:
rust_library
defines a library which can be used by other targets;rust_binary
defines an executable.Note that both targets can be used with the Fuchsia toolchain and with the host toolchain.
These GN targets should be complemented by a Cargo.toml
manifest file very similar to that of a regular Rust crate except for how dependencies are handled.
There are two types of dependencies:
Third-party dependencies should be added to the manifest file just like in the normal Rust development workflow - see the next section for how third-party dependencies are inserted into the build. All dependencies should be added to the build file as target dependencies. Third-party dependencies are all defined under //third_party/rust-crates
.
Here's an example of a library depending on the third-party crate bitflags
and on a FIDL library at //apps/framework/services
:
BUILD.gn -------- rust_library("my-library") { deps = [ "//apps/framework/services:services_rust_library", "//third_party/rust-crates:bitflags-0.7.0", ] } Cargo.toml ---------- [package] name = "my-library" version = "0.1.0" [dependencies] bitflags = "0.7.0"
Both rust_library
and rust_binary
have a with_tests
attribute which, if set to true, will trigger unit tests associated with the target to be built alongside the target and packaged in a test executable.
Integration tests are currently not supported.
Third-party crates are stored in //third-party/rust-crates/vendor
which we use as a directory source automatically set up by the build system.
In addition, we maintain some local mirrors of projects with Fuchsia-specific changes which haven't made it to crates.io. These mirrors are located in //third_party/rust-mirrors
and their build rules in //third_party/rust-crates
.
To be able to run the script updating third-party crates, you first need to build the cargo-vendor
utility:
scripts/build_cargo_vendor.sh
To update these crates, run the following command:
scripts/update_rust_crates.py
The configurations used as a reference to generate the set of required crates are listed in the update_rust_crates.py
script.
If a crate is not available in the vendor directory, it needs to be added with the following steps.
CONFIGS
in the update script;If a crate needs to link against a native library, the library needs to be present in the NATIVE_LIBS
parameter in the update script.
Some Fuchsia crates are already available on crates.io. These crates need to be referenced in the build configuration file so that the local version is used instead of the published copy.
Integration of Rust into build systems is still very much a work in progress. It largely boils down to the decision of using the rustc
compiler and handling dependencies directly in the build system, or letting the high-level Cargo package manager take care of most of the work. Here's a quick breakdown of how the two strategies compare:
Approach | rustc | cargo |
---|---|---|
Integration cost | High | Low |
Redundancy of build steps | Low | Medium |
Handling of third-party deps | Fully manual | Automated with cargo vendor |
Granularity of third-party deps integration | High | Low |
Handling of generated code (e.g. FIDL) | Fully manual | Fully manual |
Proximity to standard workflow | Low | High |
Given the relatively low amount of Rust code we currently host in the Fuchsia source tree, the Cargo-based approach made more sense:
Note that while Cargo knows how to use the vendor directory to build a single crate, some GN glue had to be added in order to properly integrate with native libraries built independently from the crate.