Repository: cross-rs/cross
Pull request #952 (2022-07-16 20:46:56)

Run non-x86 binaries natively if on a compatible host.

Alexhuszagh: This needs some changes, specifically if we use non-Debian-based hosts. IE, we need a way to get the host architecture if we're using Fedora/CentOS/RHEL, Alpine, Pacman, etc.
Alexhuszagh: This uses `dpkg` as a reasonable default, and then falls back to `uname -m` if present, which is then normalized to the Debian value. This attempts to determine if the host can natively run the binary if `CROSS_RUNNER` is not provided.
bors[bot]: Build failed:
  * [conclusion](https://github.com/cross-rs/cross/runs/7663807357?check_suite_focus=true)

Patch:
diff --git a/.changes/554.json b/.changes/554.json
deleted file mode 100644
index 09b940d..0000000
--- a/.changes/554.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-    "type": "fixed",
-    "description": "add the `--force-non-host` flag for newer rustup versions",
-    "issues": [536]
-}
diff --git a/.changes/880.json b/.changes/880.json
deleted file mode 100644
index 978cdca..0000000
--- a/.changes/880.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-    "description": "added a zig-based image, allowing multiple targets to be built from the same image, using cargo-zigbuild.",
-    "type": "added",
-    "issues": [860]
-}
diff --git a/.changes/942.json b/.changes/942.json
deleted file mode 100644
index 0144174..0000000
--- a/.changes/942.json
+++ /dev/null
@@ -1,15 +0,0 @@
-[
-    {
-        "description": "use non-canonical paths for mount locations.",
-        "type": "changed",
-        "issues": [920]
-    },
-    {
-        "description": "fixed DeviceNS drive parsing in creating WSL-style paths on windows.",
-        "type": "fixed"
-    },
-    {
-        "description": "fixed the environment variable name for mounted volumes.",
-        "type": "fixed"
-    }
-]
diff --git a/.changes/952.json b/.changes/952.json
new file mode 100644
index 0000000..3cea008
--- /dev/null
+++ b/.changes/952.json
@@ -0,0 +1,4 @@
+{
+    "description": "run non-x86 binaries natively if on a compatible host.",
+    "type": "added"
+}
diff --git a/.changes/955.json b/.changes/955.json
deleted file mode 100644
index d57dbb2..0000000
--- a/.changes/955.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-    "description": "Update QEMU to version 7.0.0 for Ubuntu targets",
-    "type": "changed",
-    "breaking": false
-}
diff --git a/.changes/956.json b/.changes/956.json
deleted file mode 100644
index a7cdfff..0000000
--- a/.changes/956.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-  "description": "use Wine from Ubuntu 20.04 WineHQ repo",
-  "type": "changed",
-  "breaking": false
-}
diff --git a/.changes/957.json b/.changes/957.json
deleted file mode 100644
index 4c485be..0000000
--- a/.changes/957.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-    "description": "use latest Debian kernel images",
-    "type": "changed",
-    "breaking": false
-}
diff --git a/.changes/962.json b/.changes/962.json
deleted file mode 100644
index cbff84c..0000000
--- a/.changes/962.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-    "description": "fix SELinux labels to allow use in multiple containers and/or the host filesystem.",
-    "type": "fixed",
-    "issues": [961]
-}
diff --git a/.changes/964.json b/.changes/964.json
deleted file mode 100644
index 721c485..0000000
--- a/.changes/964.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-    "type": "fixed",
-    "description": "don't keep stdin open when running containers."
-}
diff --git a/.changes/974.json b/.changes/974.json
deleted file mode 100644
index 03f3776..0000000
--- a/.changes/974.json
+++ /dev/null
@@ -1,11 +0,0 @@
-[
-    {
-        "description": "change `mips64-unknown-linux-muslabi64` target to hard-float target.",
-        "type": "fixed",
-        "issues": [906]
-    },
-    {
-        "description": "build static libgcc and link to static libgcc for `mips64-unknown-linux-muslabi64` target.",
-        "type": "fixed"
-    }
-]
diff --git a/.changes/984.json b/.changes/984.json
deleted file mode 100644
index e17541f..0000000
--- a/.changes/984.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-    "description": "added linux images for `riscv64gc-unknown-linux-gnu` to allow full system emulation.",
-    "type": "added"
-}
diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml
index c815329..b52be16 100644
--- a/.github/workflows/changelog.yml
+++ b/.github/workflows/changelog.yml
@@ -25,8 +25,8 @@ jobs:
         run: |
           set -x
           set -e
-          readarray -t added_modified < <(jq -r '.[]' <<<'${{ steps.files.outputs.added_modified }}')
-          readarray -t removed < <(jq -r '.[]' <<<'${{ steps.files.outputs.removed }}')
+          readarray -t added_modified <<<"$(jq -r '.[]' <<<'${{ steps.files.outputs.added_modified }}')"
+          readarray -t removed <<<"$(jq -r '.[]' <<<'${{ steps.files.outputs.removed }}')"
           added_count=${#added_modified[@]}
           removed_count=${#removed[@]}
           if ${{ !contains(github.event.pull_request.labels.*.name, 'no changelog' ) }}; then
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index f6d62f7..f446bd0 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -149,7 +149,7 @@ jobs:
               ) && github.event.head_commit.message) || ''
             }}
           matrix: |
-            - { target: x86_64-apple-darwin,              os: macos-12,                                                                               deploy: true }
+            - { target: x86_64-apple-darwin,              os: macos-10.15,                                                                             deploy: true }
             - { target: x86_64-unknown-linux-gnu,         os: ubuntu-latest,  cpp: 1, dylib: 1, std: 1, run: 1, runners: native qemu-user qemu-system, deploy: true }
             - { target: x86_64-unknown-linux-musl,        os: ubuntu-latest,                    std: 1, run: 1,                                        deploy: true }
             - { target: x86_64-pc-windows-msvc,           os: windows-2019,                                                                            deploy: true }
@@ -167,14 +167,14 @@ jobs:
             - { target: mipsel-unknown-linux-gnu,         os: ubuntu-latest,  cpp: 1, dylib: 1, std: 1, run: 1, runners: qemu-user qemu-system }
             - { target: mips64-unknown-linux-gnuabi64,    os: ubuntu-latest,  cpp: 1, dylib: 1, std: 1, run: 1 }
             - { target: mips64el-unknown-linux-gnuabi64,  os: ubuntu-latest,  cpp: 1, dylib: 1, std: 1, run: 1, runners: qemu-user qemu-system }
-            - { target: mips64-unknown-linux-muslabi64,   os: ubuntu-latest,  cpp:1, dylib: 1,  std: 1, run: 1, runners: qemu-user }
+            - { target: mips64-unknown-linux-muslabi64,   os: ubuntu-latest,                    std: 1, run: 1 }
             - { target: mips64el-unknown-linux-muslabi64, os: ubuntu-latest,                    std: 1, run: 1 }
             - { target: powerpc-unknown-linux-gnu,        os: ubuntu-latest,  cpp: 1, dylib: 1, std: 1, run: 1, runners: qemu-user qemu-system }
             - { target: powerpc64-unknown-linux-gnu,      os: ubuntu-latest,  cpp: 1, dylib: 1, std: 1, run: 1, runners: qemu-user qemu-system }
             - { target: powerpc64le-unknown-linux-gnu,    os: ubuntu-latest,  cpp: 1, dylib: 1, std: 1, run: 1, runners: qemu-user qemu-system }
-            - { target: riscv64gc-unknown-linux-gnu,      os: ubuntu-latest,  cpp: 1,           std: 1, run: 1, runners: qemu-user qemu-system }
-            - { target: s390x-unknown-linux-gnu,          os: ubuntu-latest,  cpp: 1, dylib: 1, std: 1, run: 1, runners: qemu-user qemu-system }
-            - { target: sparc64-unknown-linux-gnu,        os: ubuntu-latest,  cpp: 1, dylib: 1, std: 1, run: 1, runners: qemu-user qemu-system }
+            - { target: riscv64gc-unknown-linux-gnu,      os: ubuntu-latest,  cpp: 1,           std: 1, run: 1 }
+            - { target: s390x-unknown-linux-gnu,          os: ubuntu-latest,  cpp: 1, dylib: 1, std: 1, run: 1, runners: qemu-system }
+            - { target: sparc64-unknown-linux-gnu,        os: ubuntu-latest,  cpp: 1, dylib: 1, std: 1, run: 1, runners: qemu-system }
             - { target: aarch64-unknown-linux-musl,       os: ubuntu-latest,  cpp: 1, dylib: 1, std: 1, run: 1 }
             - { target: arm-unknown-linux-musleabihf,     os: ubuntu-latest,  cpp: 1, dylib: 1, std: 1, run: 1 }
             - { target: arm-unknown-linux-musleabi,       os: ubuntu-latest,  cpp: 1, dylib: 1, std: 1, run: 1 }
@@ -209,7 +209,6 @@ jobs:
             - { target: thumbv7em-none-eabihf,            os: ubuntu-latest,                    std: 1 }
             - { target: thumbv7m-none-eabi,               os: ubuntu-latest,                    std: 1 }
             - { target: cross,                            os: ubuntu-latest }
-            - { target: zig,                              os: ubuntu-latest }
 
   build:
     name: target (${{ matrix.pretty }},${{ matrix.os }})
@@ -248,7 +247,7 @@ jobs:
       - name: LLVM instrument coverage
         id: cov
         uses: ./.github/actions/cargo-llvm-cov
-        if: steps.prepare-meta.outputs.has-image  && steps.prepare-meta.outputs.test-variant != 'zig'
+        if: steps.prepare-meta.outputs.has-image
         with:
           name: cross-${{matrix.pretty}}
 
@@ -303,11 +302,6 @@ jobs:
           target: ${{ matrix.target }}
           image: ${{ steps.build-docker-image.outputs.image }}
 
-      - name: Test Zig Image
-        if: steps.prepare-meta.outputs.has-image && steps.prepare-meta.outputs.test-variant == 'zig'
-        run: ./ci/test-zig-image.sh
-        shell: bash
-
       - name: Test Cross Image
         if: steps.prepare-meta.outputs.has-image && steps.prepare-meta.outputs.test-variant == 'cross'
         run: ./ci/test-cross-image.sh
