setup-cross-toolchain-action

May 4, 2026 · View on GitHub

release github actions

GitHub Action for setup toolchains for cross compilation and cross testing for Rust.

Usage

Inputs

NameRequiredDescriptionTypeDefault
targetTarget tripleString
runnerTest runner (none or platform specific runner described in Platform Support section)String
packagePackages to install for target (whitespace or comma separated list) [1]String

[1]: This is currently only supported for some Linux (GNU) targets on Ubuntu/Debian hosts, and packages will be installed using the form: <sudo as needed> apt-get install --no-install-recommends <each package>:<target's dpkg arch>...

Example workflow: Basic usage

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - name: Install Rust
        run: rustup update stable
      - name: Install cross-compilation tools
        uses: taiki-e/setup-cross-toolchain-action@v1
        with:
          target: aarch64-unknown-linux-gnu
      # setup-cross-toolchain-action sets the `CARGO_BUILD_TARGET` environment variable,
      # so there is no need for an explicit `--target` flag.
      - run: cargo test --verbose
      # `cargo run` also works.
      - run: cargo run --verbose
      # You can also run the cross-compiled binaries directly (via binfmt).
      - run: ./target/aarch64-unknown-linux-gnu/debug/my-app

Example workflow: Multiple targets

jobs:
  test:
    strategy:
      matrix:
        target:
          - aarch64-unknown-linux-gnu
          - riscv64gc-unknown-linux-gnu
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - name: Install Rust
        run: rustup update stable
      - name: Install cross-compilation tools
        uses: taiki-e/setup-cross-toolchain-action@v1
        with:
          target: ${{ matrix.target }}
      - run: cargo test --verbose

Example workflow: Doctest

Since Rust 1.89, doctest is cross-tested by default.

For old Rust versions.

For old Rust versions, cross-testing of doctest is available only on nightly. If you want to use new, old stable, and old nightly in the same matrix, you can use the DOCTEST_XCOMPILE environment variable set by this action to enable doctest only in Rust 1.89+ and old nightly.

jobs:
  test:
    strategy:
      matrix:
        rust:
          - stable
          - nightly
        target:
          - aarch64-unknown-linux-gnu
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - name: Install Rust
        run: rustup update ${{ matrix.rust }} && rustup default ${{ matrix.rust }}
      - name: Install cross-compilation tools
        uses: taiki-e/setup-cross-toolchain-action@v1
        with:
          target: ${{ matrix.target }}
      # On old nightly and `-Z doctest-xcompile` is available,
      # `$DOCTEST_XCOMPILE` is `-Zdoctest-xcompile`.
      #
      # On stable, and nightly since Rust 1.89, `$DOCTEST_XCOMPILE` is not set.
      - run: cargo test --verbose $DOCTEST_XCOMPILE

Example workflow: Tier 3 targets

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - name: Install Rust
        run: rustup update nightly && rustup default nightly
      - name: Install cross-compilation tools
        uses: taiki-e/setup-cross-toolchain-action@v1
        with:
          target: aarch64_be-unknown-linux-gnu
      - run: cargo test --verbose -Z build-std

Cross-compilation of tier 3 targets currently requires nightly to build std. If you want to use tier 1/2 and tier 3 in the same matrix, you can use the BUILD_STD environment variable set by this action to use -Z build-std only for tier 3 targets.

jobs:
  test:
    strategy:
      matrix:
        target:
          - aarch64-unknown-linux-gnu
          - aarch64_be-unknown-linux-gnu
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - name: Install Rust
        run: rustup update nightly && rustup default nightly
      - name: Install cross-compilation tools
        uses: taiki-e/setup-cross-toolchain-action@v1
        with:
          target: ${{ matrix.target }}
      # If target is tier 3, `$BUILD_STD` is `-Zbuild-std`.
      # Otherwise, `$BUILD_STD` is not set.
      #
      # Once `Z build-std` is stabilized, the corresponding flag
      # will be set to `$BUILD_STD` (if it is available).
      - run: cargo test --verbose $BUILD_STD

Platform Support

Linux (GNU)

C++test
✓ (libstdc++) [1]

[1] Except for loongarch64-unknown-linux-gnu

Supported targets:

