Self-hosted service
cross-rs/cross avatar
cross-rs/cross

cross-rs/cross: cross compiling and cross testing Rust crates without touching your system

“Zero setup” cross compilation and “cross testing” of Rust crates

8,322 stars462 forksRustApache-2.0

At a glance

What is it?
cross replaces cargo for cross-target builds by running the toolchain inside a container. It is for Rust developers shipping binaries to aarch64, mips64, powerpc or s390x, and it only works if a container engine and, for tests, binfmt_misc are available.
Who is it for?
Adopt cross-rs/cross if you ship Rust binaries to non-x86_64 targets and want a repeatable container toolchain instead of hand-installed cross linkers; skip it if you cannot run a container engine or need a target that the supported-target table does not list.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 7 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 27, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem cross solves for Rust cross compilation

Building a Rust binary for aarch64-unknown-linux-gnu on an x86_64 host normally means installing a cross linker, a matching sysroot, and the C libraries for the target architecture. On Debian and Ubuntu that is dpkg --add-architecture plus apt-get install of the right -dev packages, and the setup differs per target and per distro. cross removes that step by running the build inside a container image that already holds the cross toolchain and the target libraries. The README describes the result as providing "all the ingredients needed for cross compilation without touching your system installation."

The audience is Rust developers who produce binaries for architectures they are not sitting on. The topics list for the repository covers aarch64, arm, mips, powerpc, s390x, sparc, bsd and windows. If you only ever build for your own host, cross adds a container round trip for nothing. It is also not a replacement for cargo in the sense of a different build system: the README states that cross "has the exact same CLI as Cargo", so the subcommands and flags you already use carry over.

How cross works: cargo CLI, container images, and QEMU for tests

cross is a wrapper. You invoke cross build --target <triple> instead of cargo build --target <triple>, and it starts a container from a target-specific image, mounts your project, and runs the real cargo inside. The binary itself is written in Rust and depends on clap for argument parsing, which is how it mirrors Cargo's CLI surface, and on toml and serde for reading configuration. The list of supported targets lives in targets.toml at the repository root, and the container definitions live under docker/ and crosstool-ng/.

Cross testing is the second half and the more fragile one. The README says testing "relies on QEMU emulation, so testing may fail due to QEMU bugs rather than bugs in your crate." That sentence is the honest version of the trade-off: cross test --target mips64-unknown-linux-gnuabi64 runs your test binary under emulation, and a failure may belong to QEMU. Testing also requires a Linux kernel with binfmt_misc support, which is a hard dependency listed alongside rustup.

Configuration has four entry points, all TOML: a [workspace.metadata.cross] table in Cargo.toml, a Cross.toml in the project root, a path named by the CROSS_CONFIG environment variable, or environment variables directly. The engine is picked automatically, Docker before Podman, unless CROSS_CONTAINER_ENGINE names a binary or path.

Installing cross and running a first cross-target build

The README's install command pulls the crate from the repository rather than from crates.io, so the git source is explicit. You need rustup first.

bash
cargo install cross --git https://github.com/cross-rs/cross

The README also lists two alternatives: pre-compiled release binaries on the GitHub releases page, and cargo-binstall. After installation, the Docker daemon has to be running. The README gives the systemd form, and notes that on WSL2 and other SysVinit systems you use sudo service docker start instead.

bash
sudo systemctl start docker

With the daemon up, a cross-target build is the same command you would give cargo, with cross in its place. The README's own example targets aarch64-unknown-linux-gnu.

bash
cross build --target aarch64-unknown-linux-gnu

The output lands in the usual target directory. If your crate links a C library that is not in the image, the build fails at the link step, and the fix is a pre-build hook. The README shows this for libssl-dev in a Cargo.toml, using the CROSS_DEB_ARCH variable to pick the target architecture package.

toml
[workspace.metadata.cross.target.aarch64-unknown-linux-gnu]
pre-build = [
    "dpkg --add-architecture $CROSS_DEB_ARCH",
    "apt-get update && apt-get --assume-yes install libssl-dev:$CROSS_DEB_ARCH"
]

To run the test suite under emulation, the README's second example uses mips64-unknown-linux-gnuabi64.

bash
cross test --target mips64-unknown-linux-gnuabi64

Where cross stops being the right tool

