- Notifications
You must be signed in to change notification settings - Fork399
“Zero setup” cross compilation and “cross testing” of Rust crates
License
Apache-2.0, MIT licenses found
Licenses found
cross-rs/cross
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
“Zero setup” cross compilation and “cross testing” of Rust crates
This project is developed and maintained by thecross-rs team.It was previously maintained by the Rust Embedded Working Group Tools team.New contributors are welcome! Please join ourMatrix room and say hi.
`cross test`ing a crate for the aarch64-unknown-linux-gnu target
cross
will provide all the ingredients needed for cross compilation withouttouching your system installation.cross
provides an environment, cross toolchain and cross compiled libraries,that produces the most portable binaries.“cross testing”,
cross
can test crates for architectures other than i686 andx86_64.The stable, beta and nightly channels are supported.
See ourGetting Started guide for detailedinstallation instructions.
- rustup
- A Linux kernel withbinfmt_misc support is required for cross testing.
One of these container engines is required. If both are installed,cross
willdefault todocker
.
- Docker. Note that on Linux non-sudo users need to be in the
docker
group or use rootless docker.Read the container engineinstall guide for the required installation and post-installation steps. Requires version 20.10 (API 1.40) or later. - Podman. Requires version 3.4.0 or later.
cargo install cross --git https://github.com/cross-rs/cross
It's also possible to directly download the pre-compiledreleasebinaries or usecargo-binstall.
cross
has the exact same CLI asCargobut relies on Docker or Podman. For Docker, you'll have to startthe daemon before you can use it.
# (ONCE PER BOOT, on Linux)# Start the Docker daemon, if it's not already running using systemd# on WSL2 and other systems using SysVinit, use `sudo service docker start`.$ sudo systemctl start docker# MAGIC! This Just Works$ cross build --target aarch64-unknown-linux-gnu# EVEN MORE MAGICAL! This also Just Works$ cross test --target mips64-unknown-linux-gnuabi64# Obviously, this also Just Works$ cross rustc --target powerpc-unknown-linux-gnu --release -- -C lto
Additional documentation can be found on thewiki or thedocs/
subfolder.
You have four options to configurecross
. All of these options use the TOMLformat for configuration and the possible configuration values are documentedhere.
You can directly setconfiguration values in yourCargo.toml
file, under the[workspace.metadata.cross]
table, i.e. key prefix. An exampleconfig snippet would look like this:
[workspace.metadata.cross.target.aarch64-unknown-linux-gnu]# Install libssl-dev:arm64, see <https://github.com/cross-rs/cross/blob/main/docs/custom_images.md#adding-dependencies-to-existing-images>pre-build = ["dpkg --add-architecture $CROSS_DEB_ARCH","apt-get update && apt-get --assume-yes install libssl-dev:$CROSS_DEB_ARCH"][workspace.metadata.cross.target.armv7-unknown-linux-gnueabi]image ="my/image:latest"[workspace.metadata.cross.build]env.volumes = ["A_DIRECTORY=/path/to/volume"]
You can put yourconfiguration inside aCross.toml
filein your project root directory.
By setting theCROSS_CONFIG
environment variable, you can tellcross
whereit should search for the config file. This way you are not limited to aCross.toml
file in the project root.
Besides the TOML-based configuration files, config can be passed throughenvironment variables, too.
When runningcross
from inside a container,cross
needs access tothe hosts docker daemon itself. This is normally achieved by mounting thedocker daemons socket/var/run/docker.sock
. For example:
$ docker run -v /var/run/docker.sock:/var/run/docker.sock -v .:/project \ -w /project my/development-image:tag cross build --target mips64-unknown-linux-gnuabi64
The image runningcross
requires the rust development tools to be installed.
With this setupcross
must find and mount the correct host paths into thecontainer used for cross compilation. This includes the original projectdirectory as well as the root path of the parent container to give access tothe rust build tools.
To informcross
that it is running inside a container setCROSS_CONTAINER_IN_CONTAINER=true
.
A development or CI container can be created like this:
FROM rust:1# set CROSS_CONTAINER_IN_CONTAINER to inform `cross` that it is executed from within a containerENV CROSS_CONTAINER_IN_CONTAINER=true# install `cross`RUN cargo install cross...
Limitations: Finding the mount point for the containers root directory iscurrently only available for the overlayfs2 storage driver. In order to accessthe parent containers rust setup, the child container mounts the parentsoverlayfs. The parent must not be stopped before the child container, as theoverlayfs can not be unmounted correctly by Docker if the child container stillaccesses it.
By default,cross
tries to useDocker orPodman, in that order.If you want to choose a container engine explicitly, you can set thebinary name (or path) using theCROSS_CONTAINER_ENGINE
environment variable.
For example in case you want usePodman, you can setCROSS_CONTAINER_ENGINE=podman
.
A target is considered as “supported” ifcross
can cross compile a“non-trivial” (binary) crate, usually Cargo, for that target.
Testing support (cross test
) is more complicated. It relies onQEMUemulation, so testing may fail due to QEMU bugs rather than bugs in your crate.That said, a target has a ✓ intest
column of the table below if it can runthecompiler-builtins
test suite.
Also, testing is very slow.cross test
runs units testssequentially becauseQEMU gets upset when you spawn multiple threads. This means that, if one of yourunit tests spawns threads, then it's more likely to fail or, worst, neverterminate.
Target | libc | GCC | C++ | QEMU | test |
---|---|---|---|---|---|
aarch64-linux-android [1] | 9.0.8 | 9.0.8 | ✓ | 6.1.0 | ✓ |
aarch64-unknown-linux-gnu | 2.31 | 9.4.0 | ✓ | 6.1.0 | ✓ |
aarch64-unknown-linux-gnu:centos [7] | 2.17 | 4.8.5 | 4.2.1 | ✓ | |
aarch64-unknown-linux-musl | 1.2.3 | 9.2.0 | ✓ | 6.1.0 | ✓ |
arm-linux-androideabi [1] | 9.0.8 | 9.0.8 | ✓ | 6.1.0 | ✓ |
arm-unknown-linux-gnueabi | 2.31 | 9.4.0 | ✓ | 6.1.0 | ✓ |
arm-unknown-linux-gnueabihf | 2.31 | 8.5.0 | ✓ | 6.1.0 | ✓ |
arm-unknown-linux-musleabi | 1.2.3 | 9.2.0 | ✓ | 6.1.0 | ✓ |
arm-unknown-linux-musleabihf | 1.2.3 | 9.2.0 | ✓ | 6.1.0 | ✓ |
armv5te-unknown-linux-gnueabi | 2.31 | 9.4.0 | ✓ | 6.1.0 | ✓ |
armv5te-unknown-linux-musleabi | 1.2.3 | 9.2.0 | ✓ | 6.1.0 | ✓ |
armv7-linux-androideabi [1] | 9.0.8 | 9.0.8 | ✓ | 6.1.0 | ✓ |
armv7-unknown-linux-gnueabi | 2.31 | 9.4.0 | ✓ | 6.1.0 | ✓ |
armv7-unknown-linux-gnueabihf | 2.31 | 9.4.0 | ✓ | 6.1.0 | ✓ |
armv7-unknown-linux-musleabi | 1.2.3 | 9.2.0 | ✓ | 6.1.0 | ✓ |
armv7-unknown-linux-musleabihf | 1.2.3 | 9.2.0 | ✓ | 6.1.0 | ✓ |
i586-unknown-linux-gnu | 2.31 | 9.4.0 | ✓ | N/A | ✓ |
i586-unknown-linux-musl | 1.2.3 | 9.2.0 | ✓ | N/A | ✓ |
i686-unknown-freebsd | 1.5 | 6.4.0 | ✓ | N/A | |
i686-linux-android [1] | 9.0.8 | 9.0.8 | ✓ | 6.1.0 | ✓ |
i686-pc-windows-gnu | N/A | 9.4 | ✓ | N/A | ✓ |
i686-unknown-linux-gnu | 2.31 | 9.4.0 | ✓ | 6.1.0 | ✓ |
loongarch64-unknown-linux-gnu | 2.36 | 14.2.0 | ✓ | 8.2.2 | ✓ |
loongarch64-unknown-linux-musl | 1.2.5 | 14.2.0 | ✓ | 8.2.2 | ✓ |
mips-unknown-linux-gnu | 2.30 | 9.4.0 | ✓ | 6.1.0 | ✓ |
mips-unknown-linux-musl | 1.2.3 | 9.2.0 | ✓ | 6.1.0 | ✓ |
mips64-unknown-linux-gnuabi64 | 2.30 | 9.4.0 | ✓ | 6.1.0 | ✓ |
mips64-unknown-linux-muslabi64 | 1.2.3 | 9.2.0 | ✓ | 6.1.0 | ✓ |
mips64el-unknown-linux-gnuabi64 | 2.30 | 9.4.0 | ✓ | 6.1.0 | ✓ |
mips64el-unknown-linux-muslabi64 | 1.2.3 | 9.2.0 | ✓ | 6.1.0 | ✓ |
mipsel-unknown-linux-gnu | 2.30 | 9.4.0 | ✓ | 6.1.0 | ✓ |
mipsel-unknown-linux-musl | 1.2.3 | 9.2.0 | ✓ | 6.1.0 | ✓ |
powerpc-unknown-linux-gnu | 2.31 | 9.4.0 | ✓ | 6.1.0 | ✓ |
powerpc64-unknown-linux-gnu | 2.31 | 9.4.0 | ✓ | 6.1.0 | ✓ |
powerpc64le-unknown-linux-gnu | 2.31 | 9.4.0 | ✓ | 6.1.0 | ✓ |
riscv64gc-unknown-linux-gnu | 2.35 | 11.4.0 | ✓ | 8.2.2 | ✓ |
s390x-unknown-linux-gnu | 2.31 | 9.4.0 | ✓ | 6.1.0 | ✓ |
sparc64-unknown-linux-gnu | 2.31 | 9.4.0 | ✓ | 6.1.0 | ✓ |
sparcv9-sun-solaris | 1.22.7 | 8.4.0 | ✓ | N/A | |
thumbv6m-none-eabi [4] | 3.3.0 | 9.2.1 | N/A | ||
thumbv7em-none-eabi [4] | 3.3.0 | 9.2.1 | N/A | ||
thumbv7em-none-eabihf [4] | 3.3.0 | 9.2.1 | N/A | ||
thumbv7m-none-eabi [4] | 3.3.0 | 9.2.1 | N/A | ||
thumbv7neon-linux-androideabi [1] | 9.0.8 | 9.0.8 | ✓ | 6.1.0 | ✓ |
thumbv7neon-unknown-linux-gnueabihf | 2.31 | 9.4.0 | ✓ | N/A | ✓ |
thumbv8m.base-none-eabi [4] | 3.3.0 | 9.2.1 | N/A | ||
thumbv8m.main-none-eabi [4] | 3.3.0 | 9.2.1 | N/A | ||
thumbv8m.main-none-eabihf [4] | 3.3.0 | 9.2.1 | N/A | ||
wasm32-unknown-emscripten [6] | 3.1.14 | 15.0.0 | ✓ | N/A | ✓ |
x86_64-linux-android [1] | 9.0.8 | 9.0.8 | ✓ | 6.1.0 | ✓ |
x86_64-pc-windows-gnu | N/A | 9.3 | ✓ | N/A | ✓ |
x86_64-pc-solaris | 1.22.7 | 8.4.0 | ✓ | N/A | |
x86_64-unknown-freebsd | 1.5 | 6.4.0 | ✓ | N/A | |
x86_64-unknown-dragonfly [2] [3] | 6.0.1 | 10.3.0 | ✓ | N/A | |
x86_64-unknown-illumos | 1.20.4 | 8.4.0 | ✓ | N/A | |
x86_64-unknown-linux-gnu | 2.31 | 9.4.0 | ✓ | 6.1.0 | ✓ |
x86_64-unknown-linux-gnu:centos [5] | 2.17 | 4.8.5 | ✓ | 4.2.1 | ✓ |
x86_64-unknown-linux-musl | 1.2.3 | 9.2.0 | ✓ | N/A | ✓ |
x86_64-unknown-netbsd [3] | 9.2.0 | 9.4.0 | ✓ | N/A |
[1] libc = bionic; Only works with native tests, that is, tests that do notdepends on the Android Runtime. For i686 some tests may fails with theerrorassertion failed: signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR
, seeissue#140 for more information.
[2] Nostd
component available.
[3] For some *BSD and Solaris targets, the libc column indicates the OSrelease version from which libc was extracted.
[4] libc = newlib
[5] Must changeimage = "ghcr.io/cross-rs/x86_64-unknown-linux-gnu:main-centos"
inCross.toml
for[target.x86_64-unknown-linux-gnu]
to use theCentOS7-compatible target.
[6] libc = emscripten and GCC = clang
[7] Must changeimage = "ghcr.io/cross-rs/aarch64-unknown-linux-gnu:main-centos"
inCross.toml
for[target.aarch64-unknown-linux-gnu]
to use theCentOS7-compatible target.
Additional Dockerfiles for other targets can be found incross-toolchains. These includeMSVC and Apple Darwin targets, which we cannot ship pre-built images of.
You can set the QEMU_STRACE variable when you usecross run
to get a backtraceof system calls from “foreign” (non x86_64) binaries.
$ cargo new --bin hello && cd $_$ QEMU_STRACE=1 cross run --target aarch64-unknown-linux-gnu9 brk(NULL) = 0x00000040000230009 uname(0x4000823128) = 0(..)9 write(1,0xa06320,14)Hello, world! = 149 sigaltstack(0x4000823588,(nil)) = 09 munmap(0x0000004000b16000,16384) = 09 exit_group(0)
This crate is guaranteed to compile on stable Rust 1.77.2 and up. Itmightcompile with older versions but that may change in any new patch release.
Some cross-compilation targets require a later Rust version, and using Xargorequires a nightly Rust toolchain.
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE orhttp://www.apache.org/licenses/LICENSE-2.0)
- MIT License (LICENSE-MIT orhttp://opensource.org/licenses/MIT)
at your option.
Unless you explicitly state otherwise, any contribution intentionally submittedfor inclusion in the work by you, as defined in the Apache-2.0 license, shall bedual licensed as above, without any additional terms or conditions.
Contribution to this crate is organized under the terms of theRust Code ofConduct, the maintainer of this crate, thecross-rs team, promisesto intervene to uphold that code of conduct.
About
“Zero setup” cross compilation and “cross testing” of Rust crates