targethostrunnernote
aarch64-unknown-linux-gnuUbuntu (18.04, 20.04, 22.04, 24.04), Debian (10, 11, 12, 13) [1]native (default, aarch64 host only), qemu-user, valgrind (aarch64 host only)
aarch64_be-unknown-linux-gnuUbuntu (18.04, 22.04, 24.04), Debian (10, 11, 12, 13) [2]qemu-usertier3
arm-unknown-linux-gnueabiUbuntu (18.04, 20.04, 22.04, 24.04), Debian (10, 11, 12, 13) [1]qemu-user, native (aarch64 Debian host only)
armeb-unknown-linux-gnueabiUbuntu (18.04, 22.04), Debian (10, 11, 12, 13) [3]qemu-usertier3
armv5te-unknown-linux-gnueabiUbuntu (18.04, 20.04, 22.04, 24.04), Debian (10, 11, 12, 13) [1]qemu-user, native (aarch64 Debian host only)
armv7-unknown-linux-gnueabiUbuntu (18.04, 20.04, 22.04, 24.04), Debian (10, 11, 12, 13) [1]qemu-user, native (aarch64 Debian host only)
armv7-unknown-linux-gnueabihfUbuntu (18.04, 20.04, 22.04, 24.04), Debian (10, 11, 12, 13) [1]native (default, aarch64 host only), qemu-user, valgrind (aarch64 host only)
i586-unknown-linux-gnuUbuntu (18.04, 20.04, 22.04, 24.04) [1]native (x86_64 host only), qemu-user (default)[7]
i686-unknown-linux-gnuUbuntu (18.04, 20.04, 22.04, 24.04) [1]native (default, x86_64 host only), qemu-user, valgrind (x86_64 host only)[7]
loongarch64-unknown-linux-gnuUbuntu (18.04, 20.04, 22.04, 24.04), Debian (10, 11, 12, 13) [4]qemu-userexperimental
mips-unknown-linux-gnuUbuntu (18.04, 22.04, 24.04), Debian (10, 11, 12, 13) [1]qemu-usertier3 [6]
mips64-unknown-linux-gnuabi64Ubuntu (18.04, 22.04, 24.04), Debian (10, 11, 12, 13) [1]qemu-usertier3
mips64el-unknown-linux-gnuabi64Ubuntu (18.04, 20.04, 22.04, 24.04), Debian (10, 11, 12, 13) [1]qemu-usertier3
mipsel-unknown-linux-gnuUbuntu (18.04, 20.04, 22.04, 24.04), Debian (10, 11, 12, 13) [1]qemu-usertier3 [6]
mipsisa32r6-unknown-linux-gnuUbuntu (22.04, 24.04), Debian (10, 11, 12, 13) [1]qemu-usertier3
mipsisa32r6el-unknown-linux-gnuUbuntu (20.04, 22.04, 24.04), Debian (10, 11, 12, 13) [1]qemu-usertier3
mipsisa64r6-unknown-linux-gnuabi64Ubuntu (22.04, 24.04), Debian (10, 11, 12, 13) [1]qemu-usertier3
mipsisa64r6el-unknown-linux-gnuabi64Ubuntu (20.04, 22.04, 24.04), Debian (10, 11, 12, 13) [1]qemu-usertier3
powerpc-unknown-linux-gnuUbuntu (18.04, 20.04, 22.04, 24.04), Debian (10, 11, 12, 13) [1]qemu-user
powerpc64-unknown-linux-gnuUbuntu (18.04, 22.04, 24.04), Debian (10, 11, 12, 13) [1]qemu-user
powerpc64le-unknown-linux-gnuUbuntu (18.04, 20.04, 22.04, 24.04), Debian (10, 11, 12, 13) [1]qemu-user
riscv32gc-unknown-linux-gnuUbuntu (18.04, 20.04, 22.04, 24.04), Debian (10, 11, 12, 13) [5]qemu-user
riscv64a23-unknown-linux-gnuubuntu (18.04, 22.04, 24.04), Debian (10, 11, 12, 13) [1]qemu-user
riscv64gc-unknown-linux-gnuubuntu (18.04, 22.04, 24.04), Debian (10, 11, 12, 13) [1]qemu-user
s390x-unknown-linux-gnuUbuntu (18.04, 20.04, 22.04, 24.04), Debian (10, 11, 12, 13) [1]qemu-user
sparc-unknown-linux-gnuUbuntu (18.04, 22.04, 24.04), Debian (10, 12, 13) [1]qemu-usertier3, experimental
sparc64-unknown-linux-gnuUbuntu (18.04, 22.04, 24.04), Debian (10, 11, 12, 13) [1]qemu-user
thumbv7neon-unknown-linux-gnueabihfUbuntu (18.04, 20.04, 22.04, 24.04), Debian (10, 11, 12, 13) [1]native (default, aarch64 host only), qemu-user
x86_64-unknown-linux-gnuUbuntu (18.04, 20.04, 22.04, 24.04), Debian (10, 11, 12, 13) [1]native (default, x86_64 host only), qemu-user, valgrind (x86_64 host only)