diff --git a/Cargo.lock b/Cargo.lock
index 9a515ee..d8e0b13 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -139,9 +139,9 @@ dependencies = [
 
 [[package]]
 name = "color-eyre"
-version = "0.6.2"
+version = "0.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a667583cca8c4f8436db8de46ea8233c42a7d9ae424a82d338f2e4675229204"
+checksum = "8ebf286c900a6d5867aeff75cfee3192857bb7f24b547d4f0df2ed6baa812c90"
 dependencies = [
  "backtrace",
  "color-spantrace",
@@ -190,7 +190,6 @@ dependencies = [
  "owo-colors",
  "regex",
  "rustc_version",
- "semver",
  "serde",
  "serde_ignored",
  "serde_json",
diff --git a/Cargo.toml b/Cargo.toml
index 19072ac..d26b50f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -28,7 +28,7 @@ members = ["xtask"]
 [dependencies]
 atty = "0.2"
 clap = { version = "3.2.2", features = ["derive", "unstable-v4"] }
-color-eyre = { version = "0.6.2", default-features = false, features = ["track-caller"] }
+color-eyre = { version = "0.6", default-features = false }
 eyre = "0.6"
 thiserror = "1"
 home = "0.5"
@@ -46,7 +46,6 @@ directories = "4.0.1"
 walkdir = { version = "2", optional = true }
 tempfile = "3.3.0"
 owo-colors = { version = "3.4.0", features = ["supports-colors"] }
-semver = "1"
 
 [target.'cfg(not(windows))'.dependencies]
 nix = { version = "0.24", default-features = false, features = ["user"] }
diff --git a/docker/Dockerfile.aarch64-unknown-linux-gnu b/docker/Dockerfile.aarch64-unknown-linux-gnu
index 758a960..2480cd6 100644
--- a/docker/Dockerfile.aarch64-unknown-linux-gnu
+++ b/docker/Dockerfile.aarch64-unknown-linux-gnu
@@ -28,7 +28,7 @@ RUN /dropbear.sh
 COPY linux-image.sh /
 RUN /linux-image.sh aarch64
 
-COPY linux-runner /
+COPY linux-runner base-runner.sh /
 
 ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \
     CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER="/linux-runner aarch64" \
diff --git a/docker/Dockerfile.aarch64-unknown-linux-musl b/docker/Dockerfile.aarch64-unknown-linux-musl
index c6a2e72..6355809 100644
--- a/docker/Dockerfile.aarch64-unknown-linux-musl
+++ b/docker/Dockerfile.aarch64-unknown-linux-musl
@@ -22,7 +22,7 @@ RUN /musl-symlink.sh $CROSS_MUSL_SYSROOT aarch64
 
 COPY aarch64-linux-musl-gcc.sh /usr/bin/
 
-COPY qemu-runner /
+COPY qemu-runner base-runner.sh /
 
 ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_LINKER=aarch64-linux-musl-gcc.sh \
     CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_RUNNER="/qemu-runner aarch64" \
diff --git a/docker/Dockerfile.arm-unknown-linux-gnueabi b/docker/Dockerfile.arm-unknown-linux-gnueabi
index aa6df19..db370a6 100644
--- a/docker/Dockerfile.arm-unknown-linux-gnueabi
+++ b/docker/Dockerfile.arm-unknown-linux-gnueabi
@@ -22,7 +22,7 @@ RUN TARGET_ARCH=armel /deny-debian-packages.sh \
 COPY qemu.sh /
 RUN /qemu.sh arm
 
-COPY qemu-runner /
+COPY qemu-runner base-runner.sh /
 
 ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_LINKER=arm-linux-gnueabi-gcc \
     CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_RUNNER="/qemu-runner arm" \
diff --git a/docker/Dockerfile.arm-unknown-linux-gnueabihf b/docker/Dockerfile.arm-unknown-linux-gnueabihf
index 369f7b3..83fd1e9 100644
--- a/docker/Dockerfile.arm-unknown-linux-gnueabihf
+++ b/docker/Dockerfile.arm-unknown-linux-gnueabihf
@@ -20,10 +20,10 @@ ENV PATH /x-tools/arm-unknown-linux-gnueabihf/bin/:$PATH
 COPY qemu.sh /
 RUN /qemu.sh arm
 
-COPY qemu-runner /
+COPY qemu-runner base-runner.sh /
 
 ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-unknown-linux-gnueabihf-gcc \
-    CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_RUNNER="/qemu-runner arm" \
+    CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_RUNNER="/qemu-runner armhf" \
     CC_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-gcc \
     CXX_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-g++ \
     BINDGEN_EXTRA_CLANG_ARGS_arm_unknown_linux_gnueabihf="--sysroot=/x-tools/arm-unknown-linux-gnueabihf/arm-unknown-linux-gnueabihf/sysroot/" \
diff --git a/docker/Dockerfile.arm-unknown-linux-musleabi b/docker/Dockerfile.arm-unknown-linux-musleabi
index 9a30522..1fbbe8e 100644
--- a/docker/Dockerfile.arm-unknown-linux-musleabi
+++ b/docker/Dockerfile.arm-unknown-linux-musleabi
@@ -24,7 +24,7 @@ ENV CROSS_MUSL_SYSROOT=/usr/local/arm-linux-musleabi
 COPY musl-symlink.sh /
 RUN /musl-symlink.sh $CROSS_MUSL_SYSROOT arm
 
-COPY qemu-runner /
+COPY qemu-runner base-runner.sh /
 
 ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_MUSLEABI_LINKER=arm-linux-musleabi-gcc \
     CARGO_TARGET_ARM_UNKNOWN_LINUX_MUSLEABI_RUNNER="/qemu-runner arm" \
diff --git a/docker/Dockerfile.arm-unknown-linux-musleabihf b/docker/Dockerfile.arm-unknown-linux-musleabihf
index da47f17..e7ae937 100644
--- a/docker/Dockerfile.arm-unknown-linux-musleabihf
+++ b/docker/Dockerfile.arm-unknown-linux-musleabihf
@@ -25,10 +25,10 @@ ENV CROSS_MUSL_SYSROOT=/usr/local/arm-linux-musleabihf
 COPY musl-symlink.sh /
 RUN /musl-symlink.sh $CROSS_MUSL_SYSROOT armhf
 
-COPY qemu-runner /
+COPY qemu-runner base-runner.sh /
 
 ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_MUSLEABIHF_LINKER=arm-linux-musleabihf-gcc \
-    CARGO_TARGET_ARM_UNKNOWN_LINUX_MUSLEABIHF_RUNNER="/qemu-runner arm" \
+    CARGO_TARGET_ARM_UNKNOWN_LINUX_MUSLEABIHF_RUNNER="/qemu-runner armhf" \
     CC_arm_unknown_linux_musleabihf=arm-linux-musleabihf-gcc \
     CXX_arm_unknown_linux_musleabihf=arm-linux-musleabihf-g++ \
     BINDGEN_EXTRA_CLANG_ARGS_arm_unknown_linux_musleabihf="--sysroot=$CROSS_MUSL_SYSROOT" \
diff --git a/docker/Dockerfile.armv5te-unknown-linux-gnueabi b/docker/Dockerfile.armv5te-unknown-linux-gnueabi
index 0d3b718..91ab30d 100644
--- a/docker/Dockerfile.armv5te-unknown-linux-gnueabi
+++ b/docker/Dockerfile.armv5te-unknown-linux-gnueabi
@@ -23,7 +23,7 @@ RUN TARGET_ARCH=armel /deny-debian-packages.sh \
 COPY qemu.sh /
 RUN /qemu.sh arm
 
-COPY qemu-runner /
+COPY qemu-runner base-runner.sh /
 
 ENV CARGO_TARGET_ARMV5TE_UNKNOWN_LINUX_GNUEABI_LINKER=arm-linux-gnueabi-gcc \
     CARGO_TARGET_ARMV5TE_UNKNOWN_LINUX_GNUEABI_RUNNER="/qemu-runner arm" \
diff --git a/docker/Dockerfile.armv5te-unknown-linux-musleabi b/docker/Dockerfile.armv5te-unknown-linux-musleabi
index b4c300a..3d7cb10 100644
--- a/docker/Dockerfile.armv5te-unknown-linux-musleabi
+++ b/docker/Dockerfile.armv5te-unknown-linux-musleabi
@@ -24,7 +24,7 @@ ENV CROSS_MUSL_SYSROOT=/usr/local/arm-linux-musleabi
 COPY musl-symlink.sh /
 RUN /musl-symlink.sh $CROSS_MUSL_SYSROOT arm
 
-COPY qemu-runner /
+COPY qemu-runner base-runner.sh /
 
 ENV CARGO_TARGET_ARMV5TE_UNKNOWN_LINUX_MUSLEABI_LINKER=arm-linux-musleabi-gcc \
     CARGO_TARGET_ARMV5TE_UNKNOWN_LINUX_MUSLEABI_RUNNER="/qemu-runner arm" \
diff --git a/docker/Dockerfile.armv7-unknown-linux-gnueabi b/docker/Dockerfile.armv7-unknown-linux-gnueabi
index 84caad1..7704338 100644
--- a/docker/Dockerfile.armv7-unknown-linux-gnueabi
+++ b/docker/Dockerfile.armv7-unknown-linux-gnueabi
@@ -17,7 +17,7 @@ RUN apt-get install --assume-yes --no-install-recommends \
 COPY qemu.sh /
 RUN /qemu.sh arm
 
-COPY qemu-runner /
+COPY qemu-runner base-runner.sh /
 
 ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABI_LINKER=arm-linux-gnueabi-gcc \
     CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABI_RUNNER="/qemu-runner armv7" \
diff --git a/docker/Dockerfile.armv7-unknown-linux-gnueabihf b/docker/Dockerfile.armv7-unknown-linux-gnueabihf
index 9560bc8..f532b86 100644
--- a/docker/Dockerfile.armv7-unknown-linux-gnueabihf
+++ b/docker/Dockerfile.armv7-unknown-linux-gnueabihf
@@ -28,10 +28,10 @@ RUN /dropbear.sh
 COPY linux-image.sh /
 RUN /linux-image.sh armv7
 
-COPY linux-runner /
+COPY linux-runner base-runner.sh /
 
 ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \
-    CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_RUNNER="/linux-runner armv7" \
+    CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_RUNNER="/linux-runner armv7hf" \
     CC_armv7_unknown_linux_gnueabihf=arm-linux-gnueabihf-gcc \
     CXX_armv7_unknown_linux_gnueabihf=arm-linux-gnueabihf-g++ \
     BINDGEN_EXTRA_CLANG_ARGS_armv7_unknown_linux_gnueabihf="--sysroot=/usr/arm-linux-gnueabihf" \
diff --git a/docker/Dockerfile.armv7-unknown-linux-musleabi b/docker/Dockerfile.armv7-unknown-linux-musleabi
index 05d129b..d03bddb 100644
--- a/docker/Dockerfile.armv7-unknown-linux-musleabi
+++ b/docker/Dockerfile.armv7-unknown-linux-musleabi
@@ -25,7 +25,7 @@ ENV CROSS_MUSL_SYSROOT=/usr/local/arm-linux-musleabi
 COPY musl-symlink.sh /
 RUN /musl-symlink.sh $CROSS_MUSL_SYSROOT arm
 
-COPY qemu-runner /
+COPY qemu-runner base-runner.sh /
 
 ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_MUSLEABI_LINKER=arm-linux-musleabi-gcc \
     CARGO_TARGET_ARMV7_UNKNOWN_LINUX_MUSLEABI_RUNNER="/qemu-runner armv7" \
diff --git a/docker/Dockerfile.armv7-unknown-linux-musleabihf b/docker/Dockerfile.armv7-unknown-linux-musleabihf
index 3742465..fb85b02 100644
--- a/docker/Dockerfile.armv7-unknown-linux-musleabihf
+++ b/docker/Dockerfile.armv7-unknown-linux-musleabihf
@@ -25,10 +25,10 @@ ENV CROSS_MUSL_SYSROOT=/usr/local/arm-linux-musleabihf
 COPY musl-symlink.sh /
 RUN /musl-symlink.sh $CROSS_MUSL_SYSROOT armhf
 
-COPY qemu-runner /
+COPY qemu-runner base-runner.sh /
 
 ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_MUSLEABIHF_LINKER=arm-linux-musleabihf-gcc \
-    CARGO_TARGET_ARMV7_UNKNOWN_LINUX_MUSLEABIHF_RUNNER="/qemu-runner armv7" \
+    CARGO_TARGET_ARMV7_UNKNOWN_LINUX_MUSLEABIHF_RUNNER="/qemu-runner armv7hf" \
     CC_armv7_unknown_linux_musleabihf=arm-linux-musleabihf-gcc \
     CXX_armv7_unknown_linux_musleabihf=arm-linux-musleabihf-g++ \
     BINDGEN_EXTRA_CLANG_ARGS_armv7_unknown_linux_musleabihf="--sysroot=$CROSS_MUSL_SYSROOT" \
diff --git a/docker/Dockerfile.i586-unknown-linux-gnu b/docker/Dockerfile.i586-unknown-linux-gnu
index de2da4e..6ab7bc2 100644
--- a/docker/Dockerfile.i586-unknown-linux-gnu
+++ b/docker/Dockerfile.i586-unknown-linux-gnu
@@ -11,24 +11,12 @@ COPY xargo.sh /
 RUN /xargo.sh
 
 RUN apt-get update && apt-get install --assume-yes --no-install-recommends \
-    g++-i686-linux-gnu \
-    libc6-dev-i386-cross
-
-COPY deny-debian-packages.sh /
-RUN TARGET_ARCH=i386 /deny-debian-packages.sh \
-    binutils \
-    binutils-i686-linux-gnu
+    g++-multilib
 
 COPY qemu.sh /
 RUN /qemu.sh i386
 
-COPY qemu-runner /
+COPY qemu-runner base-runner.sh /
 
-ENV CARGO_TARGET_I586_UNKNOWN_LINUX_GNU_LINKER=i686-linux-gnu-gcc \
-    CARGO_TARGET_I586_UNKNOWN_LINUX_GNU_RUNNER="/qemu-runner i586" \
-    CC_i586_unknown_linux_gnu=i686-linux-gnu-gcc \
-    CXX_i586_unknown_linux_gnu=i686-linux-gnu-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_i586_unknown_linux_gnu="--sysroot=/usr/i686-linux-gnu" \
-    QEMU_LD_PREFIX=/usr/i686-linux-gnu \
-    RUST_TEST_THREADS=1 \
+ENV CARGO_TARGET_I586_UNKNOWN_LINUX_GNU_RUNNER="/qemu-runner i586" \
     PKG_CONFIG_PATH="/usr/lib/i386-linux-gnu/pkgconfig/:${PKG_CONFIG_PATH}"
diff --git a/docker/Dockerfile.i586-unknown-linux-musl b/docker/Dockerfile.i586-unknown-linux-musl
index d33620e..0c58f4e 100644
--- a/docker/Dockerfile.i586-unknown-linux-musl
+++ b/docker/Dockerfile.i586-unknown-linux-musl
@@ -20,7 +20,7 @@ ENV CROSS_MUSL_SYSROOT=/usr/local/i586-linux-musl
 COPY musl-symlink.sh /
 RUN /musl-symlink.sh $CROSS_MUSL_SYSROOT i386
 
-COPY qemu-runner /
+COPY qemu-runner base-runner.sh /
 
 ENV CARGO_TARGET_I586_UNKNOWN_LINUX_MUSL_LINKER=i586-linux-musl-gcc \
     CARGO_TARGET_I586_UNKNOWN_LINUX_MUSL_RUNNER="/qemu-runner i586" \
diff --git a/docker/Dockerfile.i686-unknown-linux-gnu b/docker/Dockerfile.i686-unknown-linux-gnu
index a5926f1..6118955 100644
--- a/docker/Dockerfile.i686-unknown-linux-gnu
+++ b/docker/Dockerfile.i686-unknown-linux-gnu
@@ -11,13 +11,7 @@ COPY xargo.sh /
 RUN /xargo.sh
 
 RUN apt-get update && apt-get install --assume-yes --no-install-recommends \
-    g++-i686-linux-gnu \
-    libc6-dev-i386-cross
-
-COPY deny-debian-packages.sh /
-RUN TARGET_ARCH=i386 /deny-debian-packages.sh \
-    binutils \
-    binutils-i686-linux-gnu
+    g++-multilib
 
 COPY qemu.sh /
 RUN /qemu.sh i386 softmmu
@@ -28,13 +22,7 @@ RUN /dropbear.sh
 COPY linux-image.sh /
 RUN /linux-image.sh i686
 
-COPY linux-runner /
+COPY linux-runner base-runner.sh /
 
-ENV CARGO_TARGET_I686_UNKNOWN_LINUX_GNU_LINKER=i686-linux-gnu-gcc \
-    CARGO_TARGET_I686_UNKNOWN_LINUX_GNU_RUNNER="/linux-runner i686" \
-    CC_i686_unknown_linux_gnu=i686-linux-gnu-gcc \
-    CXX_i686_unknown_linux_gnu=i686-linux-gnu-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_i686_unknown_linux_gnu="--sysroot=/usr/i686-linux-gnu" \
-    QEMU_LD_PREFIX=/usr/i686-linux-gnu \
-    RUST_TEST_THREADS=1 \
+ENV CARGO_TARGET_I686_UNKNOWN_LINUX_GNU_RUNNER="/linux-runner i686" \
     PKG_CONFIG_PATH="/usr/lib/i386-linux-gnu/pkgconfig/:${PKG_CONFIG_PATH}"
diff --git a/docker/Dockerfile.i686-unknown-linux-musl b/docker/Dockerfile.i686-unknown-linux-musl
index 0229684..373ea9f 100644
--- a/docker/Dockerfile.i686-unknown-linux-musl
+++ b/docker/Dockerfile.i686-unknown-linux-musl
@@ -20,7 +20,7 @@ ENV CROSS_MUSL_SYSROOT=/usr/local/i686-linux-musl
 COPY musl-symlink.sh /
 RUN /musl-symlink.sh $CROSS_MUSL_SYSROOT i386
 
-COPY qemu-runner /
+COPY qemu-runner base-runner.sh /
 
 ENV CARGO_TARGET_I686_UNKNOWN_LINUX_MUSL_LINKER=i686-linux-musl-gcc \
     CARGO_TARGET_I686_UNKNOWN_LINUX_MUSL_RUNNER="/qemu-runner i686" \
diff --git a/docker/Dockerfile.mips-unknown-linux-gnu b/docker/Dockerfile.mips-unknown-linux-gnu
index d6c27dc..4b5f4aa 100644
--- a/docker/Dockerfile.mips-unknown-linux-gnu
+++ b/docker/Dockerfile.mips-unknown-linux-gnu
@@ -17,7 +17,7 @@ RUN apt-get install --assume-yes --no-install-recommends \
 COPY qemu.sh /
 RUN /qemu.sh mips
 
-COPY qemu-runner /
+COPY qemu-runner base-runner.sh /
 
 ENV CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_LINKER=mips-linux-gnu-gcc \
     CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_RUNNER="/qemu-runner mips" \
diff --git a/docker/Dockerfile.mips-unknown-linux-musl b/docker/Dockerfile.mips-unknown-linux-musl
index 4ae946a..f722fcc 100644
--- a/docker/Dockerfile.mips-unknown-linux-musl
+++ b/docker/Dockerfile.mips-unknown-linux-musl
@@ -22,7 +22,7 @@ ENV CROSS_MUSL_SYSROOT=/usr/local/mips-linux-muslsf
 COPY musl-symlink.sh /
 RUN /musl-symlink.sh $CROSS_MUSL_SYSROOT mips-sf
 
-COPY qemu-runner /
+COPY qemu-runner base-runner.sh /
 
 ENV CARGO_TARGET_MIPS_UNKNOWN_LINUX_MUSL_LINKER=mips-linux-muslsf-gcc \
     CARGO_TARGET_MIPS_UNKNOWN_LINUX_MUSL_RUNNER="/qemu-runner mips" \
diff --git a/docker/Dockerfile.mips64-unknown-linux-gnuabi64 b/docker/Dockerfile.mips64-unknown-linux-gnuabi64
index 46a39c6..585da05 100644
--- a/docker/Dockerfile.mips64-unknown-linux-gnuabi64
+++ b/docker/Dockerfile.mips64-unknown-linux-gnuabi64
@@ -22,7 +22,7 @@ RUN TARGET_ARCH=mips64 /deny-debian-packages.sh \
 COPY qemu.sh /
 RUN /qemu.sh mips64
 
-COPY qemu-runner /
+COPY qemu-runner base-runner.sh /
 
 ENV CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_LINKER=mips64-linux-gnuabi64-gcc \
     CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_RUNNER="/qemu-runner mips64" \
diff --git a/docker/Dockerfile.mips64-unknown-linux-muslabi64 b/docker/Dockerfile.mips64-unknown-linux-muslabi64
index 7fbecfc..c751bc7 100644
--- a/docker/Dockerfile.mips64-unknown-linux-muslabi64
+++ b/docker/Dockerfile.mips64-unknown-linux-muslabi64
@@ -14,25 +14,19 @@ RUN /qemu.sh mips64
 
 COPY musl.sh /
 RUN /musl.sh \
-    TARGET=mips64-linux-musl \
+    TARGET=mips64-linux-muslsf \
     "COMMON_CONFIG += -with-arch=mips64r2"
 
-ENV CROSS_MUSL_SYSROOT=/usr/local/mips64-linux-musl
+ENV CROSS_MUSL_SYSROOT=/usr/local/mips64-linux-muslsf
 COPY musl-symlink.sh /
-RUN /musl-symlink.sh $CROSS_MUSL_SYSROOT mips64
-RUN mkdir -p $CROSS_MUSL_SYSROOT/usr/lib64
-# needed for the C/C++ runner
-RUN ln -s $CROSS_MUSL_SYSROOT/usr/lib/libc.so $CROSS_MUSL_SYSROOT/usr/lib64/libc.so
-RUN ln -s $CROSS_MUSL_SYSROOT/usr/lib/libc.so.1 $CROSS_MUSL_SYSROOT/usr/lib64/libc.so.1
+RUN /musl-symlink.sh $CROSS_MUSL_SYSROOT mips64-sf
 
-COPY mips64-linux-muslabi64-gcc.sh /usr/bin/
+COPY qemu-runner base-runner.sh /
 
-COPY qemu-runner /
-
-ENV CARGO_TARGET_MIPS64_UNKNOWN_LINUX_MUSLABI64_LINKER=mips64-linux-muslabi64-gcc.sh \
+ENV CARGO_TARGET_MIPS64_UNKNOWN_LINUX_MUSLABI64_LINKER=mips64-linux-muslsf-gcc \
     CARGO_TARGET_MIPS64_UNKNOWN_LINUX_MUSLABI64_RUNNER="/qemu-runner mips64" \
-    CC_mips64_unknown_linux_muslabi64=mips64-linux-musl-gcc \
-    CXX_mips64_unknown_linux_muslabi64=mips64-linux-musl-g++ \
+    CC_mips64_unknown_linux_muslabi64=mips64-linux-muslsf-gcc \
+    CXX_mips64_unknown_linux_muslabi64=mips64-linux-muslsf-g++ \
     BINDGEN_EXTRA_CLANG_ARGS_mips64_unknown_linux_muslabi64="--sysroot=$CROSS_MUSL_SYSROOT" \
     QEMU_LD_PREFIX=$CROSS_MUSL_SYSROOT \
     RUST_TEST_THREADS=1
diff --git a/docker/Dockerfile.mips64el-unknown-linux-gnuabi64 b/docker/Dockerfile.mips64el-unknown-linux-gnuabi64
index b8171fd..eb08531 100644
--- a/docker/Dockerfile.mips64el-unknown-linux-gnuabi64
+++ b/docker/Dockerfile.mips64el-unknown-linux-gnuabi64
@@ -28,7 +28,7 @@ RUN /dropbear.sh
 COPY linux-image.sh /
 RUN /linux-image.sh mips64el
 
-COPY linux-runner /
+COPY linux-runner base-runner.sh /
 
 ENV CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_LINKER=mips64el-linux-gnuabi64-gcc \
     CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_RUNNER="/linux-runner mips64el" \
diff --git a/docker/Dockerfile.mips64el-unknown-linux-muslabi64 b/docker/Dockerfile.mips64el-unknown-linux-muslabi64
index f3134cf..579a90d 100644
--- a/docker/Dockerfile.mips64el-unknown-linux-muslabi64
+++ b/docker/Dockerfile.mips64el-unknown-linux-muslabi64
@@ -21,7 +21,7 @@ ENV CROSS_MUSL_SYSROOT=/usr/local/mips64el-linux-muslsf
 COPY musl-symlink.sh /
 RUN /musl-symlink.sh $CROSS_MUSL_SYSROOT mips64el-sf
 
-COPY qemu-runner /
+COPY qemu-runner base-runner.sh /
 
 ENV CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_MUSLABI64_LINKER=mips64el-linux-muslsf-gcc \
     CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_MUSLABI64_RUNNER="/qemu-runner mips64el" \
diff --git a/docker/Dockerfile.mipsel-unknown-linux-gnu b/docker/Dockerfile.mipsel-unknown-linux-gnu
index fec2bb6..5646106 100644
--- a/docker/Dockerfile.mipsel-unknown-linux-gnu
+++ b/docker/Dockerfile.mipsel-unknown-linux-gnu
@@ -28,7 +28,7 @@ RUN /dropbear.sh
 COPY linux-image.sh /
 RUN /linux-image.sh mipsel
 
-COPY linux-runner /
+COPY linux-runner base-runner.sh /
 
 ENV CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_LINKER=mipsel-linux-gnu-gcc \
     CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_RUNNER="/linux-runner mipsel" \
diff --git a/docker/Dockerfile.mipsel-unknown-linux-musl b/docker/Dockerfile.mipsel-unknown-linux-musl
index 2590c23..1769e78 100644
--- a/docker/Dockerfile.mipsel-unknown-linux-musl
+++ b/docker/Dockerfile.mipsel-unknown-linux-musl
@@ -22,7 +22,7 @@ ENV CROSS_MUSL_SYSROOT=/usr/local/mipsel-linux-muslsf
 COPY musl-symlink.sh /
 RUN /musl-symlink.sh $CROSS_MUSL_SYSROOT mipsel-sf
 
-COPY qemu-runner /
+COPY qemu-runner base-runner.sh /
 
 ENV CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_MUSL_LINKER=mipsel-linux-muslsf-gcc \
     CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_MUSL_RUNNER="/qemu-runner mipsel" \
diff --git a/docker/Dockerfile.powerpc-unknown-linux-gnu b/docker/Dockerfile.powerpc-unknown-linux-gnu
index 581cd02..d0a3173 100644
--- a/docker/Dockerfile.powerpc-unknown-linux-gnu
+++ b/docker/Dockerfile.powerpc-unknown-linux-gnu
@@ -28,7 +28,7 @@ RUN /dropbear.sh
 COPY linux-image.sh /
 RUN /linux-image.sh powerpc
 
-COPY linux-runner /
+COPY linux-runner base-runner.sh /
 
 ENV CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_LINKER=powerpc-linux-gnu-gcc \
     CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_RUNNER="/linux-runner powerpc" \
diff --git a/docker/Dockerfile.powerpc64-unknown-linux-gnu b/docker/Dockerfile.powerpc64-unknown-linux-gnu
index 4f74aa5..ea71968 100644
--- a/docker/Dockerfile.powerpc64-unknown-linux-gnu
+++ b/docker/Dockerfile.powerpc64-unknown-linux-gnu
@@ -28,7 +28,7 @@ RUN /dropbear.sh
 COPY linux-image.sh /
 RUN /linux-image.sh powerpc64
 
-COPY linux-runner /
+COPY linux-runner base-runner.sh /
 
 ENV CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_LINKER=powerpc64-linux-gnu-gcc \
     CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_RUNNER="/linux-runner powerpc64" \
diff --git a/docker/Dockerfile.powerpc64le-unknown-linux-gnu b/docker/Dockerfile.powerpc64le-unknown-linux-gnu
index 021a6a4..ab3eb74 100644
--- a/docker/Dockerfile.powerpc64le-unknown-linux-gnu
+++ b/docker/Dockerfile.powerpc64le-unknown-linux-gnu
@@ -28,7 +28,7 @@ RUN /dropbear.sh
 COPY linux-image.sh /
 RUN /linux-image.sh powerpc64le
 
-COPY linux-runner /
+COPY linux-runner base-runner.sh /
 
 ENV CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_LINKER=powerpc64le-linux-gnu-gcc \
     CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_RUNNER="/linux-runner powerpc64le" \
diff --git a/docker/Dockerfile.riscv64gc-unknown-linux-gnu b/docker/Dockerfile.riscv64gc-unknown-linux-gnu
index 3eebe67..cb96eab 100644
--- a/docker/Dockerfile.riscv64gc-unknown-linux-gnu
+++ b/docker/Dockerfile.riscv64gc-unknown-linux-gnu
@@ -4,8 +4,8 @@ ARG DEBIAN_FRONTEND=noninteractive
 COPY common.sh lib.sh /
 RUN /common.sh
 
-COPY cmake.sh /
-RUN /cmake.sh
+# COPY cmake.sh /
+# RUN /cmake.sh
 
 COPY xargo.sh /
 RUN /xargo.sh
@@ -20,15 +20,9 @@ RUN TARGET_ARCH=riscv64 /deny-debian-packages.sh \
     binutils-riscv64-linux-gnu
 
 COPY qemu.sh /
-RUN /qemu.sh riscv64 softmmu
+RUN /qemu.sh riscv64
 
-COPY dropbear.sh /
-RUN /dropbear.sh
-
-COPY linux-image.sh /
-RUN /linux-image.sh riscv64
-
-COPY linux-runner /
+COPY linux-runner base-runner.sh /
 
 ENV CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_LINKER=riscv64-linux-gnu-gcc \
     CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_RUNNER="/linux-runner riscv64" \
diff --git a/docker/Dockerfile.s390x-unknown-linux-gnu b/docker/Dockerfile.s390x-unknown-linux-gnu
index 6799586..8bb2673 100644
--- a/docker/Dockerfile.s390x-unknown-linux-gnu
+++ b/docker/Dockerfile.s390x-unknown-linux-gnu
@@ -28,7 +28,7 @@ RUN /dropbear.sh
 COPY linux-image.sh /
 RUN /linux-image.sh s390x
 
-COPY linux-runner /
+COPY linux-runner base-runner.sh /
 
 ENV CARGO_TARGET_S390X_UNKNOWN_LINUX_GNU_LINKER=s390x-linux-gnu-gcc \
     CARGO_TARGET_S390X_UNKNOWN_LINUX_GNU_RUNNER="/linux-runner s390x" \
diff --git a/docker/Dockerfile.sparc64-unknown-linux-gnu b/docker/Dockerfile.sparc64-unknown-linux-gnu
index 3e99290..15a6ee1 100644
--- a/docker/Dockerfile.sparc64-unknown-linux-gnu
+++ b/docker/Dockerfile.sparc64-unknown-linux-gnu
@@ -28,7 +28,7 @@ RUN /dropbear.sh
 COPY linux-image.sh /
 RUN /linux-image.sh sparc64
 
-COPY linux-runner /
+COPY linux-runner base-runner.sh /
 
 ENV CARGO_TARGET_SPARC64_UNKNOWN_LINUX_GNU_LINKER=sparc64-linux-gnu-gcc \
     CARGO_TARGET_SPARC64_UNKNOWN_LINUX_GNU_RUNNER="/linux-runner sparc64" \
diff --git a/docker/Dockerfile.thumbv7neon-unknown-linux-gnueabihf b/docker/Dockerfile.thumbv7neon-unknown-linux-gnueabihf
index c26b059..d9cfbd6 100644
--- a/docker/Dockerfile.thumbv7neon-unknown-linux-gnueabihf
+++ b/docker/Dockerfile.thumbv7neon-unknown-linux-gnueabihf
@@ -23,11 +23,11 @@ RUN /dropbear.sh
 COPY linux-image.sh /
 RUN /linux-image.sh armv7
 
-COPY linux-runner /
+COPY linux-runner base-runner.sh /
 
 # Export all target binutils just in case required.
 ENV CARGO_TARGET_THUMBV7NEON_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \
-    CARGO_TARGET_THUMBV7NEON_UNKNOWN_LINUX_GNUEABIHF_RUNNER="/linux-runner armv7" \
+    CARGO_TARGET_THUMBV7NEON_UNKNOWN_LINUX_GNUEABIHF_RUNNER="/linux-runner armv7hf" \
     AR_thumbv7neon_unknown_linux_gnueabihf=arm-linux-gnueabihf-ar \
     AS_thumbv7neon_unknown_linux_gnueabihf=arm-linux-gnueabihf-as \
     CC_thumbv7neon_unknown_linux_gnueabihf=arm-linux-gnueabihf-gcc \
diff --git a/docker/Dockerfile.x86_64-unknown-linux-gnu b/docker/Dockerfile.x86_64-unknown-linux-gnu
index 0dc7340..5e1105e 100644
--- a/docker/Dockerfile.x86_64-unknown-linux-gnu
+++ b/docker/Dockerfile.x86_64-unknown-linux-gnu
@@ -19,6 +19,6 @@ RUN /dropbear.sh
 COPY linux-image.sh /
 RUN /linux-image.sh x86_64
 
-COPY linux-runner /
+COPY linux-runner base-runner.sh /
 
 ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="/linux-runner x86_64"
diff --git a/docker/Dockerfile.x86_64-unknown-linux-gnu.centos b/docker/Dockerfile.x86_64-unknown-linux-gnu.centos
index e16192b..52a8e38 100644
--- a/docker/Dockerfile.x86_64-unknown-linux-gnu.centos
+++ b/docker/Dockerfile.x86_64-unknown-linux-gnu.centos
@@ -24,6 +24,6 @@ RUN /dropbear.sh
 
 COPY --from=0 /qemu /qemu
 
-COPY linux-runner /
+COPY linux-runner base-runner.sh /
 
 ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="/linux-runner x86_64"
diff --git a/docker/Dockerfile.x86_64-unknown-linux-musl b/docker/Dockerfile.x86_64-unknown-linux-musl
index 1e99b62..2712be9 100644
--- a/docker/Dockerfile.x86_64-unknown-linux-musl
+++ b/docker/Dockerfile.x86_64-unknown-linux-musl
@@ -20,7 +20,7 @@ ENV CROSS_MUSL_SYSROOT=/usr/local/x86_64-linux-musl
 COPY musl-symlink.sh /
 RUN /musl-symlink.sh $CROSS_MUSL_SYSROOT x86_64
 
-COPY qemu-runner /
+COPY qemu-runner base-runner.sh /
 
 ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_LINKER=x86_64-linux-musl-gcc \
     CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_RUNNER="/qemu-runner x86_64" \
diff --git a/docker/Dockerfile.zig b/docker/Dockerfile.zig
deleted file mode 100644
index ebca274..0000000
--- a/docker/Dockerfile.zig
+++ /dev/null
@@ -1,22 +0,0 @@
-FROM ubuntu:20.04
-ARG DEBIAN_FRONTEND=noninteractive
-
-COPY common.sh lib.sh /
-RUN /common.sh
-
-COPY cmake.sh /
-RUN /cmake.sh
-
-COPY xargo.sh /
-RUN /xargo.sh
-
-ARG TARGETPLATFORM
-COPY zig.sh /
-RUN /zig.sh $TARGETPLATFORM
-
-# we don't export `BINDGEN_EXTRA_CLANG_ARGS`, `QEMU_LD_PREFIX`, or
-# `PKG_CONFIG_PATH` since zig doesn't have a traditional sysroot structure,
-# and we're not using standard, shared packages. none of the packages
-# have runners either, since they do not ship with the required
-# dynamic linker (`ld-linux-${arch}.so`).
-ENV PATH=$PATH:/opt/zig
diff --git a/docker/base-runner.sh b/docker/base-runner.sh
new file mode 100644
index 0000000..5bf5236
--- /dev/null
+++ b/docker/base-runner.sh
@@ -0,0 +1,142 @@
+#!/usr/bin/env bash
+
+host_architecture() {
+    # there's numerous compatibility modes, so we want
+    # to ensure that these are valid. we also want to
+    # use dpkg if it's available since it gives hard-float
+    # information on compatible architectures
+    local host
+    local arch
+    if dpkg >/dev/null 2>&1; then
+        host=$(dpkg --print-architecture)
+        arch="${host}"
+    else
+        host=$(uname -m)
+        arch="${host}"
+
+        case "${arch}" in
+            aarch64|armv8b|armv8l)
+                arch=arm64
+                ;;
+            aarch64_be)
+                arch=arm64be
+                ;;
+            arm*)
+                arch=unknown
+                ;;
+            ppc)
+                arch=powerpc
+                ;;
+            ppc64le)
+                arch=ppc64el
+                ;;
+            s390)
+                arch=s390x
+                ;;
+            i?86)
+                arch=i386
+                ;;
+            x64|x86_64)
+                arch=amd64
+                ;;
+            *)
+                ;;
+        esac
+    fi
+
+    echo "${arch}"
+}
+
+normalize_arch() {
+    local arch="${1}"
+    local debian
+
+    debian="${arch}"
+    case "${arch}" in
+        aarch64)
+            debian=arm64
+            ;;
+        x86_64)
+            debian=amd64
+            ;;
+        arm)
+            debian=armel
+            ;;
+        armv7)
+            debian=arm
+            ;;
+        armv7hf)
+            debian=armhf
+            ;;
+        i?86)
+            debian=i386
+            ;;
+        powerpc64)
+            debian=ppc64
+            ;;
+        powerpc64le)
+            debian=ppc64el
+            ;;
+        riscv64*)
+            debian=riscv64
+            ;;
+        *)
+            ;;
+    esac
+
+    echo "${debian}"
+}
+
+is_native_binary() {
+    # determines if the binary can run natively on the host
+    local arch="${1}"
+    local host
+    local target
+    host=$(host_architecture)
+    target=$(normalize_arch "${arch}")
+
+    # FIXME: this is not comprehensive. add more compatible architectures.
+    case "${host}" in
+        amd64)
+            if [[ "${target}" == i386 ]] || [[ "${target}" == amd64 ]]; then
+                return 0
+            fi
+            ;;
+        *)
+            if [[ "${host}" == "${target}" ]]; then
+                return 0
+            fi
+            ;;
+    esac
+
+    return 1
+}
+
+qemu_arch() {
+    # select qemu arch
+    local arch="${1}"
+    local qarch="${arch}"
+    case "${arch}" in
+        arm|armhf|armv7|armv7hf)
+            qarch="arm"
+            ;;
+        i?86)
+            qarch="i386"
+            ;;
+        powerpc)
+            qarch="ppc"
+            ;;
+        powerpc64)
+            qarch="ppc64"
+            ;;
+        powerpc64le)
+            if [ "${CROSS_RUNNER}" = "qemu-user" ]; then
+                qarch="ppc64le"
+            else
+                qarch="ppc64"
+            fi
+            ;;
+    esac
+
+    echo "${qarch}"
+}
diff --git a/docker/dragonfly.sh b/docker/dragonfly.sh
index 241ed80..fb040f1 100755
--- a/docker/dragonfly.sh
+++ b/docker/dragonfly.sh
@@ -11,7 +11,8 @@ main() {
     local binutils=2.32 \
           dragonfly=6.0.1_REL \
           gcc=10.3.0 \
-          target=x86_64-unknown-dragonfly
+          target=x86_64-unknown-dragonfly \
+          url="https://mirror-master.dragonflybsd.org/iso-images"
     if [[ $# != "0" ]]; then
         nproc="${1}"
     fi
@@ -32,10 +33,10 @@ main() {
     pushd "${td}"
     mkdir "${td}"/{binutils,gcc}{,-build} "${td}/dragonfly"
 
-    download_binutils "${binutils}" "bz2"
+    curl --retry 3 -sSfL "https://ftp.gnu.org/gnu/binutils/binutils-${binutils}.tar.bz2" -O
     tar -C "${td}/binutils" --strip-components=1 -xjf "binutils-${binutils}.tar.bz2"
 
-    download_gcc "${gcc}" "gz"
+    curl --retry 3 -sSfL "https://ftp.gnu.org/gnu/gcc/gcc-${gcc}/gcc-${gcc}.tar.gz" -O
     tar -C "${td}/gcc" --strip-components=1 -xf "gcc-${gcc}.tar.gz"
 
     cd gcc
@@ -49,11 +50,7 @@ main() {
 EOF
     cd ..
 
-    local mirrors=(
-        "https://mirror-master.dragonflybsd.org/iso-images"
-        "https://avalon.dragonflybsd.org/iso-images/"
-    )
-    download_mirrors "" "dfly-x86_64-${dragonfly}.iso.bz2" "${mirrors[@]}"
+    curl --retry 3 -sSfL "${url}/dfly-x86_64-${dragonfly}.iso.bz2" -O
     bzcat "dfly-x86_64-${dragonfly}.iso.bz2" | bsdtar xf - -C "${td}/dragonfly" ./usr/include ./usr/lib ./lib
 
     cd binutils-build
diff --git a/docker/dropbear.sh b/docker/dropbear.sh
index ff213a2..097814e 100755
--- a/docker/dropbear.sh
+++ b/docker/dropbear.sh
@@ -8,10 +8,6 @@ set -euo pipefail
 
 main() {
     local version=2022.82
-    local mirrors=(
-        "https://matt.ucc.asn.au/dropbear/releases"
-        "https://mirror.dropbear.nl/mirror"
-    )
 
     install_packages \
         autoconf \
@@ -28,7 +24,7 @@ main() {
 
     pushd "${td}"
 
-    download_mirrors "" "dropbear-${version}.tar.bz2" "${mirrors[@]}"
+    curl --retry 3 -sSfL "https://matt.ucc.asn.au/dropbear/releases/dropbear-${version}.tar.bz2" -O
     tar --strip-components=1 -xjf "dropbear-${version}.tar.bz2"
 
     # Remove some unwanted message
diff --git a/docker/freebsd.sh b/docker/freebsd.sh
index 423e0d0..4ae37ab 100755
--- a/docker/freebsd.sh
+++ b/docker/freebsd.sh
@@ -64,10 +64,10 @@ main() {
 
     mkdir "${td}"/{binutils,gcc}{,-build} "${td}/freebsd"
 
-    download_binutils "${binutils}" "gz"
+    curl --retry 3 -sSfL "https://ftp.gnu.org/gnu/binutils/binutils-${binutils}.tar.gz" -O
     tar -C "${td}/binutils" --strip-components=1 -xf "binutils-${binutils}.tar.gz"
 
-    download_gcc "${gcc}" "gz"
+    curl --retry 3 -sSfL "https://ftp.gnu.org/gnu/gcc/gcc-${gcc}/gcc-${gcc}.tar.gz" -O
     tar -C "${td}/gcc" --strip-components=1 -xf "gcc-${gcc}.tar.gz"
 
     cd gcc
diff --git a/docker/illumos.sh b/docker/illumos.sh
index cf3168f..94884cc 100755
--- a/docker/illumos.sh
+++ b/docker/illumos.sh
@@ -31,23 +31,25 @@ main() {
 
     mkdir "${td}"/{binutils,gcc}{,-build} "${td}/illumos"
 
+    local binutils_file="binutils-${binutils}.tar.xz"
     local binutils_sum="16328a906e55a3c633854beec8e9e255a639b366436470b4f6245eb0d2fde942"
-    download_binutils "${binutils}" "xz"
-    real_sum=$(sha256sum "binutils-${binutils}.tar.xz" | cut -d ' ' -f 1)
+    curl --retry 3 -sSfL "https://ftp.gnu.org/gnu/binutils/${binutils_file}" -O
+    real_sum=$(sha256sum "${binutils_file}" | cut -d ' ' -f 1)
     if [[ "${binutils_sum}" != "${real_sum}" ]]; then
         echo "Error: invalid hash for binutils." >&2
         exit 1
     fi
-    tar -C "${td}/binutils" --strip-components=1 -xJf "binutils-${binutils}.tar.xz"
+    tar -C "${td}/binutils" --strip-components=1 -xJf "${binutils_file}"
 
+    local gcc_file="gcc-${gcc}.tar.xz"
     local gcc_sum="e30a6e52d10e1f27ed55104ad233c30bd1e99cfb5ff98ab022dc941edd1b2dd4"
-    download_gcc "${gcc}" "xz"
-    real_sum=$(sha256sum "gcc-${gcc}.tar.xz" | cut -d ' ' -f 1)
+    curl --retry 3 -sSfL "https://ftp.gnu.org/gnu/gcc/gcc-${gcc}/${gcc_file}" -O
+    real_sum=$(sha256sum "${gcc_file}" | cut -d ' ' -f 1)
     if [[ "${gcc_sum}" != "${real_sum}" ]]; then
         echo "Error: invalid hash for gcc." >&2
         exit 1
     fi
-    tar -C "${td}/gcc" --strip-components=1 -xJf "gcc-${gcc}.tar.xz"
+    tar -C "${td}/gcc" --strip-components=1 -xJf "${gcc_file}"
 
     pushd gcc
     sed -i -e 's/ftp:/https:/g' ./contrib/download_prerequisites
diff --git a/docker/lib.sh b/docker/lib.sh
index 412500b..0d299b8 100644
--- a/docker/lib.sh
+++ b/docker/lib.sh
@@ -1,6 +1,3 @@
-#!/usr/bin/env bash
-# shellcheck disable=SC2294
-
 purge_list=()
 
 install_packages() {
@@ -46,43 +43,3 @@ if_ubuntu() {
         eval "${@}"
     fi
 }
-
-GNU_MIRRORS=(
-    "https://ftp.gnu.org/gnu/"
-    "https://ftpmirror.gnu.org/"
-)
-
-download_mirrors() {
-    local relpath="${1}"
-    shift
-    local filename="${1}"
-    shift
-
-    for mirror in "${@}"; do
-        if curl --retry 3 -sSfL "${mirror}/${relpath}/${filename}" -O; then
-            break
-        fi
-    done
-    if [[ ! -f "${filename}" ]]; then
-        echo "Unable to download ${filename}" >&2
-        exit 1
-    fi
-}
-
-download_binutils() {
-    local mirror
-    local version="${1}"
-    local ext="${2}"
-    local filename="binutils-${version}.tar.${ext}"
-
-    download_mirrors "binutils" "${filename}" "${GNU_MIRRORS[@]}"
-}
-
-download_gcc() {
-    local mirror
-    local version="${1}"
-    local ext="${2}"
-    local filename="gcc-${version}.tar.${ext}"
-
-    download_mirrors "gcc/gcc-${version}" "${filename}" "${GNU_MIRRORS[@]}"
-}
diff --git a/docker/linux-image.sh b/docker/linux-image.sh
index 976a43a..f445132 100755
--- a/docker/linux-image.sh
+++ b/docker/linux-image.sh
@@ -57,7 +57,7 @@ max_kernel_version() {
 main() {
     # arch in the rust target
     local arch="${1}" \
-          kversion=5.10.0-16
+          kversion=5.10.0-8
 
     local debsource="deb http://http.debian.net/debian/ bullseye main"
     debsource="${debsource}\ndeb http://security.debian.org/ bullseye-security main"
@@ -134,12 +134,6 @@ main() {
             kernel="5.*-powerpc64le"
             deps=(libcrypt1:"${arch}")
             ;;
-        riscv64)
-            kernel="5.*-riscv64"
-            debsource="deb http://ftp.ports.debian.org/debian-ports unstable main"
-            debsource="${debsource}\ndeb http://ftp.ports.debian.org/debian-ports unreleased main"
-            deps=(libcrypt1:"${arch}")
-            ;;
         s390x)
             arch=s390x
             kernel="5.*-s390x"
@@ -195,9 +189,9 @@ main() {
     dpkg --add-architecture "${arch}" || echo "foreign-architecture ${arch}" > /etc/dpkg/dpkg.cfg.d/multiarch
 
     # Add Debian keys.
-    curl --retry 3 -sSfL 'https://ftp-master.debian.org/keys/archive-key-{7.0,8,9,10,11}.asc' -O
-    curl --retry 3 -sSfL 'https://ftp-master.debian.org/keys/archive-key-{8,9,10,11}-security.asc' -O
-    curl --retry 3 -sSfL 'https://ftp-master.debian.org/keys/release-{7,8,9,10,11}.asc' -O
+    curl --retry 3 -sSfL 'https://ftp-master.debian.org/keys/archive-key-{7.0,8,9,10}.asc' -O
+    curl --retry 3 -sSfL 'https://ftp-master.debian.org/keys/archive-key-{8,9,10}-security.asc' -O
+    curl --retry 3 -sSfL 'https://ftp-master.debian.org/keys/release-{7,8,9,10}.asc' -O
     curl --retry 3 -sSfL 'https://www.ports.debian.org/archive_{2020,2021,2022}.key' -O
 
     for key in *.asc *.key; do
diff --git a/docker/linux-runner b/docker/linux-runner
index 380e0e7..4cab72d 100755
--- a/docker/linux-runner
+++ b/docker/linux-runner
@@ -2,6 +2,9 @@
 
 set -e
 
+# shellcheck disable=SC1091
+. /base-runner.sh
+
 LOG=/tmp/qemu.log
 LOCK=/tmp/qemu.lock
 
@@ -14,37 +17,14 @@ arch="${1}"
 shift
 
 if [ "${CROSS_RUNNER}" = "" ]; then
-    if [[ "${arch}" == i?86 ]] || [[ "${arch}" == x86_64 ]]; then
+    if is_native_binary "${arch}"; then
         CROSS_RUNNER=native
     else
         CROSS_RUNNER=qemu-user
     fi
 fi
 
-# select qemu arch
-qarch="${arch}"
-case "${arch}" in
-    armv7)
-        qarch="arm"
-        ;;
-    i686)
-        qarch="i386"
-        ;;
-    powerpc)
-        qarch="ppc"
-        ;;
-    powerpc64)
-        qarch="ppc64"
-        ;;
-    powerpc64le)
-        if [ "${CROSS_RUNNER}" = "qemu-user" ]; then
-            qarch="ppc64le"
-        else
-            qarch="ppc64"
-        fi
-        ;;
-esac
-
+qarch=$(qemu_arch "${arch}")
 case "${CROSS_RUNNER}" in
     native)
         exec "${@}"
@@ -74,7 +54,7 @@ case "${arch}" in
         n=$(( n > 8 ? 8 : n ))
         opt="-machine virt -cpu cortex-a57"
         ;;
-    armv7)
+    armv7hf)
         opt="-machine virt"
         driver9p="virtio-9p-device"
         drivernet="virtio-net-device"
@@ -98,9 +78,6 @@ case "${arch}" in
         opt="-append console=ttyPZ0"
         n=1
         ;;
-    riscv64)
-        opt="-machine virt"
-        ;;
     powerpc64|powerpc64le)
         opt="-append console=hvc0 --nodefaults -serial stdio"
         ;;
@@ -143,16 +120,12 @@ esac
     else
         ${QEMU_CMD} >> "${LOG}" 2>&1 &
     fi
-    qemu_pid=$!
 
     # wait for dropbear
     for _ in $(seq 240); do
         if grep -q "Not backgrounding" "${LOG}"; then
             READY=1
             break
-        elif ! (ps -p "${qemu_pid}" >/dev/null 2>&1); then
-            # qemu command failed and exited early
-            exit 1
         fi
         sleep 0.5s
     done
diff --git a/docker/mips64-linux-muslabi64-gcc.sh b/docker/mips64-linux-muslabi64-gcc.sh
deleted file mode 100755
index a26afa9..0000000
--- a/docker/mips64-linux-muslabi64-gcc.sh
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/bash
-
-# this fixes an issue of missing symbols from the command lines
-# these soft-float routines are required even for hard-float targets.
-#   (strtod.lo): undefined reference to symbol '__trunctfsf2@@GCC_3.0'
-
-set -x
-set -euo pipefail
-
-main() {
-    if [[ $# -gt 0 ]]; then
-        exec mips64-linux-musl-gcc "${@}" -lgcc -static-libgcc
-    else
-        exec mips64-linux-musl-gcc "${@}"
-    fi
-}
-
-main "${@}"
diff --git a/docker/netbsd.sh b/docker/netbsd.sh
index 0b9cac5..8b93018 100755
--- a/docker/netbsd.sh
+++ b/docker/netbsd.sh
@@ -26,10 +26,10 @@ main() {
 
     mkdir "${td}"/{binutils,gcc}{,-build} "${td}/netbsd"
 
-    download_binutils "${binutils}" "bz2"
+    curl --retry 3 -sSfL "https://ftp.gnu.org/gnu/binutils/binutils-${binutils}.tar.bz2" -O
     tar -C "${td}/binutils" --strip-components=1 -xjf "binutils-${binutils}.tar.bz2"
 
-    download_gcc "${gcc}" "xz"
+    curl --retry 3 -sSfL "https://ftp.gnu.org/gnu/gcc/gcc-${gcc}/gcc-${gcc}.tar.xz" -O
     tar -C "${td}/gcc" --strip-components=1 -xJf "gcc-${gcc}.tar.xz"
 
     pushd "${td}"
@@ -52,14 +52,10 @@ main() {
     done
     popd
 
-    local mirrors=(
-        "ftp://ftp.netbsd.org"
-        "https://cdn.NetBSD.org"
-    )
-    download_mirrors "pub/NetBSD/NetBSD-9.2/amd64/binary/sets" "base.tar.xz" "${mirrors[@]}"
+    curl --retry 3 -sSfL ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-9.2/amd64/binary/sets/base.tar.xz -O
     tar -C "${td}/netbsd" -xJf base.tar.xz ./usr/include ./usr/lib ./lib
 
-    download_mirrors "pub/NetBSD/NetBSD-9.2/amd64/binary/sets" "comp.tar.xz" "${mirrors[@]}"
+    curl --retry 3 -sSfL ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-9.2/amd64/binary/sets/comp.tar.xz -O
     tar -C "${td}/netbsd" -xJf comp.tar.xz ./usr/include ./usr/lib
 
     pushd binutils-build
diff --git a/docker/qemu-runner b/docker/qemu-runner
index dd89705..6987632 100755
--- a/docker/qemu-runner
+++ b/docker/qemu-runner
@@ -5,6 +5,9 @@
 
 set -e
 
+# shellcheck disable=SC1091
+. /base-runner.sh
+
 if [ -n "${CROSS_DEBUG}" ]; then
     set -x
 fi
@@ -14,37 +17,14 @@ arch="${1}"
 shift
 
 if [ "${CROSS_RUNNER}" = "" ]; then
-    if [[ "${arch}" == i?86 ]] || [[ "${arch}" == x86_64 ]]; then
+    if is_native_binary "${arch}"; then
         CROSS_RUNNER=native
     else
         CROSS_RUNNER=qemu-user
     fi
 fi
 
-# select qemu arch
-qarch="${arch}"
-case "${arch}" in
-    armv7)
-        qarch="arm"
-        ;;
-    i?86)
-        qarch="i386"
-        ;;
-    powerpc)
-        qarch="ppc"
-        ;;
-    powerpc64)
-        qarch="ppc64"
-        ;;
-    powerpc64le)
-        if [ "${CROSS_RUNNER}" = "qemu-user" ]; then
-            qarch="ppc64le"
-        else
-            qarch="ppc64"
-        fi
-        ;;
-esac
-
+qarch=$(qemu_arch "${arch}")
 case "${CROSS_RUNNER}" in
     native)
         exec "${@}"
