diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a9f4efb..d4a6a6f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,11 +8,22 @@ on: push: branches: - main - - dev + # - dev schedule: - cron: '0 0 * * *' workflow_dispatch: +env: + CARGO_INCREMENTAL: 0 + CARGO_NET_RETRY: 10 + CARGO_TERM_COLOR: always + QEMU_STRACE: 1 + RUST_BACKTRACE: full + RUST_TEST_THREADS: 1 + RUSTDOCFLAGS: -D warnings + RUSTFLAGS: -D warnings + RUSTUP_MAX_RETRIES: 10 + defaults: run: shell: bash @@ -90,10 +101,11 @@ jobs: working-directory: rust-cross-toolchain/docker/test/fixtures/rust - run: cargo $BUILD_STD run --verbose --target ${{ matrix.target }} working-directory: rust-cross-toolchain/docker/test/fixtures/rust - if: matrix.target != 'x86_64-unknown-linux-gnux32' - - run: cargo $BUILD_STD test --verbose --target ${{ matrix.target }} + - run: cargo $BUILD_STD test --verbose --target ${{ matrix.target }} $DOCTEST_XCOMPILE working-directory: rust-cross-toolchain/docker/test/fixtures/rust - if: matrix.target != 'x86_64-unknown-linux-gnux32' + - run: ./target/${{ matrix.target }}/debug/rust-test + working-directory: rust-cross-toolchain + if: matrix.target != 'mipsisa32r6el-unknown-linux-gnu' tidy: runs-on: ubuntu-latest diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f449c1..b8df544 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,12 @@ Note: In this file, do not use the hard wrap in the middle of a sentence for com ## [Unreleased] +- Support binfmt. This allows running the cross-compiled binaries directly. ([#3](https://github.com/taiki-e/setup-cross-toolchain/pull/3)) + +- Set the `DOCTEST_XCOMPILE` environment variable to easily run cross-testing of doctest. ([#3](https://github.com/taiki-e/setup-cross-toolchain/pull/3)) + +- Add `runner` input option. ([#3](https://github.com/taiki-e/setup-cross-toolchain/pull/3)) + ## [1.0.0] - 2022-02-20 Initial release diff --git a/README.md b/README.md index 7120fbe..09b13d4 100644 --- a/README.md +++ b/README.md @@ -18,9 +18,10 @@ GitHub Action for setup toolchains for cross compilation and cross testing for R ### Inputs -| Name | Required | Description | Type | Default | -|----------|:--------:|----------------------------------------------------------------------------------|--------|----------------| -| target | **true** | Target triple | String | | +| Name | Required | Description | Type | Default | +|----------|:--------:|---------------|--------|----------------| +| target | **true** | Target triple | String | | +| runner | false | Test runner | String | | ### Example workflow: Basic usage @@ -39,6 +40,10 @@ jobs: # setup-cross-toolchain 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. + - run: ./target/aarch64-unknown-linux-gnu/debug/my-app ``` ### Example workflow: Multiple targets @@ -80,51 +85,86 @@ jobs: - run: cargo test --verbose -Z doctest-xcompile ``` +Cross-testing of doctest is currently available only on nightly. +If you want to use stable and nightly in the same matrix, you can use the `DOCTEST_XCOMPILE` environment variable set by this action to enable doctest only in nightly. + +```yaml +jobs: + test: + strategy: + matrix: + rust: + - stable + - nightly + target: + - aarch64-unknown-linux-gnu + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install Rust + run: rustup update ${{ matrix.rust }} && rustup default ${{ matrix.rust }} + - name: Install cross-compilation tools + uses: taiki-e/setup-cross-toolchain@v1 + with: + target: ${{ matrix.target }} + # On nightly and `-Z doctest-xcompile` is available, + # `$DOCTEST_XCOMPILE` is `-Z doctest-xcompile`. + # + # On stable, `$DOCTEST_XCOMPILE` is not set. + # Once `-Z doctest-xcompile` is stabilized, the corresponding flag + # will be set to `$DOCTEST_XCOMPILE` (if it is available). + - run: cargo test --verbose $DOCTEST_XCOMPILE +``` + ## Platform Support ### Linux (GNU) | C++ | test | | --- | ---- | -| ✓ (libstdc++) | ✓ (qemu) | +| ✓ (libstdc++) | ✓ | **Supported targets**: -| target | host | -| ------ | ----- | -| `aarch64-unknown-linux-gnu` | ubuntu-latest/ubuntu-20.04 [1], ubuntu-18.04 [2] | -| `arm-unknown-linux-gnueabi` | ubuntu-latest/ubuntu-20.04 [1], ubuntu-18.04 [2] | -| `armv5te-unknown-linux-gnueabi` | ubuntu-latest/ubuntu-20.04 [1], ubuntu-18.04 [2] | -| `armv7-unknown-linux-gnueabi` | ubuntu-latest/ubuntu-20.04 [1], ubuntu-18.04 [2] | -| `armv7-unknown-linux-gnueabihf` | ubuntu-latest/ubuntu-20.04 [1], ubuntu-18.04 [2] | -| `i586-unknown-linux-gnu` | ubuntu-latest/ubuntu-20.04 [1], ubuntu-18.04 [2] | -| `i686-unknown-linux-gnu` | ubuntu-latest/ubuntu-20.04 [1], ubuntu-18.04 [2] | -| `mips-unknown-linux-gnu` | ubuntu-18.04 [2] | -| `mips64-unknown-linux-gnuabi64` | ubuntu-18.04 [2] | -| `mips64el-unknown-linux-gnuabi64` | ubuntu-latest/ubuntu-20.04 [1], ubuntu-18.04 [2] | -| `mipsel-unknown-linux-gnu` | ubuntu-latest/ubuntu-20.04 [1], ubuntu-18.04 [2] | -| `mipsisa32r6el-unknown-linux-gnu` (tier3) | ubuntu-latest/ubuntu-20.04 [1] | -| `mipsisa64r6el-unknown-linux-gnuabi64` (tier3) | ubuntu-latest/ubuntu-20.04 [1] | -| `powerpc-unknown-linux-gnu` | ubuntu-latest/ubuntu-20.04 [1], ubuntu-18.04 [2] | -| `powerpc64-unknown-linux-gnu` | ubuntu-18.04 [2] | -| `powerpc64le-unknown-linux-gnu` | ubuntu-latest/ubuntu-20.04 [1], ubuntu-18.04 [2] | -| `riscv64gc-unknown-linux-gnu` | ubuntu-latest/ubuntu-20.04 [1] | -| `s390x-unknown-linux-gnu` | ubuntu-latest/ubuntu-20.04 [1], ubuntu-18.04 [2] | -| `sparc64-unknown-linux-gnu` | ubuntu-18.04 [2] | -| `thumbv7neon-unknown-linux-gnueabihf` | ubuntu-latest/ubuntu-20.04 [1], ubuntu-18.04 [2] | -| `x86_64-unknown-linux-gnu` [3] | ubuntu-latest/ubuntu-20.04 [1], ubuntu-18.04 [2] | +| target | host | runner | +| ------ | ----- | ------ | +| `aarch64-unknown-linux-gnu` | ubuntu-latest/ubuntu-20.04 [1], ubuntu-18.04 [2] | qemu-user (default) | +| `arm-unknown-linux-gnueabi` | ubuntu-latest/ubuntu-20.04 [1], ubuntu-18.04 [2] | qemu-user (default) | +| `armv5te-unknown-linux-gnueabi` | ubuntu-latest/ubuntu-20.04 [1], ubuntu-18.04 [2] | qemu-user (default) | +| `armv7-unknown-linux-gnueabi` | ubuntu-latest/ubuntu-20.04 [1], ubuntu-18.04 [2] | qemu-user (default) | +| `armv7-unknown-linux-gnueabihf` | ubuntu-latest/ubuntu-20.04 [1], ubuntu-18.04 [2] | qemu-user (default) | +| `i586-unknown-linux-gnu` | ubuntu-latest/ubuntu-20.04 [1], ubuntu-18.04 [2] | native (default), qemu-user | +| `i686-unknown-linux-gnu` | ubuntu-latest/ubuntu-20.04 [1], ubuntu-18.04 [2] | native (default), qemu-user | +| `mips-unknown-linux-gnu` | ubuntu-18.04 [2] | qemu-user (default) | +| `mips64-unknown-linux-gnuabi64` | ubuntu-18.04 [2] | qemu-user (default) | +| `mips64el-unknown-linux-gnuabi64` | ubuntu-latest/ubuntu-20.04 [1], ubuntu-18.04 [2] | qemu-user (default) | +| `mipsel-unknown-linux-gnu` | ubuntu-latest/ubuntu-20.04 [1], ubuntu-18.04 [2] | qemu-user (default) | +| `mipsisa32r6el-unknown-linux-gnu` (tier3) | ubuntu-latest/ubuntu-20.04 [1] | qemu-user (default) [3] | +| `mipsisa64r6el-unknown-linux-gnuabi64` (tier3) | ubuntu-latest/ubuntu-20.04 [1] | qemu-user (default) | +| `powerpc-unknown-linux-gnu` | ubuntu-latest/ubuntu-20.04 [1], ubuntu-18.04 [2] | qemu-user (default) | +| `powerpc64-unknown-linux-gnu` | ubuntu-18.04 [2] | qemu-user (default) | +| `powerpc64le-unknown-linux-gnu` | ubuntu-latest/ubuntu-20.04 [1], ubuntu-18.04 [2] | qemu-user (default) | +| `riscv64gc-unknown-linux-gnu` | ubuntu-latest/ubuntu-20.04 [1] | qemu-user (default) | +| `s390x-unknown-linux-gnu` | ubuntu-latest/ubuntu-20.04 [1], ubuntu-18.04 [2] | qemu-user (default) | +| `sparc64-unknown-linux-gnu` | ubuntu-18.04 [2] | qemu-user (default) | +| `thumbv7neon-unknown-linux-gnueabihf` | ubuntu-latest/ubuntu-20.04 [1], ubuntu-18.04 [2] | qemu-user (default) | +| `x86_64-unknown-linux-gnu` | ubuntu-latest/ubuntu-20.04 [1], ubuntu-18.04 [2] | native (default), qemu-user | [1] GCC 9, glibc 2.31
[2] GCC 7, glibc 2.27
-[3] no-op
+[3] binfmt doesn't work
## Related Projects - [rust-cross-toolchain]: Toolchains for cross compilation and cross testing for Rust. - [install-action]: GitHub Action for installing development tools. +- [create-gh-release-action]: GitHub Action for creating GitHub Releases based on changelog. +- [upload-rust-binary-action]: GitHub Action for building and uploading Rust binary to GitHub Releases. +[create-gh-release-action]: https://github.com/taiki-e/create-gh-release-action [install-action]: https://github.com/taiki-e/install-action [rust-cross-toolchain]: https://github.com/taiki-e/rust-cross-toolchain +[upload-rust-binary-action]: https://github.com/taiki-e/upload-rust-binary-action ## License diff --git a/action.yml b/action.yml index d25c587..6ced206 100644 --- a/action.yml +++ b/action.yml @@ -5,6 +5,9 @@ inputs: target: description: Target name required: true + runner: + description: Test runner + required: false runs: using: node16 diff --git a/main.sh b/main.sh index 7bbe9d2..af728c3 100755 --- a/main.sh +++ b/main.sh @@ -10,6 +10,16 @@ x() { "${cmd}" "$@" ) } +retry() { + for i in {1..5}; do + if "$@"; then + return 0 + else + sleep "${i}" + fi + done + "$@" +} bail() { echo "::error::$*" exit 1 @@ -18,28 +28,43 @@ warn() { echo "::warning::$*" } +export DEBIAN_FRONTEND=noninteractive +export RUSTUP_MAX_RETRIES="${RUSTUP_MAX_RETRIES:-10}" + if [[ $# -gt 0 ]]; then bail "invalid argument '$1'" fi target="${INPUT_TARGET:?}" +runner="${INPUT_RUNNER:-}" + target_lower="${target//-/_}" target_lower="${target_lower//./_}" target_upper="$(tr '[:lower:]' '[:upper:]' <<<"${target_lower}")" host=$(rustc -Vv | grep host | sed 's/host: //') +rustc_version=$(rustc -Vv | grep 'release: ' | sed 's/release: //') +rustup_target_list=$(rustup target list) -target_list=$(rustup target list) -if grep <<<"${target_list}" -Eq "^${target}( |$)"; then - rustup target add "${target}" &>/dev/null -else - # for -Z build-std - rustup component add rust-src &>/dev/null - echo "BUILD_STD=-Z build-std" >>"${GITHUB_ENV}" -fi -echo "CARGO_BUILD_TARGET=${target}" >>"${GITHUB_ENV}" +# Refs: https://github.com/multiarch/qemu-user-static. +register_binfmt() { + local url=https://raw.githubusercontent.com/qemu/qemu/44f28df24767cf9dca1ddc9b23157737c4cbb645/scripts/qemu-binfmt-conf.sh + retry curl --proto '=https' --tlsv1.2 -fsSL --retry 10 --retry-connrefused -o __qemu-binfmt-conf.sh "${url}" + # They confuse binfmt. + sed -i 's/ mipsn32 mipsn32el / /' ./__qemu-binfmt-conf.sh + chmod +x ./__qemu-binfmt-conf.sh + if [ ! -d /proc/sys/fs/binfmt_misc ]; then + bail "kernel does not support binfmt" + fi + if [ ! -f /proc/sys/fs/binfmt_misc/register ]; then + sudo mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc + fi + sudo ./__qemu-binfmt-conf.sh --qemu-path /usr/bin --persistent yes + rm ./__qemu-binfmt-conf.sh +} case "${host}" in x86_64-unknown-linux-gnu) + apt_packages=() case "${target}" in x86_64-unknown-linux-gnu) ;; *-linux-gnu*) @@ -81,10 +106,8 @@ case "${host}" in *) cc_target="${target/-unknown/}" ;; esac apt_target="${apt_target:-"${cc_target/i586/i686}"}" - sudo apt-get -o Acquire::Retries=10 -qq update # TODO: can we reduce the setup time by providing an option to skip installing packages for C++? - sudo apt-get -o Acquire::Retries=10 -qq -o Dpkg::Use-Pty=0 install -y \ - "g++-${multilib:+multilib-}${apt_target/_/-}" + apt_packages+=("g++-${multilib:+multilib-}${apt_target/_/-}") # https://github.com/taiki-e/rust-cross-toolchain/blob/main/docker/test/entrypoint.sh echo "CARGO_TARGET_${target_upper}_LINKER=${apt_target}-gcc" >>"${GITHUB_ENV}" @@ -97,102 +120,137 @@ case "${host}" in *) bail "unsupported target '${target}'" ;; esac + use_qemu='' case "${target}" in - x86_64-unknown-linux-gnu) ;; *-unknown-linux-*) - # https://github.com/taiki-e/rust-cross-toolchain/blob/590d6cb4d3a72c26c5096f2ad3033980298cd4aa/docker/test/entrypoint.sh#L251 - # We basically set the newer and more powerful CPU as the - # default QEMU_CPU so that we can test more CPU features. - # In some contexts, we want to test for a specific CPU, - # so respect user-set QEMU_CPU. - case "${target}" in - aarch64-* | aarch64_be-*) - qemu_arch="${target%%-*}" - qemu_cpu=a64fx - ;; - arm* | thumbv7neon-*) - qemu_arch=arm + case "${runner}" in + '') case "${target}" in - # ARMv6: https://en.wikipedia.org/wiki/ARM11 - arm-* | armv6-*) qemu_cpu=arm11mpcore ;; - # ARMv4: https://en.wikipedia.org/wiki/StrongARM - armv4t-*) qemu_cpu=sa1110 ;; - # ARMv5TE - armv5te-*) qemu_cpu=arm1026 ;; - # ARMv7-A+NEONv2 - armv7-* | thumbv7neon-*) qemu_cpu=cortex-a15 ;; - *) bail "unrecognized target '${target}'" ;; + # On x86, qemu-user is not used by default. + x86_64-* | i*86-*) ;; + *) use_qemu='1' ;; esac ;; - i*86-*) qemu_arch=i386 ;; - hexagon-*) qemu_arch=hexagon ;; - m68k-*) qemu_arch=m68k ;; - mips-* | mipsel-*) qemu_arch="${target%%-*}" ;; - mips64-* | mips64el-*) - qemu_arch="${target%%-*}" - # As of qemu 6.1, only Loongson-3A4000 supports MSA instructions with mips64r5. - qemu_cpu=Loongson-3A4000 - ;; - mipsisa32r6-* | mipsisa32r6el-*) - qemu_arch="${target%%-*}" - qemu_arch="${qemu_arch/isa32r6/}" - qemu_cpu=mips32r6-generic - ;; - mipsisa64r6-* | mipsisa64r6el-*) - qemu_arch="${target%%-*}" - qemu_arch="${qemu_arch/isa64r6/64}" - qemu_cpu=I6400 - ;; - powerpc-*spe) - qemu_arch=ppc - qemu_cpu=e500v2 - ;; - powerpc-*) - qemu_arch=ppc - qemu_cpu=Vger - ;; - powerpc64-*) - qemu_arch=ppc64 - qemu_cpu=power10 - ;; - powerpc64le-*) - qemu_arch=ppc64le - qemu_cpu=power10 - ;; - riscv32gc-* | riscv64gc-*) qemu_arch="${target%%gc-*}" ;; - s390x-*) qemu_arch=s390x ;; - sparc-*) qemu_arch=sparc32plus ;; - sparc64-*) qemu_arch=sparc64 ;; - x86_64-*) - qemu_arch=x86_64 - # qemu does not seem to support emulating x86_64 CPU features on x86_64 hosts. - # > qemu-x86_64: warning: TCG doesn't support requested feature - # - # A way that works well for emulating x86_64 CPU features on x86_64 hosts is to use Intel SDE. - # https://www.intel.com/content/www/us/en/developer/articles/tool/software-development-emulator.html - # It is not OSS, but it is licensed under Intel Simplified Software License and redistribution is allowed. - # https://www.intel.com/content/www/us/en/developer/articles/license/pre-release-license-agreement-for-software-development-emulator.html - # https://www.intel.com/content/www/us/en/developer/articles/license/onemkl-license-faq.html - ;; - *) bail "unrecognized target '${target}'" ;; - esac - if [[ -n "${qemu_cpu:-}" ]] && [[ -z "${QEMU_CPU:-}" ]]; then - echo "QEMU_CPU=${qemu_cpu}" >>"${GITHUB_ENV}" - fi - case "${target}" in - *-linux-gnu*) qemu_ld_prefix="/usr/${apt_target}" ;; + qemu-user) use_qemu='1' ;; + *) bail "unrecognized runner '${runner}'" ;; esac - if [[ -n "${qemu_ld_prefix:-}" ]] && [[ -z "${QEMU_LD_PREFIX:-}" ]]; then - echo "QEMU_LD_PREFIX=${qemu_ld_prefix}" >>"${GITHUB_ENV}" - fi - echo "CARGO_TARGET_${target_upper}_RUNNER=qemu-${qemu_arch}" >>"${GITHUB_ENV}" - # https://github.com/taiki-e/dockerfiles/pkgs/container/qemu-user - docker create --name qemu-user ghcr.io/taiki-e/qemu-user - sudo docker cp qemu-user:/usr/bin/qemu-${qemu_arch} /usr/bin/qemu-${qemu_arch} - docker rm -f qemu-user >/dev/null - x qemu-${qemu_arch} --version ;; esac + if [[ -n "${use_qemu}" ]]; then + # https://github.com/taiki-e/rust-cross-toolchain/blob/590d6cb4d3a72c26c5096f2ad3033980298cd4aa/docker/test/entrypoint.sh#L251 + # We basically set the newer and more powerful CPU as the + # default QEMU_CPU so that we can test more CPU features. + # In some contexts, we want to test for a specific CPU, + # so respect user-set QEMU_CPU. + case "${target}" in + aarch64-* | aarch64_be-*) + qemu_arch="${target%%-*}" + qemu_cpu=a64fx + ;; + arm* | thumbv7neon-*) + qemu_arch=arm + case "${target}" in + # ARMv6: https://en.wikipedia.org/wiki/ARM11 + arm-* | armv6-*) qemu_cpu=arm11mpcore ;; + # ARMv4: https://en.wikipedia.org/wiki/StrongARM + armv4t-*) qemu_cpu=sa1110 ;; + # ARMv5TE + armv5te-*) qemu_cpu=arm1026 ;; + # ARMv7-A+NEONv2 + armv7-* | thumbv7neon-*) qemu_cpu=cortex-a15 ;; + *) bail "unrecognized target '${target}'" ;; + esac + ;; + i*86-*) qemu_arch=i386 ;; + hexagon-*) qemu_arch=hexagon ;; + m68k-*) qemu_arch=m68k ;; + mips-* | mipsel-*) qemu_arch="${target%%-*}" ;; + mips64-* | mips64el-*) + qemu_arch="${target%%-*}" + # As of qemu 6.1, only Loongson-3A4000 supports MSA instructions with mips64r5. + qemu_cpu=Loongson-3A4000 + ;; + mipsisa32r6-* | mipsisa32r6el-*) + qemu_arch="${target%%-*}" + qemu_arch="${qemu_arch/isa32r6/}" + qemu_cpu=mips32r6-generic + ;; + mipsisa64r6-* | mipsisa64r6el-*) + qemu_arch="${target%%-*}" + qemu_arch="${qemu_arch/isa64r6/64}" + qemu_cpu=I6400 + ;; + powerpc-*spe) + qemu_arch=ppc + qemu_cpu=e500v2 + ;; + powerpc-*) + qemu_arch=ppc + qemu_cpu=Vger + ;; + powerpc64-*) + qemu_arch=ppc64 + qemu_cpu=power10 + ;; + powerpc64le-*) + qemu_arch=ppc64le + qemu_cpu=power10 + ;; + riscv32gc-* | riscv64gc-*) qemu_arch="${target%%gc-*}" ;; + s390x-*) qemu_arch=s390x ;; + sparc-*) qemu_arch=sparc32plus ;; + sparc64-*) qemu_arch=sparc64 ;; + x86_64-*) + qemu_arch=x86_64 + # qemu does not seem to support emulating x86_64 CPU features on x86_64 hosts. + # > qemu-x86_64: warning: TCG doesn't support requested feature + # + # A way that works well for emulating x86_64 CPU features on x86_64 hosts is to use Intel SDE. + # https://www.intel.com/content/www/us/en/developer/articles/tool/software-development-emulator.html + # It is not OSS, but it is licensed under Intel Simplified Software License and redistribution is allowed. + # https://www.intel.com/content/www/us/en/developer/articles/license/pre-release-license-agreement-for-software-development-emulator.html + # https://www.intel.com/content/www/us/en/developer/articles/license/onemkl-license-faq.html + ;; + *) bail "unrecognized target '${target}'" ;; + esac + echo "CARGO_TARGET_${target_upper}_RUNNER=qemu-${qemu_arch}" >>"${GITHUB_ENV}" + if [[ -n "${qemu_cpu:-}" ]] && [[ -z "${QEMU_CPU:-}" ]]; then + echo "QEMU_CPU=${qemu_cpu}" >>"${GITHUB_ENV}" + fi + case "${target}" in + *-linux-gnu*) qemu_ld_prefix="/usr/${apt_target}" ;; + esac + if [[ -n "${qemu_ld_prefix:-}" ]] && [[ -z "${QEMU_LD_PREFIX:-}" ]]; then + echo "QEMU_LD_PREFIX=${qemu_ld_prefix}" >>"${GITHUB_ENV}" + fi + # https://github.com/taiki-e/dockerfiles/pkgs/container/qemu-user + docker create --name qemu-user ghcr.io/taiki-e/qemu-user + mkdir -p .setup-cross-toolchain + docker cp qemu-user:/usr/bin .setup-cross-toolchain/qemu + docker rm -f qemu-user >/dev/null + sudo mv .setup-cross-toolchain/qemu/qemu-* /usr/bin/ + rm -rf ./.setup-cross-toolchain + x qemu-${qemu_arch} --version + register_binfmt + fi + + retry sudo apt-get -o Acquire::Retries=10 -qq update + retry sudo apt-get -o Acquire::Retries=10 -qq -o Dpkg::Use-Pty=0 install -y --no-install-recommends \ + "${apt_packages[@]}" ;; *) bail "unsupported host '${host}'" ;; esac + +if grep <<<"${rustup_target_list}" -Eq "^${target}( |$)"; then + retry rustup target add "${target}" &>/dev/null +else + # for -Z build-std + retry rustup component add rust-src &>/dev/null + echo "BUILD_STD=-Z build-std" >>"${GITHUB_ENV}" +fi +echo "CARGO_BUILD_TARGET=${target}" >>"${GITHUB_ENV}" +if [[ "${rustc_version}" == *"nightly"* ]] || [[ "${rustc_version}" == *"dev"* ]]; then + if cargo -Z help | grep -Eq '-Z doctest-xcompile\b'; then + echo "DOCTEST_XCOMPILE=-Z doctest-xcompile" >>"${GITHUB_ENV}" + fi +fi