Skip to content

Latest commit

 

History

History
122 lines (95 loc) · 5 KB

File metadata and controls

122 lines (95 loc) · 5 KB

Rust in lib-common

Along with C, Rust is the other compiled language supported in lib-common.

Rust language

The documentation of the Rust language is rich and really good. A good entry point is the official documentation page of the Rust language: https://doc.rust-lang.org/

Build system

Waf is our main build system in lib-common. However, Rust comes with another build system called Cargo. Cargo is a very complete build system integrating a package manager, build scheduler, and some various useful tools. Using Rust without Cargo is very hard and remove a lot of possibilities. So in lib-common base projects, Cargo is used along with Waf.

Unfortunately, having two different build systems for the same repository and shared code is not straight forward.

Waf

Waf being our main build system, it is the one scheduling the different tasks and when to call Cargo to build the different Rust program parts.

To pass the necessary information about dependencies and compilation flags, a waf target needs to be defined for each Rust packages that uses C code. It needs to have 'rust' in its features. The name of cargo package to build can be defined manually, or is the name of the waf target by default.

Example:

ctx(target='libcommon-core-rs', features='rust',
    cargo_package='libcommon-core',
    use=['libcommon-minimal'],
)

With this target, waf generates a file called .waf-cargo-build/waf_build_env.json used by the Cargo build script of the package (see below).

Even though the dependencies between Cargo packages need to be defined in the Cargo build system (see below), it is also necessary that these dependencies are also reflected in the waf build system to avoid concurrency issues when generating the .waf-cargo-build/waf_build_env.json files.

If the Cargo package do not use any of the C code, and only creates a library that is only used by Rust, it is not necessary to have a waf target defined for the Cargo package.

Cargo

Rust packages are built using Cargo. For lib-common based projects, a single Cargo.toml and Cargo.lock workspace is used.

Cargo is a very complete build system. It integrates a package manager that can be used to use external crates very easily. Like uv, a Cargo.lock is generated and keep in-sync to ensure that the external crate versions are consistent. To update the Cargo.lock, run cargo generate-lockfile or simply do a build waf build.

A cargo package is composed of at least of a Cargo.toml. This files defines the characteristics of the package. It is similar to the definition of a waf target.

When adding a new Cargo package, you need to add it into the workspace members list of the workspace Cargo.toml.

To customize the build of a cargo package, a build script build.rs can be used. It must be used when the package is also handled by waf. To ease the transmission of information between waf and cargo, a Rust lib waf-cargo-build should be used in the cargo build script build.rs of the package.

C functions and symbols can be exported from C code to Rust with the help of bindgen. waf-cargo-build integrates the support of bindgen. bindgen generates a file called .waf-cargo-build/bindings.rs that needs to be included in the library code. To avoid exporting multiple times the same C symbols for different rust packages, the different exported symbols by bindgen for a given package are tracked and exported in a file called .waf-cargo-build/bindings_items.json and are blocked in Rust packages that depends of that package.

A cargo package can define a lib and/or multiple bins.

For packages that define libs that can be used by waf (staticlib and cdylib) or binaries (bin), when the cargo package is also referenced by a waf target, waf will hard-link the resulting outputs in the waf build directory for staticlib, or in the source directory same as standard C waf targets.

For packages that only define Rust libraries (lib, rlib, dylib and proc-macro), waf will not call cargo build on these packages, and are entirely handled by Cargo.

For Rust libraries that are used both by C code and other Rust packages, they need to be defined both a Rust library and C libraries, crate-type = ["lib", "staticlib"] or crate-type = ["lib", "cdylib"]

Even though, the dependencies between cargo packages can, and should be defined in waf for cargo packages that use C code, it is also necessary to define in the Cargo build system the dependencies between the different cargo packages.

Limitations

  • TODO: Add sccache as a caching system for dev and CI platforms. This should speed up building the external crates which should not move a lot.

  • TODO: Support tests in Rust in zchk tests.

  • TODO: Add macros, traits and methods to simplify the creation of IOPs.

  • TODO: Add traits for IOP classes. We can detect if a struct is a class in libcommon-derive if the first field is __vptr.

  • TODO: Add traits for qv_t, qh_t, qm_t.