Rust plugin

The Rust plugin can be used for Rust projects that use the Cargo build system.

Keys

This plugin provides the following unique keys.

rust-channel

Type

str

Description

The Rust channel or version to use.

Accepted values:

  • A version number, such as "1.99"

  • A channel name, either stable, beta, or nightly

  • A nightly version number, in the format nightly-YYYY-MM-DD

  • "none" to stop the plugin from installing the Rust toolchain

If this key is set to a channel or version, rustup must also be available in the build environment so the plugin can install or select the requested toolchain.

If this key is left unset, the plugin uses rustup and defaults to the stable channel. However, if Cargo and the Rust compiler are already available in the build environment, the plugin uses those directly and skips the rustup toolchain selection.

rust-features

Type

list[str]

Description

The build features to use for optional dependencies.

Equivalent to the --features option in Cargo. Set to ["*"] to select all the features available in the project.

This option doesn’t override any default features specified by the project itself.

To override the default features, see the rust-no-default-features key.

rust-no-default-features

Type

bool

Description

Whether to ignore the features specified by the project.

If set, the rust-features key can specify an exhaustive list of features to override.

rust-path

Type

list[str]

Description

The path to the directory containing the manifest.

Equivalent to the --manifest-path option in Cargo.

Defaults to ".".

rust-use-global-lto

Type

bool

Description

Whether to use global LTO.

This option may significantly impact the build performance but reduce the final binary size and improve runtime performance. This will forcibly enable LTO for all the crates you specified, regardless of whether the projects have the LTO option enabled in the manifest.

This is equivalent to declaring lto = "fat" in the manifest.

To further improve runtime performance, see Performance tuning.

rust-ignore-toolchain-file

Type

bool

Description

Whether to ignore the rust-toolchain.toml and rust-toolchain files.

The part source may use this file to specify which Rust toolchain to use and which component to install. To bypass the upstream project’s specifications, set to true.

rust-cargo-parameters

Type

list[str]

Description

The extra parameters to pass to Cargo.

rust-inherit-ldflags

Type

bool

Description

Whether to inherit the LDFLAGS environment variable.

This key adds LDFLAGS from the environment to the Rust linker directives.

By default, the Cargo build system and Rust compiler don’t respect the LDFLAGS environment variable. If set to true,the plugin forcibly adds the contents listed by LDFLAGS to the Rust linker directives by wrapping and appending its value to RUSTFLAGS.

Squashing LDFLAGS into RUSTFLAGS makes the Rust binary in a classically-confined snap respect the snap linkage, so that the binary won’t find the libraries in the host filesystem. Here’s an example part that does this:

parts:
  my-classic-app:
    plugin: rust
    source: .
    rust-inherit-ldflags: true
    build-environment:
      - LDFLAGS: >
        -Wl,-rpath=\$ORIGIN/lib:/snap/core24/current/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR
        -Wl,-dynamic-linker=$(find
        /snap/core24/current/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR -name
        'ld*.so.*' -print | head -n1)

Environment variables

This plugin sets the PATH environment variable so the Rust compiler is accessible in the build environment.

Some environment variables may also influence the Rust compiler or Cargo build tool. For more information, see Cargo documentation for the details.

Dependencies

If Cargo and the Rust compiler are already available in the build environment, this plugin uses them directly. Otherwise, it uses rustup to install or select a Rust toolchain.

To provide Rust through another part instead of rustup, define a part named rust-deps, list cargo and rustc with the stage-packages key, and declare it in the after key of the part using the toolchain. For example:

parts:
  rust-deps:
    plugin: nil
    stage-packages:
      - cargo
      - rustc

  my-app:
    plugin: rust
    source: .
    after:
      - rust-deps

When after includes rust-deps, or when rust-channel is set to "none", the plugin validates that Cargo and the Rust compiler are available and does not use rustup. Do not combine after: [rust-deps] when rust-channel is set to anything but "none".

Performance tuning

Warning

Keep in mind that due to individual differences between different projects, some of the optimisations may not work as expected or even incur performance penalties.

Some programs may even behave differently or crash if aggressive optimisations are used.

Many Rust programs boast their performance over similar programs implemented in other programming languages. To get even better performance, you might want to follow the tips below.

  • Use the rust-use-global-lto option to enable LTO support. This is suitable for most projects. However, analysing the whole program during the build time requires more memory and CPU time.

  • Specify codegen-units=1 in Cargo.toml to reduce LLVM parallelism. This may sound counter-intuitive, but reducing code generator threads could improve the quality of generated machine code. This option will also reduce the build time performance since the code generator uses only one thread per translation unit.

  • Disable incremental=true in Cargo.toml to improve inter-procedural optimisations. Many projects may have already done this for the release profile. You should check if that is the case for your project.

  • (Advanced) Perform cross-language LTO. This requires installing the correct version of LLVM/Clang and setting the right environment variables. You must know which LLVM version of your selected Rust toolchain is using. You can use rustc -vV to check the LLVM version used by the compiler. For example, you can see Rust 1.81 uses LLVM 18.1 because it prints an output like this:

    rustc 1.81.0 (eeb90cda1 2024-09-04)
    binary: rustc
    commit-hash: eeb90cda1969383f56a2637cbd3037bdf598841c
    commit-date: 2024-09-04
    host: x86_64-unknown-linux-gnu
    release: 1.81.0
    LLVM version: 18.1.7
    

    On Rust toolchains that don’t include the LLVM version, you can check the LLVM version number by examining the lib directory. For example, Rust 1.81 uses LLVM 18.1 because it bundles a libLLVM.so.18.1-rust-1.81.0-stable file under the lib directory. In this case, you would install clang-18 and lld-18 from the Ubuntu archive.

    • You will need to set these environment variables for Clang:

      parts:
        my-app:
          plugin: rust
          source: .
          build-packages:
            - clang-18
            - lld-18
          build-environment:
            - CC: clang-18
            - CXX: clang++-18
            - CFLAGS: -flto=full -O3
            - CXXFLAGS: -flto=full -O3
            - RUSTFLAGS: "-Cembed-bitcode=yes -Clinker-plugin-lto -Clinker=clang-18 -Clink-arg=-flto=full -Clink-arg=-fuse-ld=lld -Clink-arg=-Wl,--lto-O3"
      

      For some projects that manipulate the object files during the build, you may also need:

      export NM=llvm-nm-18
      export AR=llvm-ar-18
      export RANLIB=llvm-ranlib-18
      

      You can refer to the rustc documentation for more information on the meaning of those options.

    • You will need significantly more memory and CPU time for large projects to build and link. For instance, Firefox under full LTO requires about 80 GiB of memory to pass the linking phase.