This provides information on creating Rust projects for installation within Chrome OS and Chrome OS SDK. All commands and paths given are from within the SDK's chroot.
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 Chrome OS build system.
WARNING: Some legacy projects are still using cargo.eclass. These two eclasses can't be used together in a single project. Rust projects with dependencies should all use
cros-rust.eclass
.
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.
To import a third-party crate, we need to create an ebuild for it in ~/chromiumos/src/third_party/chromiumos-overlay/dev-rust/<crate_name>/<crate_name>-<crate_version>.ebuild
.
There is a script to automate this process that can be run inside the chroot:
`~/chromiumos/src/platform/dev/contrib/cargo2ebuild.py`
The recommended way to use this script is to:
-k <placeholder crate name>
-d
This process can be done without the script. For an example
crate with the following SemVer dependencies:
[dependencies] libc = "0.2" getopts = "1.2" rayon = "1.4.1" http = "^0.1.8" indexmap = "^1.0" string = "~1.2" bit-set = "~2.7.1" walkdir = "~2"
We would create the following ebuild:
# Copyright <copyright_year> The Chromium OS Authors. All rights reserved. # Distributed under the terms of the GNU General Public License v2 EAPI="7" CROS_RUST_REMOVE_DEV_DEPS=1 inherit cros-rust DESCRIPTION="An example library" HOMEPAGE="url/to/the/homepage" SRC_URI="https://crates.io/api/v1/crates/${PN}/${PV}/download -> ${P}.crate" LICENSE="|| ( <fill in license> )" SLOT="${PV}/${PR}" KEYWORDS="*" DEPEND=" =dev-rust/libc-0.2*:= =dev-rust/getopts-1.2*:= >=dev-rust/rayon-1.4.1 <dev-rust/rayon-2.0:= >=dev-rust/http-0.1.8 <dev-rust/http-0.2:= =dev-rust/indexmap-1*:= =dev-rust/string-1.2*:= >=dev-rust/bit-set-2.7.1 <dev-rust/bit-set-2.8:= =dev-rust/walkdir-2*:= " # (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}"
DESCRIPTION
, HOMEPAGE
, SRC_URI
and LICENSE
should be found from Cargo.toml
or crates.io.cros-rust
ebuild and be listed in DEPEND section.Cargo.toml
which do not have any operator specified in their version number (for example, '^', '<', '~') are handled the same as crates with '^' specified.ebuild example.ebuild digest
to generate Manifest.After creating the ebuild file, running emerge-${BOARD} <crate_name>
will install the crate's package to cros-rust-registry
.
Many third party crates have dev dependencies that are not actually needed for Chrome OS. To keep dev dependencies from being enforced cros-rust.eclass
provides, CROS_RUST_REMOVE_DEV_DEPS
which can be set to remove the dev dependencies during src_prepare
. This is especially useful when there would otherwise be circular dependencies.
If some third-party crates are dependent on some unused crates (e.g., dependencies uses by unused features or they're in dev-dependencies) and we want to mock those unused crates out, we could create empty-crate ebuilds for them. Here is an empty ebuild for example crate:
# Copyright <copyright_year> The Chromium OS Authors. All rights reserved. # Distributed under the terms of the GNU General Public License v2 EAPI="7" CROS_RUST_EMPTY_CRATE=1 inherit cros-rust DESCRIPTION="Empty example crate" HOMEPAGE="" LICENSE="BSD-Google" SLOT="${PV}/${PR}" KEYWORDS="*"
You can create your Rust project in anywhere in the Chrome OS system and it's 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 Chromium OS Authors. All rights reserved. # 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_crate:= example2/first_party_crate:= " # (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" }
cros-rust.eclass publishes this crate by using the cros-rust_publish
command to allow it to be used by other first-party crates.
WARNING: Please make sure your project could be built by both steps for engineering productivity:
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.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 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 Chromium OS Authors. All rights reserved. # 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.
The cros-rust
eclass supports building crates in the Chrome OS 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
.
# provided by ebuild
This macro introduces a replacement of:
[dependencies] data_model = { path = "../data_model" } # provided by ebuild
with:
[dependencies] data_model = { version = "*" }
Example usage: Add dependency to first-party crate
Cargo.toml
but with # provided by ebuild
macro:[dependencies] data_model = { path = "../data_model" } # provided by ebuild
# ignored by ebuild
We will use this to discard parts of [patch.crates-io]
which should be applied to local developer builds but not to ebuilds.
This macro introduces a replacement of:
audio_streams = { path = "../../third_party/adhd/audio_streams" } # ignored by ebuild
with empty line while building with emerge.
Example usage: Add dependency to first-party crate for sub-crates from root crate.
[patch.crates-io]
section in root crate's Cargo.toml
but with # ignored by ebuild
macro:[patch.crates-io] audio_streams = { path = "../../third_party/adhd/audio_streams" } # ignored by ebuild
Because the sources for all ebuilds in Chrome OS must be available at localmirror, you will have to upload all third-party crate dependencies for the project to localmirror. This is taken care of automatically if you use the cargo2ebuild.py script.
The following will download a crate, upload it to localmirror, and make it accessible for download:
WARNING: localmirror is shared by all Chrome OS developers. If you break it, everybody will have a bad day.
export CRATE_NAME="<crate_name>" export CRATE_VERSION="<crate_version>" mkdir -p /tmp/crates curl -L "https://crates.io/api/v1/crates/${CRATE_NAME}/${CRATE_VERSION}/download" >"/tmp/crates/${CRATE_NAME}-${CRATE_VERSION}.crate" gsutil cp -a public-read "/tmp/crates/${CRATE_NAME}-${CRATE_VERSION}.crate" gs://chromeos-localmirror/distfiles/
There are a few different ways for building and testing first party Rust code.
Using cros_workon_make is the same for Rust as with typical platform2 packages on Chrome OS. 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.
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 Chrome OS leading to undesired consequences. One workaround is to have an up-to-date Cargo.lock file checked in for your project. 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 Chrome OS 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.
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 (none of these exist as of November 30th, 2018) |
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