[1] GCC 7, glibc 2.27 for Ubuntu 18.04. GCC 9, glibc 2.31 for Ubuntu 20.04. GCC 11, glibc 2.35 for Ubuntu 22.04. GCC 13, glibc 2.39 for Ubuntu 24.04. GCC 8, glibc 2.28 for Debian 10. GCC 10, glibc 2.31 for Debian 11. GCC 12, glibc 2.36 for Debian 12, GCC 14, glibc 2.41 for Debian 13.
[2] GCC 14, glibc 2.40
[3] GCC 7, glibc 2.25
[4] GCC 14, glibc 2.40
[5] GCC 11, glibc 2.33
[6] Since nightly-2023-07-05, mips{,el}-unknown-linux-gnu requires release mode for building std.
[7] Not fully supported with containers.

qemu-user runner

The current default QEMU version is 11.0.

We usually set QEMU CPU to max (or CPU newer than the default if -cpu=max is unavailable) to allow testing more CPU features. If you want to test for a specific CPU, you can override it by setting the QEMU_CPU environment variable.

You can select/pin the version by using qemu input option, or @ syntax in runner input option (if both are set, the latter is preferred). For example:

- uses: taiki-e/setup-cross-toolchain-action@v1
  with:
    target: aarch64-unknown-linux-gnu
    qemu: '7.2'
- uses: taiki-e/setup-cross-toolchain-action@v1
  with:
    target: aarch64-unknown-linux-gnu
    runner: qemu@8.1

valgrind runner

Note: binfmt does not work with this runner.

The current default Valgrind version is 3.26.0.

The current default arguments passed to Valgrind is -v --error-exitcode=1 --error-limit=no --leak-check=full --track-origins=yes --fair-sched=yes --gen-suppressions=all. You can override it by setting the CARGO_TARGET_<target name in upper underscore format>_RUNNER environment variable.

See "test-valgrind" job in our CI config for basic usage with x86_64/i686/aarch64/armv7hf. See "valgrind-cross" job in atomic-maybe-uninit's CI config for how to run tests with valgrind on powerpc64le/s390x/riscv64.

Linux (musl)

libcGCCC++test
musl 1.2.3 / 1.1.24 [1]9? (libstdc++)

[1] 1.2 on Rust 1.71+, otherwise 1.1. 1.1 toolchain is with a patch that fixes CVE-2020-28928.

Supported targets:

targethostrunnernote
aarch64-unknown-linux-muslx86_64/aarch64 Linuxnative (default, aarch64 host only), qemu-user
arm-unknown-linux-musleabix86_64 Linuxqemu-user
arm-unknown-linux-musleabihfx86_64 Linuxqemu-user
armv5te-unknown-linux-musleabix86_64 Linuxqemu-user
armv7-unknown-linux-musleabix86_64 Linuxqemu-user
armv7-unknown-linux-musleabihfx86_64/aarch64 Linuxnative (default, aarch64 host only), qemu-user
i586-unknown-linux-muslx86_64 Linuxnative (x86_64 host only), qemu-user (default)
i686-unknown-linux-muslx86_64 Linuxnative (default, x86_64 host only), qemu-user
powerpc64le-unknown-linux-muslx86_64 Linuxqemu-user
riscv64gc-unknown-linux-muslx86_64 Linuxqemu-user
x86_64-unknown-linux-muslx86_64 Linuxnative (default, x86_64 host only), qemu-user