diff --git a/docker/qemu.sh b/docker/qemu.sh
index 5039cd9..75626c5 100755
--- a/docker/qemu.sh
+++ b/docker/qemu.sh
@@ -171,11 +171,11 @@ main() {
         libselinux1-dev \
         zlib1g-dev
 
-    # if we have python3.6+, we can install qemu 7.0.0, which needs ninja-build
+    # if we have python3.6+, we can install qemu 6.1.0, which needs ninja-build
     # ubuntu 16.04 only provides python3.5, so remove when we have a newer qemu.
     is_ge_python36=$(python3 -c "import sys; print(int(sys.version_info >= (3, 6)))")
     if [[ "${is_ge_python36}" == "1" ]]; then
-        if_ubuntu version=7.0.0
+        if_ubuntu version=6.1.0
         if_ubuntu install_packages ninja-build
     fi
 
diff --git a/docker/solaris.sh b/docker/solaris.sh
index 5c485f6..bb59a2e 100755
--- a/docker/solaris.sh
+++ b/docker/solaris.sh
@@ -31,10 +31,10 @@ main() {
 
     mkdir "${td}"/{binutils,gcc}{,-build} "${td}/solaris"
 
-    download_binutils "${binutils}" "xz"
+    curl --retry 3 -sSfL "https://ftp.gnu.org/gnu/binutils/binutils-${binutils}.tar.xz" -O
     tar -C "${td}/binutils" --strip-components=1 -xJf "binutils-${binutils}.tar.xz"
 
-    download_gcc "${gcc}" "xz"
+    curl --retry 3 -sSfL "https://ftp.gnu.org/gnu/gcc/gcc-${gcc}/gcc-${gcc}.tar.xz" -O
     tar -C "${td}/gcc" --strip-components=1 -xJf "gcc-${gcc}.tar.xz"
 
     cd gcc
diff --git a/docker/wine.sh b/docker/wine.sh
index 2779b22..cda79f3 100755
--- a/docker/wine.sh
+++ b/docker/wine.sh
@@ -15,11 +15,11 @@ main() {
     # hardcode version, since we might want to avoid a version later.
     wget -nc https://dl.winehq.org/wine-builds/winehq.key
     mv winehq.key /usr/share/keyrings/winehq-archive.key
-    wget -nc https://dl.winehq.org/wine-builds/ubuntu/dists/focal/winehq-focal.sources
-    mv winehq-focal.sources /etc/apt/sources.list.d/
+    wget -nc https://dl.winehq.org/wine-builds/ubuntu/dists/bionic/winehq-bionic.sources
+    mv winehq-bionic.sources /etc/apt/sources.list.d/
     apt-get update
     apt install --no-install-recommends --assume-yes \
-        "winehq-stable=7.0.0.0~focal-1"
+        "winehq-stable=7.0.0.0~bionic-1"
 
     purge_packages
 }
diff --git a/docker/zig.sh b/docker/zig.sh
deleted file mode 100755
index d41ee37..0000000
--- a/docker/zig.sh
+++ /dev/null
@@ -1,197 +0,0 @@
-#!/usr/bin/env bash
-
-set -x
-set -eo pipefail
-
-# shellcheck disable=SC1091
-. lib.sh
-
-main() {
-    local platform="${1}"
-    install_packages ca-certificates curl xz-utils
-
-    install_zig "${platform}"
-    install_zigbuild "${platform}"
-
-    purge_packages
-    rm "${0}"
-}
-
-install_zig() {
-    local platform="${1}"
-    local version="0.9.1"
-    local dst="/opt/zig"
-    local arch=
-    local os=
-    local triple=
-
-    case "${platform}" in
-        'linux/386')
-            arch="i386"
-            os="linux"
-            ;;
-        'linux/amd64')
-            arch="x86_64"
-            os="linux"
-            ;;
-        'linux/arm64')
-            arch="aarch64"
-            os="linux"
-            ;;
-        'linux/riscv64')
-            arch="riscv64"
-            os="linux"
-            ;;
-        'linux/ppc64le')
-            triple="powerpc64le-linux-gnu"
-            ;;
-        'linux/s390x')
-            triple="s390x-linux-gnu"
-            ;;
-        'darwin/amd64')
-            arch="x86_64"
-            os="macos"
-            ;;
-        'darwin/arm64')
-            arch="aarch64"
-            os="macos"
-            ;;
-        # NOTE: explicitly don't support linux/arm/v6
-        *)
-            echo "Unsupported target platform '${platform}'" 1>&2
-            exit 1
-            ;;
-    esac
-
-    if [[ -n "${arch}" ]]; then
-        install_zig_tarball "${arch}" "${os}" "${version}" "${dst}"
-    else
-        install_zig_source "${triple}" "${version}" "${dst}"
-    fi
-}
-
-install_zig_tarball() {
-    local arch="${1}"
-    local os="${2}"
-    local version="${3}"
-    local dst="${4}"
-    local filename="zig-${os}-${arch}-${version}.tar.xz"
-
-    local td
-    td="$(mktemp -d)"
-
-    pushd "${td}"
-
-    curl --retry 3 -sSfL "https://ziglang.org/download/${version}/${filename}" -O
-    mkdir -p "${dst}"
-    tar --strip-components=1 -xJf "${filename}" --directory "${dst}"
-
-    popd
-
-    rm -rf "${td}"
-}
-
-install_zig_source() {
-    local triple="${1}"
-    local version="${2}"
-    local dst="${3}"
-    local filename="zig-bootstrap-${version}.tar.xz"
-
-    local td
-    td="$(mktemp -d)"
-
-    pushd "${td}"
-
-    curl --retry 3 -sSfL "https://ziglang.org/download/${version}/${filename}" -O
-    mkdir zig
-    tar --strip-components=1 -xJf "${filename}" --directory zig
-
-    pushd zig
-    install_packages python3 make g++
-    ./build -j5 "${triple}" native
-    mv "out/zig-${triple}-native" /opt/zig
-
-    popd
-    popd
-
-    rm -rf "${td}"
-}
-
-install_zigbuild() {
-    local platform="${1}"
-    local version=0.11.0
-    local dst="/usr/local"
-    local triple=
-
-    # we don't know if `linux/arm/v7` is hard-float,
-    # and we don't know the the zigbuild `apple-darwin`
-    # target doesn't manually specify the architecture.
-    case "${platform}" in
-        'linux/386')
-            triple="i686-unknown-linux-musl"
-            ;;
-        'linux/amd64')
-            triple="x86_64-unknown-linux-musl"
-            ;;
-        'linux/arm64')
-            triple="aarch64-unknown-linux-musl"
-            ;;
-        *)
-            ;;
-    esac
-
-    if [[ -n "${triple}" ]]; then
-        install_zigbuild_tarball "${triple}" "${version}" "${dst}"
-    else
-        install_zigbuild_source "${version}" "${dst}"
-    fi
-}
-
-install_zigbuild_tarball() {
-    local triple="${1}"
-    local version="${2}"
-    local dst="${3}"
-    local repo="https://github.com/messense/cargo-zigbuild"
-    local filename="cargo-zigbuild-v${version}.${triple}.tar.gz"
-
-    local td
-    td="$(mktemp -d)"
-
-    pushd "${td}"
-
-    curl --retry 3 -sSfL "${repo}/releases/download/v${version}/${filename}" -O
-    mkdir -p "${dst}/bin"
-    tar -xzf "${filename}" --directory "${dst}/bin"
-
-    popd
-
-    rm -rf "${td}"
-}
-
-install_zigbuild_source() {
-    local version="${1}"
-    local dst="${2}"
-
-    local td
-    td="$(mktemp -d)"
-
-    pushd "${td}"
-
-    export RUSTUP_HOME="${td}/rustup"
-    export CARGO_HOME="${td}/cargo"
-
-    curl --retry 3 -sSfL https://sh.rustup.rs -o rustup-init.sh
-    sh rustup-init.sh -y --no-modify-path --profile minimal
-
-    PATH="${CARGO_HOME}/bin:${PATH}" \
-        cargo install cargo-zigbuild \
-        --version "${version}" \
-        --root "${dst}" \
-        --locked
-
-    popd
-
-    rm -rf "${td}"
-}
-
-main "${@}"
diff --git a/docs/cross_toml.md b/docs/cross_toml.md
index 98b935e..87020a7 100644
--- a/docs/cross_toml.md
+++ b/docs/cross_toml.md
@@ -33,7 +33,6 @@ The `target` key allows you to specify parameters for specific compilation targe
 [target.aarch64-unknown-linux-gnu]
 xargo = false
 build-std = false