The container dependency is the first wall. Docker must be version 20.10 (API 1.40) or later, or Podman 3.4.0 or later, and on Linux a non-root user has to be in the docker group or run rootless Docker. A machine with no container engine gets nothing from cross, and the README does not describe a fallback path that skips the container.

Cross testing narrows the audience further. binfmt_misc is a Linux kernel feature, so the test half of the tool is effectively Linux-only, and the README attributes failures to QEMU as readily as to your code. If your test suite is timing-sensitive or exercises threads and signals heavily, emulation is a poor proxy for the real target.

Running cross from inside a container has its own documented limits. You must set CROSS_CONTAINER_IN_CONTAINER=true, and the README states that finding the mount point for the container's root directory "is currently only available for the overlayfs2 storage driver." It also warns that the parent container must not be stopped before the child, because Docker cannot unmount the overlayfs while the child still uses it. That is a narrow, brittle setup, and the README presents it as such rather than as a general solution.

cross compared with plain cargo and a hand-built toolchain

The alternative most teams already have is cargo with a manually configured linker in .cargo/config.toml plus a target sysroot installed through the system package manager or downloaded separately. That approach has no container runtime requirement and no QEMU in the loop, and it works on macOS and Windows hosts for targets whose toolchains are distributable. Its cost is that every developer and every CI runner has to reproduce the same sysroot and linker setup, and a distro upgrade can break it.

cross inverts that: the target environment is defined in the image and the config file, so a fresh machine needs rustup and a container engine and nothing else. The price is the container runtime, the image pull on first use, and the fact that anything the image lacks must be installed by a pre-build hook you write. For a single target on a single distro, hand configuration is less machinery. For a matrix of targets across several architectures, the container definition is the part that stays reproducible.

Release cadence, licence, and what upgrading costs

The most recent release listed is v0.2.5 from 2023-02-04, with v0.2.4 and v0.2.3 in July 2022. The repository's last push was on 2026-08-19, so work continues on the main branch even though tagged releases are old. The Cargo.toml carries version = "0.2.5" and edition = "2024" with rust-version = "1.85.0", which means the current source expects a recent toolchain regardless of which release you install. Installing from git, as the README instructs, gets you the main branch rather than a tagged release, and that is the version whose minimum Rust is 1.85.0.

On licensing, the crate declares MIT OR Apache-2.0, and the repository ships both LICENSE-MIT and LICENSE-APACHE. The README's badge and the repository description both point at Apache-2.0; the Cargo.toml is the more specific of the two and states the dual option. That is a permissive arrangement, but the container images cross pulls are separate artifacts with their own contents, and the README does not describe their licensing. If your organisation has rules about what may run in a build container, that is a question for the image definitions under docker/, not for the cross crate's own licence.

Editorial conclusion

Adopt cross-rs/cross if you ship Rust binaries to non-x86_64 targets and want a repeatable container toolchain instead of hand-installed cross linkers; skip it if you cannot run a container engine or need a target that the supported-target table does not list. Before committing, check three things: that your target appears in targets.toml with the test column marked, that your container engine meets the documented minimum (Docker 20.10 / API 1.40, or Podman 3.4.0), and that a pre-build step installs any C library your crate links against, because the container image does not carry it by default.

Frequently asked questions

How do I install cross-rs/cross?

The README gives cargo install cross --git https://github.com/cross-rs/cross, and notes that pre-compiled release binaries and cargo-binstall are also options. You need rustup installed first, plus Docker or Podman.

Does cross-rs/cross need Docker, or can it run without a container engine?

One of Docker or Podman is required, and the README does not describe a mode that works without one. If both are installed, cross defaults to Docker; CROSS_CONTAINER_ENGINE selects the engine explicitly.

Why does cross test fail on a target that cross build handles fine?

Cross testing runs the test binary under QEMU emulation, and the README states that testing may fail due to QEMU bugs rather than bugs in your crate. It also requires a Linux kernel with binfmt_misc support.

How do I install a system library that the target container image does not include?

Use a pre-build hook in the cross configuration. The README's example adds the target architecture with dpkg --add-architecture $CROSS_DEB_ARCH and then installs libssl-dev:$CROSS_DEB_ARCH for the aarch64-unknown-linux-gnu target.

Official sources

  1. cross-rs/cross on GitHub
  2. Issues
  3. License: Apache-2.0
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/cross-rs-cross.svg)](https://hysenlabs.com/projects/cross-rs-cross)