the Chromium logo

The Chromium Projects

Rust on ChromeOS

This provides information on creating Rust projects for installation within ChromeOS and ChromeOS SDK. All commands and paths given are from within the SDK's chroot.

Usage

cros-rust.eclass is an eclass that supports first-party and third-party crate dependencies. Rust project's ebuild should inherit the eclass to support Rust building in ChromeOS build system.

All the Rust projects using cros-rust.eclass will get dependent crates from /build/${BOARD}/usr/lib/cros_rust_registry instead of crates.io. You'll learn how to publish first-party and third-party crates to cros_rust_registry in the following sections.

Third-party ebuild crates

To add a third-party crate, follow the instructions in the rust_crates repository. No ebuild is needed for third-party crates.

First-party crates

You can create your Rust project in anywhere in the ChromeOS system and its ebuild in a suitable place in chromiumos-overlay with name <category>/<crate_name>-9999.ebuild. Here is an ebuild for an example first-party crate:

# Copyright <copyright_year> The ChromiumOS Authors
# Distributed under the terms of the GNU General Public License v2

EAPI="7"

CROS_WORKON_INCREMENTAL_BUILD=1
CROS_WORKON_LOCALNAME="example"
CROS_WORKON_PROJECT="path/to/project/repository"
# We don't use CROS_WORKON_OUTOFTREE_BUILD here since project's Cargo.toml is
# using "provided by ebuild" macro which supported by cros-rust.
CROS_WORKON_SUBTREE="path/to/project/subtree"

inherit cros-workon cros-rust

DESCRIPTION="An example first party project"
HOMEPAGE="home_page_url"

LICENSE="BSD-Google"
SLOT="0/${PVR}"
KEYWORDS="~*"
IUSE="test"

DEPEND="
	dev-rust/third-party-crates-src:=
"
# (crbug.com/1182669): build-time only deps need to be in RDEPEND so they are pulled in when
# installing binpkgs since the full source tree is required to use the crate.
RDEPEND="${DEPEND}"

# Only include this if you need to install binaries or multiple crates.
src_install() {

	# 1. Publish this library for other first-party crates.
	#    This is needed if other crates depend on this crate.
	cros-rust_src_install
	# 2. Install the binary to image. This isn't needed for libraries.
	dobin "$(cros-rust_get_build_dir)/example_bin"
}

Then follow the instructions in the rust_crates repository for adding a first-party crate.

WARNING: Please make sure your project could be built by both steps for engineering productivity:

  1. From chroot with emerge-${BOARD} CRATE-EBUILD-NAME

    Tips: You can set USE=-lto to speed up build times when using emerge. This turns off link time optimization, which is useful for release builds but significantly increases build times and isn't really needed during development.

  2. From project root directory with cargo build

We add two macros to resolve conflicts between these two build system. Check details from the following section.

Ebuild versioning

Ebuild versions should match the version in Cargo.toml. To keep the versions in sync, add a files/chromeos-version.sh script like this:

#!/bin/sh
#
# Copyright <copyright_year> The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

# Assumes the first 'version =' line in the Cargo.toml is the version for the
# crate.
awk '/^version = / { print $3; exit }' "$1/<path/to/Cargo.toml>" | tr -d '"'

Replace <path/to/Cargo.toml> with the path of Cargo.toml relative to the root of the repository it's in.

Cargo.toml macros

The cros-rust eclass supports building crates in the ChromeOS build system, but it breaks cargo build in some situations. We add two macros which are recognized by the eclass to keep both build systems working. The macros take the form of special comments in Cargo.toml.

Panic Signatures

The default crash handler is not able to generate useful signatures for crashes in Rust binaries. To get better crash signatures, you need to install a custom panic handler which integrates with ChromeOS's crash collector.

All you need to do is to call the following function at the top of main():

fn main() {
    libchromeos::panic_handler::install_memfd_handler();
    ...
}

Ensure that your package & ebuild depend on libchromeos:

Cargo.toml

[dependencies]
libchromeos = { path = "../libchromeos-rs" } # provided by ebuild
...

Ebuild:

DEPEND="
	${COMMON_DEPEND}
	...
	dev-rust/libchromeos:=
	...
"

Workflows

There are a few different ways for building and testing first party Rust code.

cros_workon_make

Using cros_workon_make is the same for Rust as with typical platform2 packages on ChromeOS. The downsides for using it with Rust on CrOS are it modifies the Cargo.toml file and can be slower than running cargo directly. You will want to locally commit any Cargo.toml changes before running cros_workon_make. If you try to run cargo directly with the cros_workon_make-modified Cargo.toml, things will likely be broken, so be sure to checkout the unmodified copy before calling cargo.

cargo

The primary downside of using cargo directly is it will fetch dependencies from crates.io though the internet. These often do not match with the versions used by ChromeOS, leading to undesired consequences.

One workaround is to have an up-to-date Cargo.lock file checked in for your project. Run the following outside the chroot in the crate root:

cros_sdk --working-dir=. -- \
  cargo --config 'source.crates-io.directory="/usr/lib/cros_rust_registry/registry"' generate-lockfile

Also make sure to allow the Cargo.lock in the .gitignore of your crate.

Another is to use the same cargo config as cros_workon_make. There is a helper script that set this up for you:

BOARD=<board> ~/chromiumos/src/platform/dev/contrib/setup_cros_cargo_home

This can be applied outside the ChromeOS chroot by copying the ~/.cargo/config from the chroot outside and updating the paths to be correct for outside the chroot.

***note Note the resulting ~/.cargo/config depends on the cros_rust_registry for the specified ${BOARD}. You may need to run build_packages for the board or emerge-${BOARD} dev-rust/<dependency> to install or update dependencies.


Cross-compiling

This is taken care of in the ~/.cargo/config if you preform the setup above.

The toolchain that is installed by default is targetable to the following triples:

Target Triple Description
x86_64-pc-linux-gnu (default) Used exclusively for packages installed in the chroot
armv7a-cros-linux-gnueabihf Used by 32-bit usermode ARM devices
aarch64-cros-linux-gnu Used by 64-bit usermode ARM devices
x86_64-cros-linux-gnu Used by x86_64 devices

When building Rust projects for development, a non-default target can be selected as follows:

cargo build --target=<target_triple>

If a specific board is being targeted, that board's sysroot can be used for compiling and linking purposes by setting the SYSROOT environment variable as follows:

export SYSROOT="/build/<board>"

If C files are getting compiled with a build script that uses the cc or gcc crates, you may also need to set the TARGET_CC environment variable to point at the appropriate C compiler.

export TARGET_CC="<target_triple>-clang"

If a C/C++ package is being pulled in via pkg-config, the PKG_CONFIG_ALLOW_CROSS environment variable should be exposed. Without this, you might see CrossCompilation as part of an error message during build script execution.

export PKG_CONFIG_ALLOW_CROSS=1