-zig = "2.17"
 image = "test-image"
 pre-build = ["apt-get update"] # can also be the path to a file to run
 runner = "custom-runner"
@@ -93,26 +92,3 @@ also supports
 [target.x86_64-unknown-linux-gnu]
 dockerfile = "./Dockerfile"
 ```
-
-# `target.TARGET.zig`
-
-```toml
-[target.x86_64-unknown-linux-gnu.zig]
-enable = true       # enable use of the zig image
-version = "2.17"    # glibc version to use
-image = "zig:local" # custom zig image to use
-```
-
-also supports
-
-```toml
-[target.x86_64-unknown-linux-gnu]
-zig = true
-```
-
-or
-
-```toml
-[target.x86_64-unknown-linux-gnu]
-zig = "2.17"
-```
diff --git a/src/bin/commands/containers.rs b/src/bin/commands/containers.rs
index fad12db..973609d 100644
--- a/src/bin/commands/containers.rs
+++ b/src/bin/commands/containers.rs
@@ -416,11 +416,11 @@ pub fn create_persistent_volume(
     // stop the container if it's already running
     let state = docker::remote::container_state(engine, &container, msg_info)?;
     if !state.is_stopped() {
-        msg_info.warn(format_args!("container {container} was running."))?;
+        msg_info.warn("container {container} was running.")?;
         docker::remote::container_stop_default(engine, &container, msg_info)?;
     }
     if state.exists() {
-        msg_info.warn(format_args!("container {container} was exited."))?;
+        msg_info.warn("container {container} was exited.")?;
         docker::remote::container_rm(engine, &container, msg_info)?;
     }
 
diff --git a/src/build.rs b/src/build.rs
index bf311ce..fa5c998 100644
--- a/src/build.rs
+++ b/src/build.rs
@@ -23,11 +23,6 @@ fn main() {
         .unwrap()
         .write_all(commit_info().as_bytes())
         .unwrap();
-
-    if env::var("CROSS_SANDBOXED").is_ok() {
-        println!("cargo:rustc-cfg=cross_sandboxed");
-    }
-    println!("cargo:rerun-if-env-changed=CROSS_SANDBOXED");
 }
 
 fn commit_info() -> String {
diff --git a/src/cli.rs b/src/cli.rs
index f5cf598..bc7743f 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -3,7 +3,7 @@ use std::path::{Path, PathBuf};
 
 use crate::cargo::Subcommand;
 use crate::errors::Result;
-use crate::file::{absolute_path, PathExt};
+use crate::file::PathExt;
 use crate::rustc::TargetList;
 use crate::shell::{self, MessageInfo};
 use crate::Target;
@@ -23,6 +23,15 @@ pub struct Args {
     pub color: Option<String>,
 }
 
+// Fix for issue #581. target_dir must be absolute.
+fn absolute_path(path: PathBuf) -> Result<PathBuf> {
+    Ok(if path.is_absolute() {
+        path
+    } else {
+        env::current_dir()?.join(path)
+    })
+}
+
 pub fn is_subcommand_list(stdout: &str) -> bool {
     stdout.starts_with("Installed Commands:")
 }
@@ -142,8 +151,22 @@ fn str_to_owned(arg: &str) -> Result<String> {
     Ok(arg.to_owned())
 }
 
+#[allow(clippy::needless_return)]
 fn store_manifest_path(path: String) -> Result<String> {
-    Path::new(&path).as_posix_relative()
+    let p = Path::new(&path);
+    if p.is_absolute() {
+        #[cfg(target_os = "windows")]
+        {
+            return p.as_wslpath();
+        }
+        #[cfg(not(target_os = "windows"))]
+        {
+            use crate::file::ToUtf8;
+            return p.to_utf8().map(ToOwned::to_owned);
+        }
+    } else {
+        p.as_posix()
+    }
 }
 
 fn store_target_dir(_: String) -> Result<String> {
diff --git a/src/config.rs b/src/config.rs
index 9933e6c..9cc4d13 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -67,46 +67,29 @@ impl Environment {
         self.get_values_for("BUILD_STD", target, bool_from_envvar)
     }
 
-    fn zig(&self, target: &Target) -> (Option<bool>, Option<bool>) {
-        self.get_values_for("ZIG", target, bool_from_envvar)
-    }
-
-    fn zig_version(&self, target: &Target) -> (Option<String>, Option<String>) {
-        self.get_values_for("ZIG_VERSION", target, ToOwned::to_owned)
-    }
-
-    fn zig_image(&self, target: &Target) -> Result<(Option<PossibleImage>, Option<PossibleImage>)> {
-        let get_build = |env: &Environment, var: &str| env.get_build_var(var);
-        let get_target = |env: &Environment, var: &str| env.get_target_var(target, var);
-        let env_build = get_possible_image(
-            self,
-            "ZIG_IMAGE",
-            "ZIG_IMAGE_TOOLCHAIN",
-            get_build,
-            get_build,
-        )?;
-        let env_target = get_possible_image(
-            self,
-            "ZIG_IMAGE",
-            "ZIG_IMAGE_TOOLCHAIN",
-            get_target,
-            get_target,
-        )?;
-
-        Ok((env_build, env_target))
-    }
-
     fn image(&self, target: &Target) -> Result<Option<PossibleImage>> {
-        let get_target = |env: &Environment, var: &str| env.get_target_var(target, var);
-        get_possible_image(self, "IMAGE", "IMAGE_TOOLCHAIN", get_target, get_target)
+        self.get_target_var(target, "IMAGE")
+            .map(Into::into)
+            .map(|mut i: PossibleImage| {
+                if let Some(toolchain) = self.get_target_var(target, "IMAGE_TOOLCHAIN") {
+                    i.toolchain = toolchain
+                        .split(',')
+                        .map(|t| ImagePlatform::from_target(t.trim().into()))
+                        .collect::<Result<Vec<_>>>()?;
+                    Ok(i)
+                } else {
+                    Ok(i)
+                }
+            })
+            .transpose()
     }
 
     fn dockerfile(&self, target: &Target) -> (Option<String>, Option<String>) {
-        self.get_values_for("DOCKERFILE", target, ToOwned::to_owned)
+        self.get_values_for("DOCKERFILE", target, |s| s.to_owned())
     }
 
     fn dockerfile_context(&self, target: &Target) -> (Option<String>, Option<String>) {
-        self.get_values_for("DOCKERFILE_CONTEXT", target, ToOwned::to_owned)
+        self.get_values_for("DOCKERFILE_CONTEXT", target, |s| s.to_owned())
     }
 
     fn pre_build(&self, target: &Target) -> (Option<PreBuild>, Option<PreBuild>) {
@@ -159,29 +142,6 @@ impl Environment {
     }
 }
 
-fn get_possible_image(
-    env: &Environment,
-    image_var: &str,
-    toolchain_var: &str,
-    get_image: impl Fn(&Environment, &str) -> Option<String>,
-    get_toolchain: impl Fn(&Environment, &str) -> Option<String>,
-) -> Result<Option<PossibleImage>> {
-    get_image(env, image_var)
-        .map(Into::into)
-        .map(|mut i: PossibleImage| {
-            if let Some(toolchain) = get_toolchain(env, toolchain_var) {
-                i.toolchain = toolchain
-                    .split(',')
-                    .map(|t| ImagePlatform::from_target(t.trim().into()))
-                    .collect::<Result<Vec<_>>>()?;
-                Ok(i)
-            } else {
-                Ok(i)
-            }
-        })
-        .transpose()
-}
-
 fn split_to_cloned_by_ws(string: &str) -> Vec<String> {
     string.split_whitespace().map(String::from).collect()
 }
@@ -222,7 +182,7 @@ impl Config {
                     .replace(|c| c == '-' || c == '_', "")
                     .to_lowercase();
                 if mentioned_target != target && mentioned_target_norm == target_norm {
-                    msg_info.warn(format_args!("a target named \"{mentioned_target}\" is mentioned in the Cross configuration, but the current specified target is \"{target}\"."))?;
+                    msg_info.warn("a target named \"{mentioned_target}\" is mentioned in the Cross configuration, but the current specified target is \"{target}\".")?;
                     msg_info.status(" > Is the target misspelled in the Cross configuration?")?;
                 }
             }
@@ -309,36 +269,6 @@ impl Config {
         }
     }
 
-    fn get_from_value<T>(
-        &self,
-        target: &Target,
-        env: impl Fn(&Environment, &Target) -> (Option<T>, Option<T>),
-        config: impl Fn(&CrossToml, &Target) -> (Option<T>, Option<T>),
-    ) -> Result<Option<T>> {
-        let (env_build, env_target) = env(&self.env, target);
-
-        if let Some(env_target) = env_target {
-            return Ok(Some(env_target));
-        }
-
-        let (build, target) = self
-            .toml
-            .as_ref()
-            .map(|t| config(t, target))
-            .unwrap_or_default();
-
-        // FIXME: let expression
-        if target.is_none() && env_build.is_some() {
-            return Ok(env_build);
-        }
-
-        if target.is_none() {
-            Ok(build)
-        } else {
-            Ok(target)
-        }
-    }
-
     #[cfg(test)]
     fn new_with(toml: Option<CrossToml>, env: Environment) -> Self {
         Config { toml, env }
@@ -352,19 +282,6 @@ impl Config {
         self.bool_from_config(target, Environment::build_std, CrossToml::build_std)
     }
 
-    pub fn zig(&self, target: &Target) -> Option<bool> {
-        self.bool_from_config(target, Environment::zig, CrossToml::zig)
-    }
-
-    pub fn zig_version(&self, target: &Target) -> Result<Option<String>> {
-        self.get_from_value(target, Environment::zig_version, CrossToml::zig_version)
-    }
-
-    pub fn zig_image(&self, target: &Target) -> Result<Option<PossibleImage>> {
-        let (b, t) = self.env.zig_image(target)?;
-        self.get_from_value(target, |_, _| (b.clone(), t.clone()), CrossToml::zig_image)
-    }
-
     pub fn image(&self, target: &Target) -> Result<Option<PossibleImage>> {
         let env = self.env.image(target)?;
         self.get_from_ref(
@@ -521,36 +438,24 @@ mod tests {
         use super::*;
 
         #[test]
-        pub fn parse_error_in_env() -> Result<()> {
+        pub fn parse_error_in_env() {
             let mut map = std::collections::HashMap::new();
             map.insert("CROSS_BUILD_XARGO", "tru");
             map.insert("CROSS_BUILD_STD", "false");
-            map.insert("CROSS_BUILD_ZIG_IMAGE", "zig:local");
 
             let env = Environment::new(Some(map));
             assert_eq!(env.xargo(&target()), (Some(true), None));
             assert_eq!(env.build_std(&target()), (Some(false), None));
-            assert_eq!(env.zig(&target()), (None, None));
-            assert_eq!(env.zig_version(&target()), (None, None));
-            assert_eq!(env.zig_image(&target())?, (Some("zig:local".into()), None));
-
-            Ok(())
         }
 
         #[test]
-        pub fn build_and_target_set_returns_tuple() -> Result<()> {
+        pub fn build_and_target_set_returns_tuple() {
             let mut map = std::collections::HashMap::new();
             map.insert("CROSS_BUILD_XARGO", "true");
-            map.insert("CROSS_BUILD_ZIG", "true");
-            map.insert("CROSS_BUILD_ZIG_VERSION", "2.17");
             map.insert("CROSS_TARGET_AARCH64_UNKNOWN_LINUX_GNU_XARGO", "false");
 
             let env = Environment::new(Some(map));
             assert_eq!(env.xargo(&target()), (Some(true), Some(false)));
-            assert_eq!(env.zig(&target()), (Some(true), None));
-            assert_eq!(env.zig_version(&target()), (Some("2.17".into()), None));
-
-            Ok(())
         }
 
         #[test]
diff --git a/src/cross_toml.rs b/src/cross_toml.rs
index c4f3c91..858faf8 100644
--- a/src/cross_toml.rs
+++ b/src/cross_toml.rs
@@ -25,8 +25,6 @@ pub struct CrossBuildConfig {
     env: CrossEnvConfig,
     xargo: Option<bool>,
     build_std: Option<bool>,
-    #[serde(default, deserialize_with = "opt_string_bool_or_struct")]
-    zig: Option<CrossZigConfig>,
     default_target: Option<String>,
     #[serde(default, deserialize_with = "opt_string_or_string_vec")]
     pre_build: Option<PreBuild>,
@@ -40,8 +38,6 @@ pub struct CrossBuildConfig {
 pub struct CrossTargetConfig {
     xargo: Option<bool>,
     build_std: Option<bool>,
-    #[serde(default, deserialize_with = "opt_string_bool_or_struct")]
-    zig: Option<CrossZigConfig>,
     #[serde(default, deserialize_with = "opt_string_or_struct")]
     image: Option<PossibleImage>,
     #[serde(default, deserialize_with = "opt_string_or_struct")]
@@ -74,44 +70,6 @@ impl FromStr for CrossTargetDockerfileConfig {
     }
 }
 
-/// Zig configuration
-#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)]
-#[serde(rename_all = "kebab-case")]
-pub struct CrossZigConfig {
-    enable: Option<bool>,
-    version: Option<String>,
-    #[serde(default, deserialize_with = "opt_string_or_struct")]
-    image: Option<PossibleImage>,
-}
-
-impl From<&str> for CrossZigConfig {
-    fn from(s: &str) -> CrossZigConfig {
-        CrossZigConfig {
-            enable: Some(true),
-            version: Some(s.to_owned()),
-            image: None,
-        }
-    }
-}
-
-impl From<bool> for CrossZigConfig {
-    fn from(s: bool) -> CrossZigConfig {
-        CrossZigConfig {
-            enable: Some(s),
-            version: None,
-            image: None,
-        }
-    }
-}
-
-impl FromStr for CrossZigConfig {
-    type Err = std::convert::Infallible;
-
-    fn from_str(s: &str) -> Result<Self, Self::Err> {
-        Ok(s.into())
-    }
-}
-
 /// Cross configuration
 #[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Default)]
 pub struct CrossToml {
@@ -183,7 +141,7 @@ impl CrossToml {
         })?;
 
         if !unused.is_empty() {
-            msg_info.warn(format_args!(
+            msg_info.warn(format!(
                 "found unused key(s) in Cross configuration:\n > {}",
                 unused.clone().into_iter().collect::<Vec<_>>().join(", ")
             ))?;
@@ -317,33 +275,6 @@ impl CrossToml {
         self.get_value(target, |b| b.build_std, |t| t.build_std)
     }
 
-    /// Returns the `{}.zig` or `{}.zig.version` part of `Cross.toml`
-    pub fn zig(&self, target: &Target) -> (Option<bool>, Option<bool>) {
-        self.get_value(
-            target,
-            |b| b.zig.as_ref().and_then(|z| z.enable),
-            |t| t.zig.as_ref().and_then(|z| z.enable),
-        )
-    }
-
-    /// Returns the `{}.zig` or `{}.zig.version` part of `Cross.toml`
-    pub fn zig_version(&self, target: &Target) -> (Option<String>, Option<String>) {
-        self.get_value(
-            target,
-            |b| b.zig.as_ref().and_then(|c| c.version.clone()),
-            |t| t.zig.as_ref().and_then(|c| c.version.clone()),
-        )
-    }
-
-    /// Returns the  `{}.zig.image` part of `Cross.toml`
-    pub fn zig_image(&self, target: &Target) -> (Option<PossibleImage>, Option<PossibleImage>) {
-        self.get_value(
-            target,
-            |b| b.zig.as_ref().and_then(|c| c.image.clone()),
-            |t| t.zig.as_ref().and_then(|c| c.image.clone()),
-        )
-    }
-
     /// Returns the list of environment variables to pass through for `build` and `target`
     pub fn env_passthrough(&self, target: &Target) -> (Option<&[String]>, Option<&[String]>) {
         self.get_ref(
@@ -511,68 +442,6 @@ where
     deserializer.deserialize_any(StringOrStringVec(PhantomData))
 }
 
-fn opt_string_bool_or_struct<'de, T, D>(deserializer: D) -> Result<Option<T>, D::Error>
-where
-    T: Deserialize<'de> + From<bool> + std::str::FromStr<Err = std::convert::Infallible>,
-    D: serde::Deserializer<'de>,
-{
-    use std::{fmt, marker::PhantomData};
-
-    use serde::de::{self, MapAccess, Visitor};
-
-    struct StringBoolOrStruct<T>(PhantomData<fn() -> T>);
-
-    impl<'de, T> Visitor<'de> for StringBoolOrStruct<T>
-    where
-        T: Deserialize<'de> + From<bool> + std::str::FromStr<Err = std::convert::Infallible>,
-    {
-        type Value = Option<T>;
-
-        fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
-            formatter.write_str("string, bool, or map")
-        }
-
-        fn visit_bool<E>(self, value: bool) -> Result<Self::Value, E>
-        where
-            E: de::Error,
-        {
-            Ok(Some(From::from(value)))
-        }
-
-        fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
-        where
-            E: de::Error,
-        {
-            Ok(FromStr::from_str(value).ok())
-        }
-
-        fn visit_map<M>(self, map: M) -> Result<Self::Value, M::Error>
-        where
-            M: MapAccess<'de>,
-        {
-            let t: Result<T, _> =
-                Deserialize::deserialize(de::value::MapAccessDeserializer::new(map));
-            t.map(Some)
-        }
-
-        fn visit_none<E>(self) -> Result<Self::Value, E>
-        where
-            E: de::Error,
-        {
-            Ok(None)
-        }
-
-        fn visit_unit<E>(self) -> Result<Self::Value, E>
-        where
-            E: de::Error,
-        {
-            Ok(None)
-        }
-    }
-
-    deserializer.deserialize_any(StringBoolOrStruct(PhantomData))
-}
-
 #[cfg(test)]
 mod tests {
     use crate::docker::ImagePlatform;
@@ -617,7 +486,6 @@ mod tests {
                 },
                 xargo: Some(true),
                 build_std: None,
-                zig: None,
                 default_target: None,
                 pre_build: Some(PreBuild::Lines(vec![p!("echo 'Hello World!'")])),
                 dockerfile: None,
@@ -655,35 +523,12 @@ mod tests {
                 },
                 xargo: Some(false),
                 build_std: Some(true),
-                zig: None,
                 image: Some("test-image".into()),
                 runner: None,
                 dockerfile: None,
                 pre_build: Some(PreBuild::Lines(vec![])),
             },
         );
-        target_map.insert(
-            Target::BuiltIn {
-                triple: "aarch64-unknown-linux-musl".into(),
-            },
-            CrossTargetConfig {
-                env: CrossEnvConfig {
-                    passthrough: None,
-                    volumes: None,
-                },
-                xargo: None,
-                build_std: None,
-                zig: Some(CrossZigConfig {
-                    enable: Some(true),
-                    version: Some(p!("2.17")),
-                    image: Some("zig:local".into()),
-                }),
-                image: None,
-                runner: None,
-                dockerfile: None,
-                pre_build: None,
-            },
-        );
 
         let cfg = CrossToml {
             targets: target_map,
@@ -699,11 +544,6 @@ mod tests {
             build-std = true
             image = "test-image"
             pre-build = []
-
-            [target.aarch64-unknown-linux-musl.zig]
-            enable = true
-            version = "2.17"
-            image = "zig:local"
         "#;
         let (parsed_cfg, unused) = CrossToml::parse_from_cross(test_str, &mut m!())?;
 
@@ -723,7 +563,6 @@ mod tests {
             CrossTargetConfig {
                 xargo: Some(false),
                 build_std: None,
-                zig: None,
                 image: Some(PossibleImage {
                     name: "test-image".to_owned(),
                     toolchain: vec![ImagePlatform::from_target(
@@ -753,16 +592,6 @@ mod tests {
                 },
                 xargo: Some(true),
                 build_std: None,
-                zig: Some(CrossZigConfig {
-                    enable: None,
-                    version: None,
-                    image: Some(PossibleImage {
-                        name: "zig:local".to_owned(),
-                        toolchain: vec![ImagePlatform::from_target(
-                            "aarch64-unknown-linux-gnu".into(),
-                        )?],
-                    }),
-                }),
                 default_target: None,
                 pre_build: Some(PreBuild::Lines(vec![])),
                 dockerfile: None,
@@ -774,10 +603,6 @@ mod tests {
             xargo = true
             pre-build = []
 
-            [build.zig.image]
-            name = "zig:local"
-            toolchain = ["aarch64-unknown-linux-gnu"]
-
             [build.env]
             passthrough = []
 
@@ -827,7 +652,6 @@ mod tests {
                 },
                 build_std: None,
                 xargo: Some(true),
-                zig: None,
                 default_target: None,
                 pre_build: None,
                 dockerfile: None,
diff --git a/src/docker/custom.rs b/src/docker/custom.rs
index bfeba1f..847f3f0 100644
--- a/src/docker/custom.rs
+++ b/src/docker/custom.rs
@@ -70,7 +70,6 @@ impl<'a> Dockerfile<'a> {
         build_args: impl IntoIterator<Item = (impl AsRef<str>, impl AsRef<str>)>,
         msg_info: &mut MessageInfo,
     ) -> Result<String> {
-        let uses_zig = options.cargo_variant.uses_zig();
         let mut docker_build = docker::subcommand(&options.engine, "buildx");
         docker_build.arg("build");
         docker_build.env("DOCKER_SCAN_SUGGEST", "false");
@@ -131,9 +130,7 @@ impl<'a> Dockerfile<'a> {
         };
 
         if matches!(self, Dockerfile::File { .. }) {
-            if let Ok(cross_base_image) =
-                self::get_image_name(&options.config, &options.target, uses_zig)
-            {
+            if let Ok(cross_base_image) = self::get_image_name(&options.config, &options.target) {
                 docker_build.args([
                     "--build-arg",
                     &format!("CROSS_BASE_IMAGE={cross_base_image}"),
diff --git a/src/docker/local.rs b/src/docker/local.rs
index 6358992..665bb38 100644
--- a/src/docker/local.rs
+++ b/src/docker/local.rs
@@ -1,6 +1,5 @@
 use std::io;
-use std::path::Path;
-use std::process::{Command, ExitStatus};
+use std::process::ExitStatus;
 
 use super::shared::*;
 use crate::errors::Result;
@@ -9,16 +8,6 @@ use crate::file::{PathExt, ToUtf8};
 use crate::shell::{MessageInfo, Stream};
 use eyre::Context;
 
-// NOTE: host path must be absolute
-fn mount(docker: &mut Command, host_path: &Path, absolute_path: &Path, prefix: &str) -> Result<()> {
-    let mount_path = absolute_path.as_posix_absolute()?;
-    docker.args(&[
-        "-v",
-        &format!("{}:{prefix}{}:z", host_path.to_utf8()?, mount_path),
-    ]);
-    Ok(())
-}
-
 pub(crate) fn run(
     options: DockerOptions,
     paths: DockerPaths,
@@ -28,7 +17,7 @@ pub(crate) fn run(
     let engine = &options.engine;
     let dirs = &paths.directories;
 
-    let mut cmd = cargo_safe_command(options.cargo_variant);
+    let mut cmd = cargo_safe_command(options.uses_xargo);
     cmd.args(args);
 
     let mut docker = subcommand(engine, "run");
@@ -43,7 +32,6 @@ pub(crate) fn run(
         &options.config,
         dirs,
         &options.target,
-        options.cargo_variant,
         msg_info,
     )?;
 
@@ -51,7 +39,7 @@ pub(crate) fn run(
         &mut docker,
         &options,
         &paths,
-        |docker, host, absolute| mount(docker, host, absolute, ""),
+        |docker, val| mount(docker, val, ""),
         |_| {},
     )?;
 
@@ -64,28 +52,28 @@ pub(crate) fn run(
     docker
         .args(&[
             "-v",
-            &format!("{}:{}:z", dirs.xargo.to_utf8()?, dirs.xargo_mount_path()),
+            &format!("{}:{}:Z", dirs.xargo.to_utf8()?, dirs.xargo_mount_path()),
         ])
         .args(&[
             "-v",
-            &format!("{}:{}:z", dirs.cargo.to_utf8()?, dirs.cargo_mount_path()),
+            &format!("{}:{}:Z", dirs.cargo.to_utf8()?, dirs.cargo_mount_path()),
         ])
         // Prevent `bin` from being mounted inside the Docker container.
         .args(&["-v", &format!("{}/bin", dirs.cargo_mount_path())]);
     docker.args(&[
         "-v",
-        &format!("{}:{}:z", dirs.host_root.to_utf8()?, dirs.mount_root),
+        &format!("{}:{}:Z", dirs.host_root.to_utf8()?, dirs.mount_root),
     ]);
     docker
         .args(&[
             "-v",
             &format!(
-                "{}:{}:z,ro",
+                "{}:{}:Z,ro",
                 dirs.get_sysroot().to_utf8()?,
                 dirs.sysroot_mount_path()
             ),
         ])
-        .args(&["-v", &format!("{}:/target:z", dirs.target.to_utf8()?)]);
+        .args(&["-v", &format!("{}:/target:Z", dirs.target.to_utf8()?)]);
     docker_cwd(&mut docker, &paths)?;
 
     // When running inside NixOS or using Nix packaging we need to add the Nix
@@ -93,16 +81,15 @@ pub(crate) fn run(
     if let Some(ref nix_store) = dirs.nix_store {
         docker.args(&[
             "-v",
-            &format!(
-                "{}:{}:z",
-                nix_store.to_utf8()?,
-                nix_store.as_posix_absolute()?
-            ),
+            &format!("{}:{}:Z", nix_store.to_utf8()?, nix_store.as_posix()?),
         ]);
     }
 
-    if io::Stdin::is_atty() && io::Stdout::is_atty() && io::Stderr::is_atty() {
-        docker.arg("-t");
+    if io::Stdin::is_atty() {
+        docker.arg("-i");
+        if io::Stdout::is_atty() && io::Stderr::is_atty() {
+            docker.arg("-t");
+        }
     }
     let mut image_name = options.image.name.clone();
     if options.needs_custom_image() {
diff --git a/src/docker/provided_images.rs b/src/docker/provided_images.rs
index 9e4ee45..7c468a0 100644
--- a/src/docker/provided_images.rs
+++ b/src/docker/provided_images.rs
@@ -273,9 +273,4 @@ pub static PROVIDED_IMAGES: &[ProvidedImage] = &[
             platforms: &[ImagePlatform::DEFAULT],
             sub: None
         },
-        ProvidedImage {
-            name: "zig",
-            platforms: &[ImagePlatform::DEFAULT],
-            sub: None
-        },
 ];
diff --git a/src/docker/remote.rs b/src/docker/remote.rs
index 8394bee..bdb2926 100644
--- a/src/docker/remote.rs
+++ b/src/docker/remote.rs
@@ -168,11 +168,7 @@ fn create_volume_dir(
     // make our parent directory if needed
     subcommand_or_exit(engine, "exec")?
         .arg(container)
-        .args(&[
-            "sh",
-            "-c",
-            &format!("mkdir -p '{}'", dir.as_posix_absolute()?),
-        ])
+        .args(&["sh", "-c", &format!("mkdir -p '{}'", dir.as_posix()?)])
         .run_and_get_status(msg_info, false)
 }
 
@@ -187,7 +183,7 @@ fn copy_volume_files(
     subcommand_or_exit(engine, "cp")?
         .arg("-a")
         .arg(src.to_utf8()?)
-        .arg(format!("{container}:{}", dst.as_posix_absolute()?))
+        .arg(format!("{container}:{}", dst.as_posix()?))
         .run_and_get_status(msg_info, false)
 }
 
@@ -218,11 +214,7 @@ fn container_path_exists(
 ) -> Result<bool> {
     Ok(subcommand_or_exit(engine, "exec")?
         .arg(container)
-        .args(&[
-            "bash",
-            "-c",
-            &format!("[[ -d '{}' ]]", path.as_posix_absolute()?),
-        ])
+        .args(&["bash", "-c", &format!("[[ -d '{}' ]]", path.as_posix()?)])
         .run_and_get_status(msg_info, true)?
         .success())
 }
@@ -575,7 +567,7 @@ fn read_dir_fingerprint(
             let modified = file.metadata()?.modified()?;
             let millis = modified.duration_since(epoch)?.as_millis() as u64;
             let rounded = epoch + time::Duration::from_millis(millis);
-            let relpath = file.path().strip_prefix(home)?.as_posix_relative()?;
+            let relpath = file.path().strip_prefix(home)?.as_posix()?;
             map.insert(relpath, rounded);
         }
     }
@@ -655,7 +647,7 @@ rm \"{PATH}\"
     // SAFETY: safe, single-threaded execution.
     let mut tempfile = unsafe { temp::TempFile::new()? };
     for file in files {
-        writeln!(tempfile.file(), "{}", dst.join(file).as_posix_relative()?)?;
+        writeln!(tempfile.file(), "{}", dst.join(file).as_posix()?)?;
     }
 
     // need to avoid having hundreds of files on the command, so
@@ -853,6 +845,11 @@ pub fn unique_container_identifier(
     Ok(format!("{toolchain_id}-{triple}-{name}-{project_hash}"))
 }
 
+fn mount_path(val: &Path) -> Result<String> {
+    let host_path = file::canonicalize(val)?;
+    canonicalize_mount_path(&host_path)
+}
+
 pub(crate) fn run(
     options: DockerOptions,
     paths: DockerPaths,
@@ -865,10 +862,6 @@ pub(crate) fn run(
 
     let mount_prefix = MOUNT_PREFIX;
 
-    if options.in_docker() {
-        msg_info.warn("remote and docker-in-docker are unlikely to work together when using cross. remote cross uses data volumes, so docker-in-docker should not be required.")?;
-    }
-
     // the logic is broken into the following steps
     // 1. get our unique identifiers and cleanup from a previous run.
     // 2. if not using persistent volumes, create a data volume
@@ -928,7 +921,7 @@ pub(crate) fn run(
         &mut docker,
         &options,
         &paths,
-        |_, _, _| Ok(()),
+        |_, val| mount_path(val),
         |(src, dst)| volumes.push((src, dst)),
     )
     .wrap_err("could not determine mount points")?;
@@ -1107,7 +1100,7 @@ pub(crate) fn run(
     let mut final_args = vec![];
     let mut iter = args.iter().cloned();
     let mut has_target_dir = false;
-    let target_dir_string = target_dir.as_posix_absolute()?;
+    let target_dir_string = target_dir.as_posix()?;
     while let Some(arg) = iter.next() {
         if arg == "--target-dir" {
             has_target_dir = true;
@@ -1128,7 +1121,7 @@ pub(crate) fn run(
         final_args.push("--target-dir".to_owned());
         final_args.push(target_dir_string);
     }
-    let mut cmd = cargo_safe_command(options.cargo_variant);
+    let mut cmd = cargo_safe_command(options.uses_xargo);
     cmd.args(final_args);
 
     // 5. create symlinks for copied data
@@ -1163,11 +1156,7 @@ symlink_recurse \"${{prefix}}\"
 "
     ));
     for (src, dst) in to_symlink {
-        symlink.push(format!(
-            "ln -s \"{}\" \"{}\"",
-            src.as_posix_absolute()?,
-            dst
-        ));
+        symlink.push(format!("ln -s \"{}\" \"{}\"", src.as_posix()?, dst));
     }
     subcommand_or_exit(engine, "exec")?
         .arg(&container)
@@ -1178,14 +1167,7 @@ symlink_recurse \"${{prefix}}\"
     // 6. execute our cargo command inside the container
     let mut docker = subcommand(engine, "exec");
     docker_user_id(&mut docker, engine.kind);
-    docker_envvars(
-        &mut docker,
-        &options.config,
-        dirs,
-        target,
-        options.cargo_variant,
-        msg_info,
-    )?;
+    docker_envvars(&mut docker, &options.config, dirs, target, msg_info)?;
     docker_cwd(&mut docker, &paths)?;
     docker.arg(&container);
     docker.args(&["sh", "-c", &build_command(dirs, &cmd)]);
@@ -1203,7 +1185,7 @@ symlink_recurse \"${{prefix}}\"
     if !skip_artifacts && container_path_exists(engine, &container, &target_dir, msg_info)? {
         subcommand_or_exit(engine, "cp")?
             .arg("-a")
-            .arg(&format!("{container}:{}", target_dir.as_posix_absolute()?))
+            .arg(&format!("{container}:{}", target_dir.as_posix()?))
             .arg(
                 &dirs
                     .target
diff --git a/src/docker/shared.rs b/src/docker/shared.rs
index 9fb7675..a11d8c3 100644
--- a/src/docker/shared.rs
+++ b/src/docker/shared.rs
@@ -12,11 +12,14 @@ use crate::cargo::{cargo_metadata_with_args, CargoMetadata};
 use crate::config::{bool_from_envvar, Config};
 use crate::errors::*;
 use crate::extensions::{CommandExt, SafeCommand};
-use crate::file::{self, write_file, PathExt, ToUtf8};
+use crate::file::{self, write_file, ToUtf8};
 use crate::id;
 use crate::rustc::QualifiedToolchain;
 use crate::shell::{MessageInfo, Verbosity};
-use crate::{CargoVariant, Target};
+use crate::Target;
+
+#[cfg(target_os = "windows")]
+use crate::file::PathExt;
 
 pub use super::custom::CROSS_CUSTOM_DOCKERFILE_IMAGE_PREFIX;
 
@@ -36,7 +39,7 @@ pub struct DockerOptions {
     pub target: Target,
     pub config: Config,
     pub image: Image,
-    pub cargo_variant: CargoVariant,
+    pub uses_xargo: bool,
 }
 
 impl DockerOptions {
@@ -45,14 +48,14 @@ impl DockerOptions {
         target: Target,
         config: Config,
         image: Image,
-        cargo_variant: CargoVariant,
+        uses_xargo: bool,
     ) -> DockerOptions {
         DockerOptions {
             engine,
             target,
             config,
             image,
-            cargo_variant,
+            uses_xargo,
         }
     }
 
@@ -284,10 +287,6 @@ impl Directories {
         }
         create_target_dir(target)?;
 
-        // get our mount paths prior to canonicalizing them
-        let cargo_mount_path = cargo.as_posix_absolute()?;
-        let xargo_mount_path = xargo.as_posix_absolute()?;
-
         // now that we know the paths exist, canonicalize them. this avoids creating
         // directories after failed canonicalization into a shared directory.
         let cargo = file::canonicalize(&cargo)?;
@@ -308,15 +307,17 @@ impl Directories {
             &metadata.workspace_root
         });
 
-        // on Windows, we can not mount the directory name directly. Instead, we use wslpath to convert the path to a linux compatible path.
-        // NOTE: on unix, host root has already found the mount path
-        let mount_root = host_root.as_posix_absolute()?;
+        // root is either workspace_root, or, if we're outside the workspace root, the current directory
+        // NOTE: host root has already found the mount path
+        let mount_root = canonicalize_mount_path(&host_root)?;
         let mount_cwd = mount_finder.find_path(cwd, false)?;
 
         toolchain.set_sysroot(|p| mount_finder.find_mount_path(p));
 
         // canonicalize these once to avoid syscalls
-        let sysroot_mount_path = toolchain.get_sysroot().as_posix_absolute()?;
+        let cargo_mount_path = canonicalize_mount_path(&cargo)?;
+        let xargo_mount_path = canonicalize_mount_path(&xargo)?;
+        let sysroot_mount_path = canonicalize_mount_path(toolchain.get_sysroot())?;
 
         Ok(Directories {
             cargo,
@@ -458,8 +459,12 @@ pub fn parse_docker_opts(value: &str) -> Result<Vec<String>> {
     shell_words::split(value).wrap_err_with(|| format!("could not parse docker opts of {}", value))
 }
 
-pub(crate) fn cargo_safe_command(cargo_variant: CargoVariant) -> SafeCommand {
-    SafeCommand::new(cargo_variant.to_str())
+pub(crate) fn cargo_safe_command(uses_xargo: bool) -> SafeCommand {
+    if uses_xargo {
+        SafeCommand::new("xargo")
+    } else {
+        SafeCommand::new("cargo")
+    }
 }
 
 fn add_cargo_configuration_envvars(docker: &mut Command) {
@@ -496,12 +501,21 @@ fn add_cargo_configuration_envvars(docker: &mut Command) {
     }
 }
 
+// NOTE: host path must be canonical
+pub(crate) fn mount(docker: &mut Command, host_path: &Path, prefix: &str) -> Result<String> {
+    let mount_path = canonicalize_mount_path(host_path)?;
+    docker.args(&[
+        "-v",
+        &format!("{}:{prefix}{}", host_path.to_utf8()?, mount_path),
+    ]);
+    Ok(mount_path)
+}
+
 pub(crate) fn docker_envvars(
     docker: &mut Command,
     config: &Config,
     dirs: &Directories,
     target: &Target,
-    cargo_variant: CargoVariant,
     msg_info: &mut MessageInfo,
 ) -> Result<()> {
     for ref var in config.env_passthrough(target)?.unwrap_or_default() {
@@ -520,10 +534,6 @@ pub(crate) fn docker_envvars(
         .args(&["-e", &format!("CARGO_HOME={}", dirs.cargo_mount_path())])
         .args(&["-e", "CARGO_TARGET_DIR=/target"])
         .args(&["-e", &cross_runner]);
-    if cargo_variant.uses_zig() {
-        // otherwise, zig has a permission error trying to create the cache
-        docker.args(&["-e", "XDG_CACHE_HOME=/target/.zig-cache"]);
-    }
     add_cargo_configuration_envvars(docker);
 
     if let Some(username) = id::username().wrap_err("could not get username")? {
@@ -569,7 +579,7 @@ pub(crate) fn docker_mount(
     docker: &mut Command,
     options: &DockerOptions,
     paths: &DockerPaths,
-    mount_cb: impl Fn(&mut Command, &Path, &Path) -> Result<()>,
+    mount_cb: impl Fn(&mut Command, &Path) -> Result<String>,
     mut store_cb: impl FnMut((String, String)),
 ) -> Result<()> {
     for ref var in options
@@ -583,44 +593,37 @@ pub(crate) fn docker_mount(
             None => env::var(var),
         };
 
-        // NOTE: we use canonical paths on the host, since it's unambiguous.
-        // however, for the mounted paths, we use the same path as was
-        // provided. this avoids canonicalizing symlinks which then causes
-        // the mounted path to differ from the path expected on the host.
-        // for example, if `/tmp` is a symlink to `/private/tmp`, canonicalizing
-        // it would lead to us mounting `/tmp/process` to `/private/tmp/process`,
-        // which would cause any code relying on `/tmp/process` to break.
-
         if let Ok(val) = value {
-            let canonical_path = file::canonicalize(&val)?;
-            let host_path = paths.mount_finder.find_path(&canonical_path, true)?;
-            let absolute_path = Path::new(&val).as_posix_absolute()?;
-            let mount_path = paths
-                .mount_finder
-                .find_path(Path::new(&absolute_path), true)?;
-            mount_cb(docker, host_path.as_ref(), mount_path.as_ref())?;
-            docker.args(&["-e", &format!("{}={}", var, mount_path)]);
+            let canonical_val = file::canonicalize(&val)?;
+            let host_path = paths.mount_finder.find_path(&canonical_val, true)?;
+            let mount_path = mount_cb(docker, host_path.as_ref())?;
+            docker.args(&["-e", &format!("{}={}", host_path, mount_path)]);
             store_cb((val, mount_path));
         }
     }
 
     for path in paths.workspace_dependencies() {
-        // NOTE: we use canonical paths here since cargo metadata
-        // always canonicalizes paths, so these should be relative
-        // to the mounted project directory.
         let canonical_path = file::canonicalize(path)?;
         let host_path = paths.mount_finder.find_path(&canonical_path, true)?;
-        let absolute_path = Path::new(path).as_posix_absolute()?;
-        let mount_path = paths
-            .mount_finder
-            .find_path(Path::new(&absolute_path), true)?;
-        mount_cb(docker, host_path.as_ref(), mount_path.as_ref())?;
+        let mount_path = mount_cb(docker, host_path.as_ref())?;
         store_cb((path.to_utf8()?.to_owned(), mount_path));
     }
 
     Ok(())
 }
 
+pub(crate) fn canonicalize_mount_path(path: &Path) -> Result<String> {
+    #[cfg(target_os = "windows")]
+    {
+        // On Windows, we can not mount the directory name directly. Instead, we use wslpath to convert the path to a linux compatible path.
+        path.as_wslpath()
+    }
+    #[cfg(not(target_os = "windows"))]
+    {
+        path.to_utf8().map(|p| p.to_owned())
+    }
+}
+
 pub(crate) fn user_id() -> String {
     env::var("CROSS_CONTAINER_UID").unwrap_or_else(|_| id::user().to_string())
 }
@@ -682,7 +685,7 @@ pub(crate) fn docker_seccomp(
             #[cfg(target_os = "windows")]
             if matches!(engine_type, EngineType::Podman | EngineType::PodmanRemote) {
                 // podman weirdly expects a WSL path here, and fails otherwise
-                path_string = path.as_posix_absolute()?;
+                path_string = path.as_wslpath()?;
             }
             path_string
         };
@@ -694,31 +697,24 @@ pub(crate) fn docker_seccomp(
 }
 
 /// Simpler version of [get_image]
-pub fn get_image_name(config: &Config, target: &Target, uses_zig: bool) -> Result<String> {
+pub fn get_image_name(config: &Config, target: &Target) -> Result<String> {
     if let Some(image) = config.image(target)? {
         return Ok(image.name);
     }
 
-    let target_name = match uses_zig {
-        true => match config.zig_image(target)? {
-            Some(image) => return Ok(image.name),
-            None => "zig",
-        },
-        false => target.triple(),
-    };
     let compatible = PROVIDED_IMAGES
         .iter()
-        .filter(|p| p.name == target_name)
+        .filter(|p| p.name == target.triple())
         .collect::<Vec<_>>();
 
     if compatible.is_empty() {
         eyre::bail!(
-            "`cross` does not provide a Docker image for target {target_name}, \
+            "`cross` does not provide a Docker image for target {target}, \
                    specify a custom image in `Cross.toml`."
         );
     }
 
-    let version = if crate::commit_info().is_empty() {
+    let version = if include_str!(concat!(env!("OUT_DIR"), "/commit-info.txt")).is_empty() {
         env!("CARGO_PKG_VERSION")
     } else {
         "main"
@@ -730,31 +726,24 @@ pub fn get_image_name(config: &Config, target: &Target, uses_zig: bool) -> Resul
         .image_name(CROSS_IMAGE, version))
 }
 
-pub(crate) fn get_image(config: &Config, target: &Target, uses_zig: bool) -> Result<PossibleImage> {
+pub(crate) fn get_image(config: &Config, target: &Target) -> Result<PossibleImage> {
     if let Some(image) = config.image(target)? {
         return Ok(image);
     }
 
-    let target_name = match uses_zig {
-        true => match config.zig_image(target)? {
-            Some(image) => return Ok(image),
-            None => "zig",
-        },
-        false => target.triple(),
-    };
     let compatible = PROVIDED_IMAGES
         .iter()
-        .filter(|p| p.name == target_name)
+        .filter(|p| p.name == target.triple())
         .collect::<Vec<_>>();
 
     if compatible.is_empty() {
         eyre::bail!(
-            "`cross` does not provide a Docker image for target {target_name}, \
+            "`cross` does not provide a Docker image for target {target}, \
                specify a custom image in `Cross.toml`."
         );
     }
 
-    let version = if crate::commit_info().is_empty() {
+    let version = if include_str!(concat!(env!("OUT_DIR"), "/commit-info.txt")).is_empty() {
         env!("CARGO_PKG_VERSION")
     } else {
         "main"
@@ -777,7 +766,7 @@ pub(crate) fn get_image(config: &Config, target: &Target, uses_zig: bool) -> Res
     } else {
         // if there's multiple targets and no option can be chosen, bail
         return Err(eyre::eyre!(
-            "`cross` provides multiple images for target {target_name}, \
+            "`cross` provides multiple images for target {target}, \
                specify toolchain in `Cross.toml`."
         )
         .with_note(|| {
@@ -908,15 +897,20 @@ impl MountFinder {
         path.to_path_buf()
     }
 
+    #[allow(unused_variables, clippy::needless_return)]
     fn find_path(&self, path: &Path, host: bool) -> Result<String> {
-        if cfg!(target_os = "windows") && host {
-            // On Windows, we can not mount the directory name directly.
-            // Instead, we convert the path to a linux compatible path.
-            return path.to_utf8().map(ToOwned::to_owned);
-        } else if cfg!(target_os = "windows") {
-            path.as_posix_absolute()
-        } else {
-            self.find_mount_path(path).as_posix_absolute()
+        #[cfg(target_os = "windows")]
+        {
+            // On Windows, we can not mount the directory name directly. Instead, we use wslpath to convert the path to a linux compatible path.
+            if host {
+                return Ok(path.to_utf8()?.to_owned());
+            } else {
+                return path.as_wslpath();
+            }
+        }
+        #[cfg(not(target_os = "windows"))]
+        {
+            return Ok(self.find_mount_path(path).to_utf8()?.to_owned());
         }
     }
 }
@@ -1108,14 +1102,24 @@ mod tests {
             Directories::create(mount_finder, metadata, &cwd, toolchain)
         }
 
+        fn path_to_posix(path: &Path) -> Result<String> {
+            #[cfg(target_os = "windows")]
+            {
+                path.as_wslpath()
+            }
+            #[cfg(not(target_os = "windows"))]
+            {
+                path.as_posix()
+            }
+        }
+
         #[track_caller]
         fn paths_equal(x: &Path, y: &Path) -> Result<()> {
-            assert_eq!(x.as_posix_absolute()?, y.as_posix_absolute()?);
+            assert_eq!(path_to_posix(x)?, path_to_posix(y)?);
             Ok(())
         }
 
         #[test]
-        #[cfg_attr(cross_sandboxed, ignore)]
         fn test_host() -> Result<()> {
             let vars = unset_env();
             let mount_finder = MountFinder::new(vec![]);
@@ -1126,9 +1130,9 @@ mod tests {
             paths_equal(&directories.host_root, &metadata.workspace_root)?;
             assert_eq!(
                 &directories.mount_root,
-                &metadata.workspace_root.as_posix_absolute()?
+                &path_to_posix(&metadata.workspace_root)?
             );
-            assert_eq!(&directories.mount_cwd, &get_cwd()?.as_posix_absolute()?);
+            assert_eq!(&directories.mount_cwd, &path_to_posix(&get_cwd()?)?);
 
             reset_env(vars);
             Ok(())
@@ -1174,11 +1178,11 @@ mod tests {
             paths_equal(&directories.host_root, &mount_path(get_cwd()?))?;
             assert_eq!(
                 &directories.mount_root,
-                &mount_path(get_cwd()?).as_posix_absolute()?
+                &path_to_posix(&mount_path(get_cwd()?))?
             );
             assert_eq!(
                 &directories.mount_cwd,
-                &mount_path(get_cwd()?).as_posix_absolute()?
+                &path_to_posix(&mount_path(get_cwd()?))?
             );
 
             reset_env(vars);
diff --git a/src/errors.rs b/src/errors.rs
index 364317f..c0c5aaf 100644
--- a/src/errors.rs
+++ b/src/errors.rs
@@ -10,10 +10,8 @@ pub use eyre::Result;
 pub static mut TERMINATED: AtomicBool = AtomicBool::new(false);
 
 pub fn install_panic_hook() -> Result<()> {
-    let is_dev = !crate::commit_info().is_empty() || std::env::var("CROSS_DEBUG").is_ok();
     color_eyre::config::HookBuilder::new()
-        .display_env_section(is_dev)
-        .display_location_section(is_dev)
+        .display_env_section(false)
         .install()
 }
 
diff --git a/src/file.rs b/src/file.rs
index 2e9cf7c..bebf205 100644
--- a/src/file.rs
+++ b/src/file.rs
@@ -1,5 +1,4 @@
 use std::borrow::Cow;
-use std::env;
 use std::ffi::OsStr;
 use std::fs::{self, File};
 use std::io::Read;
@@ -27,8 +26,9 @@ impl ToUtf8 for Path {
 }
 
 pub trait PathExt {
-    fn as_posix_relative(&self) -> Result<String>;
-    fn as_posix_absolute(&self) -> Result<String>;
+    fn as_posix(&self) -> Result<String>;
+    #[cfg(target_family = "windows")]
+    fn as_wslpath(&self) -> Result<String>;
 }
 
 #[cfg(target_family = "windows")]
@@ -44,23 +44,6 @@ fn fmt_disk(disk: u8) -> String {
     (disk as char).to_string()
 }
 
-#[cfg(target_family = "windows")]
-fn fmt_ns_disk(disk: &std::ffi::OsStr) -> Result<String> {
-    let disk = disk.to_utf8()?;
-    Ok(match disk.len() {
-        // ns can be similar to `\\.\COM42`, or also `\\.\C:\`
-        2 => {
-            let c = disk.chars().next().expect("cannot be empty");
-            if c.is_ascii_alphabetic() && disk.ends_with(':') {
-                fmt_disk(c as u8)
-            } else {
-                disk.to_owned()
-            }
-        }
-        _ => disk.to_owned(),
-    })
-}
-
 #[cfg(target_family = "windows")]
 fn fmt_unc(server: &std::ffi::OsStr, volume: &std::ffi::OsStr) -> Result<String> {
     let server = server.to_utf8()?;
@@ -78,7 +61,7 @@ fn fmt_unc(server: &std::ffi::OsStr, volume: &std::ffi::OsStr) -> Result<String>
 }
 
 impl PathExt for Path {
-    fn as_posix_relative(&self) -> Result<String> {
+    fn as_posix(&self) -> Result<String> {
         if cfg!(target_os = "windows") {
             let push = |p: &mut String, c: &str| {
                 if !p.is_empty() && p != "/" {
@@ -106,16 +89,11 @@ impl PathExt for Path {
         }
     }
 
-    #[cfg(not(target_family = "windows"))]
-    fn as_posix_absolute(&self) -> Result<String> {
-        absolute_path(self)?.to_utf8().map(ToOwned::to_owned)
-    }
-
-    // this is similar to as_posix_relative, but it handles drive
-    // separators and will only work with absolute paths.
+    // this is similar to as_posix, but it handles drive separators
+    // and doesn't assume a relative path.
     #[cfg(target_family = "windows")]
-    fn as_posix_absolute(&self) -> Result<String> {
-        let path = absolute_path(self)?;
+    fn as_wslpath(&self) -> Result<String> {
+        let path = canonicalize(self)?;
 
         let push = |p: &mut String, c: &str, r: bool| {
             if !r {
@@ -137,7 +115,7 @@ impl PathExt for Path {
                         // a root_prefix since we force absolute paths.
                         Prefix::VerbatimDisk(disk) => fmt_disk(disk),
                         Prefix::UNC(server, volume) => fmt_unc(server, volume)?,
-                        Prefix::DeviceNS(ns) => fmt_ns_disk(ns)?,
+                        Prefix::DeviceNS(ns) => ns.to_utf8()?.to_owned(),
                         Prefix::Disk(disk) => fmt_disk(disk),
                     }
                 }
@@ -196,15 +174,6 @@ fn _canonicalize(path: &Path) -> Result<PathBuf> {
     }
 }
 
-// Fix for issue #581. target_dir must be absolute.
-pub fn absolute_path(path: impl AsRef<Path>) -> Result<PathBuf> {
-    Ok(if path.as_ref().is_absolute() {
-        path.as_ref().to_path_buf()
-    } else {
-        env::current_dir()?.join(path)
-    })
-}
-
 /// Pretty format a file path. Also removes the path prefix from a command if wanted
 pub fn pretty_path(path: impl AsRef<Path>, strip: impl for<'a> Fn(&'a str) -> bool) -> String {
     let path = path.as_ref();
@@ -288,7 +257,6 @@ mod tests {
         };
     }
 
-    #[track_caller]
     fn result_eq<T: PartialEq + Eq + Debug>(x: Result<T>, y: Result<T>) {
         match (x, y) {
             (Ok(x), Ok(y)) => assert_eq!(x, y),
@@ -297,44 +265,32 @@ mod tests {
     }
 
     #[test]
-    fn as_posix_relative() {
-        result_eq(
-            p!(".").join("..").as_posix_relative(),
-            Ok("./..".to_owned()),
-        );
-        result_eq(p!(".").join("/").as_posix_relative(), Ok("/".to_owned()));
-        result_eq(
-            p!("foo").join("bar").as_posix_relative(),
-            Ok("foo/bar".to_owned()),
-        );
-        result_eq(
-            p!("/foo").join("bar").as_posix_relative(),
-            Ok("/foo/bar".to_owned()),
-        );
+    fn as_posix() {
+        result_eq(p!(".").join("..").as_posix(), Ok("./..".to_owned()));
+        result_eq(p!(".").join("/").as_posix(), Ok("/".to_owned()));
+        result_eq(p!("foo").join("bar").as_posix(), Ok("foo/bar".to_owned()));
+        result_eq(p!("/foo").join("bar").as_posix(), Ok("/foo/bar".to_owned()));
     }
 
     #[test]
     #[cfg(target_family = "windows")]
     fn as_posix_prefix() {
         assert_eq!(p!("C:").join(".."), p!("C:.."));
-        assert!(p!("C:").join("..").as_posix_relative().is_err());
+        assert!(p!("C:").join("..").as_posix().is_err());
     }
 
     #[test]
     #[cfg(target_family = "windows")]
-    fn as_posix_with_drive() {
-        result_eq(p!(r"C:\").as_posix_absolute(), Ok("/mnt/c".to_owned()));
-        result_eq(
-            p!(r"C:\Users").as_posix_absolute(),
-            Ok("/mnt/c/Users".to_owned()),
-        );
+    fn as_wslpath() {
+        result_eq(p!(r"C:\").as_wslpath(), Ok("/mnt/c".to_owned()));
+        result_eq(p!(r"C:\Users").as_wslpath(), Ok("/mnt/c/Users".to_owned()));
         result_eq(
-            p!(r"\\localhost\c$\Users").as_posix_absolute(),
+            p!(r"\\localhost\c$\Users").as_wslpath(),
             Ok("/mnt/c/Users".to_owned()),
         );
-        result_eq(p!(r"\\.\C:\").as_posix_absolute(), Ok("/mnt/c".to_owned()));
+        result_eq(p!(r"\\.\C:\").as_wslpath(), Ok("/mnt/c".to_owned()));
         result_eq(
-            p!(r"\\.\C:\Users").as_posix_absolute(),
+            p!(r"\\.\C:\Users").as_wslpath(),
             Ok("/mnt/c/Users".to_owned()),
         );
     }
diff --git a/src/lib.rs b/src/lib.rs
index 44c8dbe..b147006 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -433,40 +433,6 @@ impl Serialize for Target {
     }
 }
 
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum CargoVariant {
-    Cargo,
-    Xargo,
-    Zig,
-}
-
-impl CargoVariant {
-    pub fn create(uses_zig: bool, uses_xargo: bool) -> Result<CargoVariant> {
-        match (uses_zig, uses_xargo) {
-            (true, true) => eyre::bail!("cannot use both zig and xargo"),
-            (true, false) => Ok(CargoVariant::Zig),
-            (false, true) => Ok(CargoVariant::Xargo),
-            (false, false) => Ok(CargoVariant::Cargo),
-        }
-    }
-
-    pub fn to_str(self) -> &'static str {
-        match self {
-            CargoVariant::Cargo => "cargo",
-            CargoVariant::Xargo => "xargo",
-            CargoVariant::Zig => "cargo-zigbuild",
-        }
-    }
-
-    pub fn uses_xargo(self) -> bool {
-        self == CargoVariant::Xargo
-    }
-
-    pub fn uses_zig(self) -> bool {
-        self == CargoVariant::Zig
-    }
-}
-
 fn warn_on_failure(
     target: &Target,
     toolchain: &QualifiedToolchain,
@@ -476,7 +442,7 @@ fn warn_on_failure(
     if target.is_builtin() {
         let component = rustup::check_component(&rust_std, toolchain, msg_info)?;
         if component.is_not_available() {
-            msg_info.warn(format_args!("rust-std is not available for {target}"))?;
+            msg_info.warn(format!("rust-std is not available for {target}"))?;
             msg_info.note(
                 format_args!(
                     r#"you may need to build components for the target via `-Z build-std=<components>` or in your cross configuration specify `target.{target}.build-std`
@@ -487,23 +453,16 @@ fn warn_on_failure(
     }
     Ok(())
 }
-
-fn add_libc_version(triple: &str, zig_version: Option<&str>) -> String {
-    match zig_version {
-        Some(libc) => format!("{triple}.{libc}"),
-        None => triple.to_owned(),
-    }
-}
-
 pub fn run(
     args: Args,
     target_list: TargetList,
     msg_info: &mut MessageInfo,
 ) -> Result<Option<ExitStatus>> {
     if args.version && args.subcommand.is_none() {
-        msg_info.print(format_args!(
+        let commit_info = include_str!(concat!(env!("OUT_DIR"), "/commit-info.txt"));
+        msg_info.print(format!(
             concat!("cross ", env!("CARGO_PKG_VERSION"), "{}"),
-            crate::commit_info()
+            commit_info
         ))?;
     }
 
@@ -520,12 +479,10 @@ pub fn run(
             .unwrap_or_else(|| Target::from(host.triple(), &target_list));
         config.confusable_target(&target, msg_info)?;
 
-        let uses_zig = config.zig(&target).unwrap_or(false);
-        let zig_version = config.zig_version(&target)?;
         // Get the image we're supposed to base all our next actions on.
         // The image we actually run in might get changed with
         // `target.{{TARGET}}.dockerfile` or `target.{{TARGET}}.pre-build`
-        let image = match docker::get_image(&config, &target, uses_zig) {
+        let image = match docker::get_image(&config, &target) {
             Ok(i) => i,
             Err(err) => {
                 msg_info.warn(err)?;
@@ -611,7 +568,6 @@ To override the toolchain mounted in the image, set `target.{}.image.toolchain =
             let uses_build_std = config.build_std(&target).unwrap_or(false);
             let uses_xargo =
                 !uses_build_std && config.xargo(&target).unwrap_or(!target.is_builtin());