(Other linux-musl targets supported by rust-cross-toolchain may also work, although this action's CI has not tested them.)

For the qemu-user runner, see "qemu-user runner" section for linux-gnu targets.

Linux (uClibc)

libcGCCC++test
uClibc-ng 1.0.3410.2.0✓ (libstdc++)

Supported targets:

targethostrunnernote
armv5te-unknown-linux-uclibceabix86_64 Linuxqemu-usertier3
armv7-unknown-linux-uclibceabix86_64 Linuxqemu-usertier3
armv7-unknown-linux-uclibceabihfx86_64 Linuxqemu-usertier3
mips-unknown-linux-uclibcx86_64 Linuxqemu-usertier3 [1]
mipsel-unknown-linux-uclibcx86_64 Linuxqemu-usertier3 [1]

[1] mips{,el}-unknown-linux-uclibc requires release mode for building std.

For the qemu-user runner, see "qemu-user runner" section for linux-gnu targets.

Android

ClangC++test
14✓ (libc++)

Note: By making use of these targets you accept the Android SDK License

Supported targets:

targetapi levelhostrunnernote
aarch64-linux-android21 (default), 22-24, 26-33 [1]x86_64 Linuxqemu-user
arm-linux-androideabi21 / 19 [2] (default), 21-24, 26-33 [1]x86_64 Linuxqemu-user
armv7-linux-androideabi21 / 19 [2] (default), 21-24, 26-33 [1]x86_64 Linuxqemu-user
i686-linux-android21 / 19 [2] (default), 21-24, 26-33 [1]x86_64 Linuxnative (default), qemu-user
thumbv7neon-linux-androideabi21 / 19 [2] (default), 21-24, 26-33 [1]x86_64 Linuxqemu-user
x86_64-linux-android21 (default), 22-24, 26-33 [1]x86_64 Linuxnative (default), qemu-user

[1] This action currently uses the API level 24 system image, so cargo test and cargo run may not work on API level 26+.
[2] 21 on Rust 1.82+, otherwise 19.

(Other android targets supported by rust-cross-toolchain may also work, although this action's CI has not tested them.)

You can select/pin the API level version by using @ syntax in target option. For example:

- uses: taiki-e/setup-cross-toolchain-action@v1
  with:
    target: arm-linux-androideabi@21

For the qemu-user runner, see "qemu-user runner" section for linux-gnu targets.

FreeBSD

C++test
✓ (libc++)

Supported targets:

targetversionhostnote
aarch64-unknown-freebsd12.4 (default), 13.5, 14.3Ubuntu, Debian [1]tier3
i686-unknown-freebsd12.4 (default), 13.5, 14.3Ubuntu, Debian [1]
x86_64-unknown-freebsd12.4 (default), 13.5, 14.3Ubuntu, Debian [1]

[1] Clang 13 for Ubuntu 18.04, otherwise Clang 15.

(Other FreeBSD targets supported by rust-cross-toolchain may also work, although this action's CI has not tested them.)

You can select/pin the OS version by using @ syntax in target option. For example:

- uses: taiki-e/setup-cross-toolchain-action@v1
  with:
    target: x86_64-unknown-freebsd@14

Only specifying a major version is supported.

NetBSD

GCCC++test
7.5.0✓ (libstdc++)

Supported targets:

targetversionhostnote
aarch64-unknown-netbsd9.4 (default), 10.1x86_64 Linuxtier3
x86_64-unknown-netbsd9.4 (default [1]), 8.2, 10.1x86_64 Linux

[1] 9 on Rust 1.67+, otherwise 8.

(Other NetBSD targets supported by rust-cross-toolchain may also work, although this action's CI has not tested them.)

You can select/pin the OS version by using @ syntax in target option. For example:

- uses: taiki-e/setup-cross-toolchain-action@v1
  with:
    target: x86_64-unknown-netbsd@10

Only specifying a major version is supported.

illumos

libcGCCC++test
solaris 2.108.5.0✓ (libstdc++)

Supported targets:

targethostnote
x86_64-unknown-illumosx86_64 Linux (any libc)

WASI

libcClangC++test
wasi-sdk 27 (wasi-libc 3f7eb4c)20? (libc++)

Supported targets:

targethostrunnernote
wasm32-wasip1Linuxwasmtime
wasm32-wasip1-threadsLinuxwasmtime
wasm32-wasip2Linuxwasmtimebinfmt does not work due to .wasm file in this target is not marked as executable
wasm32-wasiLinuxwasmtimeRemoved in Rust 1.84

Windows (MinGW)

C++test
✓ (libstdc++)

Supported targets:

targethostrunnernote
x86_64-pc-windows-gnuWindows, Ubuntu (22.04, 24.04), Debian (11, 12) [1]native (Windows host) / wine (Linux host)

[1] GCC 10, MinGW-w64 8 for Ubuntu 22.04. GCC 13, MinGW-w64 11 for Ubuntu 24.04. GCC 10, MinGW-w64 8 for Debian 11. GCC 12, MinGW-w64 10 for Debian 12.

On Windows host, GitHub-provided Windows runners support cross-compile for other architectures or environments, so this action just runs rustup target add and/or sets some environment variables.

(Other Windows targets may also work, although this action's CI has not tested them.)

On Linux host, this action installs MinGW toolchain and Wine.

wine runner

The current default Wine version is 10.0.

You can select/pin the version by using wine input option, or @ syntax in runner input option (if both are set, the latter is preferred). For example:

- uses: taiki-e/setup-cross-toolchain-action@v1
  with:
    target: x86_64-pc-windows-gnu
    wine: '9.22'
- uses: taiki-e/setup-cross-toolchain-action@v1
  with:
    target: x86_64-pc-windows-gnu
    runner: wine@9.22

Windows (LLVM MinGW)

libcClangC++test
Mingw-w64 7c9cfe618✓ (libc++)

Supported targets:

targethostrunnernote
aarch64-pc-windows-gnullvmWindows (arm64 only), Ubuntu (22.04, 24.04)wine
i686-pc-windows-gnullvmUbuntu (22.04, 24.04)wine
x86_64-pc-windows-gnullvmWindows (x86_64 only), Ubuntu (22.04, 24.04)wine

For the wine runner for {i686,x86_64}-pc-windows-gnullvm, see "wine runner" section for windows-gnu targets.

The wine runner for aarch64-pc-windows-gnullvm is AArch64 Wine running on qemu-user; specifying the Wine version is not yet supported, but the QEMU version can be specified by using qemu input option like Linux targets.

Windows (MSVC)

C++test
✓ [1]

[1] For x86/x86_64 targets all runners and for aarch64 targets only arm64 runners.

Supported targets:

targethostrunnernote
aarch64-pc-windows-msvcWindowsnative
i686-pc-windows-msvcWindowsnative
x86_64-pc-windows-msvcWindowsnative
i586-pc-windows-msvcWindowsnativeRemoved in Rust 1.87

GitHub-provided Windows runners support cross-compile for other architectures or environments, so this action just runs rustup target add and/or sets some environment variables.

(Other Windows targets may also work, although this action's CI has not tested them.)

macOS

C++test
✓ [1]

[1] For x86_64-apple-darwin all runners and for aarch64-apple-darwin only arm64 runners. (x86_64h-apple-darwin is also x86_64 but build-only because the CPU of GitHub-provided macOS runners is older than Haswell. If you use a large runner or self-hosted runner, you may be able to run the test.)

Supported targets:

targethostrunnernote
aarch64-apple-darwinmacOSnative
x86_64-apple-darwinmacOSnative
x86_64h-apple-darwinmacOSnativetier3

GitHub-provided macOS runners support cross-compile for other architectures or environments, so this action just runs rustup target add and/or sets some environment variables.

(Other macOS targets may also work, although this action's CI has not tested them.)

Mac Catalyst

C++test
✓ [1]

[1] For x86_64-apple-ios-macabi only x86_64 runners and for aarch64-apple-ios-macabi only arm64 runners.

Supported targets:

targethostrunnernote
aarch64-apple-ios-macabimacOSnative
x86_64-apple-ios-macabimacOSnative

GitHub-provided macOS runners support cross-compile for other targets, so this action just runs rustup target add and/or sets some environment variables.

Security

The @v<major> tags are updated with each release. If you want to enhance workflow stability and security against supply chain attacks, consider using the @v<major>.<minor>.<patch> tag or their hash to pin the version and regularly updating with dependency cooldown. Since all releases are immutable, pinning the version in either way should have the same effect.

Compatibility

This action has been tested for GitHub-hosted runners (Ubuntu, macOS, Windows) and containers (Ubuntu, Debian).

To use this action in self-hosted runners or in containers, at least the following tools are required:

  • bash
  • rustup, cargo

Currently, when using this action with containers, --privileged option is required (due to binfmt).

container:
  image: '...'
  options: --privileged

Note that what this action installs for its setup (such as above tools) is considered an implementation detail if they are installed by this action's side, and there is no guarantee that they will be available in subsequent steps, because this action is not an action for installing those tools.

License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.