-            let cargo_variant = CargoVariant::create(uses_zig, uses_xargo)?;
             if !toolchain.is_custom {
                 // build-std overrides xargo, but only use it if it's a built-in
                 // tool but not an available target or doesn't have rust-std.
@@ -640,7 +596,6 @@ To override the toolchain mounted in the image, set `target.{}.image.toolchain =
 
             let needs_interpreter = args.subcommand.map_or(false, |sc| sc.needs_interpreter());
 
-            let add_libc = |triple: &str| add_libc_version(triple, zig_version.as_deref());
             let mut filtered_args = if args
                 .subcommand
                 .map_or(false, |s| !s.needs_target_in_command())
@@ -661,24 +616,8 @@ To override the toolchain mounted in the image, set `target.{}.image.toolchain =
             } else if !args.all.iter().any(|a| a.starts_with("--target")) {
                 let mut args_with_target = args.all.clone();
                 args_with_target.push("--target".to_owned());
-                args_with_target.push(add_libc(target.triple()));
+                args_with_target.push(target.triple().to_owned());
                 args_with_target
-            } else if zig_version.is_some() {
-                let mut filtered_args = Vec::new();
-                let mut args_iter = args.all.clone().into_iter();
-                while let Some(arg) = args_iter.next() {
-                    if arg == "--target" {
-                        filtered_args.push("--target".to_owned());
-                        if let Some(triple) = args_iter.next() {
-                            filtered_args.push(add_libc(&triple));
-                        }
-                    } else if let Some(stripped) = arg.strip_prefix("--target=") {
-                        filtered_args.push(format!("--target={}", add_libc(stripped)));
-                    } else {
-                        filtered_args.push(arg);
-                    }
-                }
-                filtered_args
             } else {
                 args.all.clone()
             };
@@ -704,13 +643,8 @@ To override the toolchain mounted in the image, set `target.{}.image.toolchain =
                 }
 
                 let paths = docker::DockerPaths::create(&engine, metadata, cwd, toolchain.clone())?;
-                let options = docker::DockerOptions::new(
-                    engine,
-                    target.clone(),
-                    config,
-                    image,
-                    cargo_variant,
-                );
+                let options =
+                    docker::DockerOptions::new(engine, target.clone(), config, image, uses_xargo);
                 let status = docker::run(options, paths, &filtered_args, msg_info)
                     .wrap_err("could not run container")?;
                 let needs_host = args.subcommand.map_or(false, |sc| sc.needs_host(is_remote));
@@ -755,25 +689,21 @@ pub(crate) fn warn_host_version_mismatch(
             host_version_meta.short_version_string
         );
         if versions.is_lt() || (versions.is_eq() && dates.is_lt()) {
-            msg_info.warn(format_args!("using older {rustc_warning}.\n > Update with `rustup update --force-non-host {toolchain}`"))?;
+            msg_info.warn(format!("using older {rustc_warning}.\n > Update with `rustup update --force-non-host {toolchain}`"))?;
             return Ok(VersionMatch::OlderTarget);
         } else if versions.is_gt() || (versions.is_eq() && dates.is_gt()) {
-            msg_info.warn(format_args!(
+            msg_info.warn(format!(
                 "using newer {rustc_warning}.\n > Update with `rustup update`"
             ))?;
             return Ok(VersionMatch::NewerTarget);
         } else {
-            msg_info.warn(format_args!("using {rustc_warning}."))?;
+            msg_info.warn(format!("using {rustc_warning}."))?;
             return Ok(VersionMatch::Different);
         }
     }
     Ok(VersionMatch::Same)
 }
 
-fn commit_info() -> &'static str {
-    include_str!(concat!(env!("OUT_DIR"), "/commit-info.txt"))
-}
-
 /// Obtains the [`CrossToml`] from one of the possible locations
 ///
 /// These locations are checked in the following order:
diff --git a/src/rustup.rs b/src/rustup.rs
index 5e952d9..a467ae6 100644
--- a/src/rustup.rs
+++ b/src/rustup.rs
@@ -130,31 +130,10 @@ cross will not attempt to configure the toolchain further so that it can run you
     })
 }
 
-fn version(msg_info: &mut MessageInfo) -> Result<Version> {
-    let out = rustup_command(msg_info, false)
-        .arg("--version")
-        .run_and_get_stdout(msg_info)?;
-
-    match out
-        .lines()
-        .next()
-        .and_then(|line| line.split_whitespace().nth(1))
-    {
-        Some(version) => {
-            semver::Version::parse(version).wrap_err_with(|| "failed to parse rustup version")
-        }
-        None => eyre::bail!("failed to get rustup version"),
-    }
-}
-
 pub fn install_toolchain(toolchain: &QualifiedToolchain, msg_info: &mut MessageInfo) -> Result<()> {
-    let mut command = rustup_command(msg_info, false);
     let toolchain = toolchain.to_string();
-    command.args(&["toolchain", "add", &toolchain, "--profile", "minimal"]);
-    if version(msg_info)? >= semver::Version::new(1, 25, 0) {
-        command.arg("--force-non-host");
-    }
-    command
+    rustup_command(msg_info, false)
+        .args(&["toolchain", "add", &toolchain, "--profile", "minimal"])
         .run(msg_info, false)
         .wrap_err_with(|| format!("couldn't install toolchain `{toolchain}`"))
 }
diff --git a/xtask/src/codegen.rs b/xtask/src/codegen.rs
index 363ac15..d686aca 100644
--- a/xtask/src/codegen.rs
+++ b/xtask/src/codegen.rs
@@ -28,7 +28,7 @@ pub static PROVIDED_IMAGES: &[ProvidedImage] = &["##,
 
     for image_target in get_matrix()
         .iter()
-        .filter(|i| i.to_image_target().is_toolchain_image())
+        .filter(|i| i.to_image_target().is_standard_target_image())
     {
         write!(
             &mut images,
diff --git a/xtask/src/util.rs b/xtask/src/util.rs
index c761163..8c06295 100644
--- a/xtask/src/util.rs
+++ b/xtask/src/util.rs
@@ -146,13 +146,7 @@ impl ImageTarget {
 
     /// Determine if this target is a "normal" target for a triplet
     pub fn is_standard_target_image(&self) -> bool {
-        !matches!(self.name.as_ref(), "cross" | "zig") && self.has_ci_image()
-    }
-
-    // this exists solely for zig, since we also want it as a provided target.
-    /// Determine if this target has a toolchain image
-    pub fn is_toolchain_image(&self) -> bool {
-        !matches!(self.name.as_ref(), "cross") && self.has_ci_image()
+        self.name != "cross" && self.has_ci_image()
     }
 
     /// Determine if this target needs to interact with the project root.


Test patch:
diff --git a/ci/test-zig-image.sh b/ci/test-zig-image.sh
deleted file mode 100755
index 2468b45..0000000
--- a/ci/test-zig-image.sh
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/usr/bin/env bash
-# shellcheck disable=SC2086,SC1091,SC1090
-
-set -x
-set -eo pipefail
-
-# NOTE: "${@}" is an unbound variable for bash 3.2, which is the
-# installed version on macOS. likewise, "${var[@]}" is an unbound
-# error if var is an empty array.
-
-ci_dir=$(dirname "${BASH_SOURCE[0]}")
-ci_dir=$(realpath "${ci_dir}")
-. "${ci_dir}"/shared.sh
-
-# zig cc is very slow: only use a few targets.
-TARGETS=(
-    "aarch64-unknown-linux-gnu"
-    "aarch64-unknown-linux-musl"
-    "i586-unknown-linux-gnu"
-    "i586-unknown-linux-musl"
-)
-
-# on CI, it sets `CROSS_TARGET_ZIG_IMAGE` rather than `CROSS_TARGET_ZIG_IMAGE`
-if [[ -n "${CROSS_TARGET_ZIG_IMAGE}" ]]; then
-    export CROSS_BUILD_ZIG_IMAGE="${CROSS_TARGET_ZIG_IMAGE}"
-    unset CROSS_TARGET_ZIG_IMAGE
-fi
-
-main() {
-    export CROSS_BUILD_ZIG=1
-
-    local td=
-    local target=
-
-    retry cargo fetch
-    cargo build
-    export CROSS="${PROJECT_HOME}/target/debug/cross"
-
-    td="$(mktemp -d)"
-    git clone --depth 1 https://github.com/cross-rs/rust-cpp-hello-word "${td}"
-    pushd "${td}"
-
-    for target in "${TARGETS[@]}"; do
-        CROSS_CONTAINER_ENGINE="${CROSS_ENGINE}" "${CROSS}" build --target "${target}" --verbose
-        # note: ensure #724 doesn't replicate during CI.
-        # https://github.com/cross-rs/cross/issues/724
-        cargo clean
-    done
-
-    popd
-    rm -rf "${td}"
-}
-
-main "${@}"