Repository: cross-rs/cross
Pull request #1021 (2022-09-12 17:32:46)

Allow CI without requiring targets to be built/tested.
Co-authored-by: Emil Gardström <emil.gardstrom@gmail.com>

Alexhuszagh: Related to https://github.com/cross-rs/cross/pull/1019#issuecomment-1243832924, and due to certain spurious CI failures when we're merely changing documentation, CI, or other items in the repository.
Alexhuszagh: bors try
Alexhuszagh: Currently `bors try` isn't working, so I might be checking if a label is set the wrong way.
bors[bot]: ## try

Build failed:
  * [conclusion](https://github.com/cross-rs/cross/actions/runs/3039334578/jobs/4894185268)
Alexhuszagh: I think this is a lot easier now since the `bors try --none` was provided, so we can essentially use the same logic if there's a `no-ci-targets` label.
Alexhuszagh: bors try
bors[bot]: ## try

Build failed:
  * [conclusion](https://github.com/cross-rs/cross/actions/runs/3237361805/jobs/5304456474)
Alexhuszagh: bors try
bors[bot]: ## try

Build succeeded:
  * [conclusion](https://github.com/cross-rs/cross/actions/runs/3237547686/jobs/5304867376)
Alexhuszagh: bors try
bors[bot]: ## try

Build failed:
  * [conclusion](https://github.com/cross-rs/cross/actions/runs/3237621145/jobs/5304950179)
Alexhuszagh: bors try --none
bors[bot]: ## try

Build succeeded:
  * [conclusion](https://github.com/cross-rs/cross/actions/runs/3237852197/jobs/5305530088)
Alexhuszagh: bors try
Alexhuszagh: This isn't working anyway, even if it works locally for me... Still producing the full matrix:

https://github.com/cross-rs/cross/actions/runs/3251818420/jobs/5337315491#step:4:8
bors[bot]: ## try

Build failed:
  * [conclusion](https://github.com/cross-rs/cross/actions/runs/3251818420/jobs/5337548422)
Emilgardis: can I push to this branch? I think I have the solution
Alexhuszagh: > can I push to this branch? I think I have the solution

Definitely. Any working solution is appreciated.
Emilgardis: bors try
Emilgardis: well, that makes sense

```
Error: 
   0: `gh pr view 1021 --json labels` failed with exit status: 4

Location:
   /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/core/src/convert/mod.rs:550

Stderr:
   gh: To use GitHub CLI in a GitHub Actions workflow, set the GH_TOKEN environment variable. Example:
     env:
       GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```
Emilgardis: bors try
bors[bot]: ## try

Already running a review
Emilgardis: bors try-

bors try
bors[bot]: ## try

Build succeeded:
  * [conclusion](https://github.com/cross-rs/cross/actions/runs/3252500479/jobs/5338875763)
Emilgardis: bors try
Emilgardis: canceled, seems to work now.

I think the only issue was the `GH_TOKEN`, I thought the issue was the env var
bors[bot]: ## try

Build failed:
  * [conclusion](https://github.com/cross-rs/cross/actions/runs/3252558350/jobs/5338931270)
Emilgardis: do we think this is ready? @Alexhuszagh 
Alexhuszagh: bors try --target x86_64-unknown-linux-gnu
(Will cancel)
bors[bot]: ## try

Build failed:
  * [conclusion](https://github.com/cross-rs/cross/actions/runs/3321324926/jobs/5488934193)
Alexhuszagh: bors try-
bors try --target x86_64-unknown-linux-gnu
bors[bot]: ## try

Build succeeded:
  * [conclusion](https://github.com/cross-rs/cross/actions/runs/3321390403/jobs/5489169375)
Alexhuszagh:  bors try --target x86_64-unknown-linux-gnu
Emilgardis: needs a proper co-authored by, the current message will only ping me :3 

> ﻿Co-authored-by: Emil Gardström <emil.gardstrom@gmail.com>
Alexhuszagh: I've fixed the co-author, so I think this is ready.
bors[bot]: Build failed:
  * [conclusion](https://github.com/cross-rs/cross/actions/runs/3347252419/jobs/5545189992)
bors[bot]: Build failed:
  * [conclusion](https://github.com/cross-rs/cross/actions/runs/3362021936/jobs/5573388155)
Emilgardis: ugh

```diff
diff --git a/xtask/src/ci/target_matrix.rs b/xtask/src/ci/target_matrix.rs
index 2f2f455..69bcb52 100644
--- a/xtask/src/ci/target_matrix.rs
+++ b/xtask/src/ci/target_matrix.rs
@@ -61,7 +61,7 @@ fn parse_gh_labels(pr: &str) -> cross::Result<Vec<String>> {
     }
     eyre::ensure!(
         pr.chars().all(|c| c.is_ascii_digit()),
-        "pr should be a number`"
+        "pr should be a number, got {:?}", pr
     );
     let stdout = Command::new("gh")
         .args(["pr", "view", pr, "--json", "labels"])
@@ -89,7 +89,7 @@ fn process_bors_message(message: &str) -> cross::Result<(Vec<&str>, TargetMatrix
         Ok((vec![pr], app))
     } else if let Some(message) = message.strip_prefix("Merge") {
         Ok((
-            message.split(" #").skip(1).map(|x| x.trim_end()).collect(),
+            message.lines().next().unwrap_or_default().split(" #").skip(1).collect(),
             TargetMatrixArgs::default(),
         ))
     } else {
@@ -263,11 +263,11 @@ mod tests {
     #[test]
     fn prs() {
         assert_eq!(
-            process_bors_message("Merge #1337\n").unwrap().0,
+            process_bors_message("Merge #1337\n1337: merge").unwrap().0,
             vec!["1337"]
         );
         assert_eq!(
-            process_bors_message("Merge #1337 #42\n").unwrap().0,
+            process_bors_message("Merge #1337 #42\n1337: merge\n42: merge 2").unwrap().0,
             vec!["1337", "42"]
         );
         assert_eq!(
```

Patch:
diff --git a/.changes/1063.json b/.changes/1063.json
deleted file mode 100644
index 4d3a9cb..0000000
--- a/.changes/1063.json
+++ /dev/null
@@ -1,13 +0,0 @@
-[
-    {
-        "type": "changed",
-        "description": "changed musl targets to use static-pie linkage by default, consistent with Alpine.",
-        "breaking": true
-    },
-    {
-        "type": "fixed",
-        "description": "fixed C++ support for musl targets.",
-        "issues": [902],
-        "breaking": true
-    }
-]
diff --git a/.changes/1073.json b/.changes/1073.json
deleted file mode 100644
index 8cd67b9..0000000
--- a/.changes/1073.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-    "type": "added",
-    "description": "passthrough cross environment variables by default"
-}
diff --git a/.changes/1078.json b/.changes/1078.json
deleted file mode 100644
index bfecb4f..0000000
--- a/.changes/1078.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-    "type": "fixed",
-    "description": "Fix custom image names for images with a trailing '-' character.\ncustom images in packages with the `^[^0-9-].*([^A-Za-z_]*-)|(-[^A-Za-z_]*)$` package name pattern are now supported.",
-    "issues": [1077]
-}
diff --git a/.changes/1084.json b/.changes/1084.json
deleted file mode 100644
index 39d80ea..0000000
--- a/.changes/1084.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-    "type": "fixed",
-    "description": "fixed remote docker data volume paths on windows",
-    "issues": [1081]
-}
diff --git a/.changes/1085.json b/.changes/1085.json
deleted file mode 100644
index 373c306..0000000
--- a/.changes/1085.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-    "type": "added",
-    "description": "support custom toolchains without rustup."
-}
diff --git a/.changes/591-1095.json b/.changes/591-1095.json
deleted file mode 100644
index d85f46b..0000000
--- a/.changes/591-1095.json
+++ /dev/null
@@ -1,24 +0,0 @@
-[
-    {
-        "description": "update Ubuntu images to 20.04 LTS.",
-        "type": "changed",
-        "breaking": true,
-        "issues": [417, 517, 556, 616]
-    },
-    {
-        "description": "remove Linux image from `mips-unknown-linux-gnu`.",
-        "type": "removed",
-        "breaking": true
-    },
-    {
-        "type": "changed",
-        "description": "upgraded most linux images to use a 5.x kernel instead of a 4.x kernel.",
-        "breaking": true
-    },
-    {
-        "type": "changed",
-        "description": "updated powerpc64, riscv64, and sparc64 *-linux-gnu images to use a 6.x kernel instead of a 4.x kernel.",
-        "breaking": true,
-        "issues": [1094]
-    }
-]
diff --git a/.changes/591.json b/.changes/591.json
new file mode 100644
index 0000000..83b03ca
--- /dev/null
+++ b/.changes/591.json
@@ -0,0 +1,13 @@
+[
+    {
+        "description": "update Ubuntu images to 20.04 LTS.",
+        "type": "changed",
+        "breaking": true,
+        "issues": [417, 517, 556, 616]
+    },
+    {
+        "description": "remove Linux image from `mips-unknown-linux-gnu`.",
+        "type": "removed",
+        "breaking": true
+    }
+]
diff --git a/.editorconfig b/.editorconfig
deleted file mode 100644
index 689711a..0000000
--- a/.editorconfig
+++ /dev/null
@@ -1,25 +0,0 @@
-root = true
-
-[*]
-end_of_line = lf
-insert_final_newline = true
-
-[*.{rs,py,sh,md,toml,yml,js}]
-charset = utf-8
-
-[*.{rs,py,sh,yml,js}]
-trim_trailing_whitespace = true
-
-[*.{rs,py,sh}]
-indent_style = space
-indent_size = 4
-
-[*.yml]
-indent_style = space
-indent_size = 2
-
-[Dockerfile.*]
-charset = utf-8
-trim_trailing_whitespace = true
-indent_style = space
-indent_size = 4
diff --git a/.gitattributes b/.gitattributes
deleted file mode 100644
index 39a109d..0000000
--- a/.gitattributes
+++ /dev/null
@@ -1,1 +0,0 @@
-Dockerfile.* linguist-language=Dockerfile
diff --git a/.github/ISSUE_TEMPLATE/b_issue_report.yml b/.github/ISSUE_TEMPLATE/b_issue_report.yml
index dae86c8..398616b 100644
--- a/.github/ISSUE_TEMPLATE/b_issue_report.yml
+++ b/.github/ISSUE_TEMPLATE/b_issue_report.yml
@@ -90,7 +90,7 @@ body:
         - label: Windows
         - label: Linux / BSD
         - label: other OS (specify in description)
-
+  
   - type: checkboxes
     id: host-arch
     attributes:
diff --git a/.github/ISSUE_TEMPLATE/z_feature_request.yml b/.github/ISSUE_TEMPLATE/z_feature_request.yml
index b194f9c..454bc10 100644
--- a/.github/ISSUE_TEMPLATE/z_feature_request.yml
+++ b/.github/ISSUE_TEMPLATE/z_feature_request.yml
@@ -20,7 +20,7 @@ body:
         description: |
             Write a description of what your feature would do.
             If you have an idea how to solve this, feel free to leave a comment on the feature request after creating it.
-
+            
             If you have tried solved this but couldn't, explain what you tried and how or why it didn't work. We want to help!
         placeholder: |
             Examples:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 35d6081..c024c09 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -97,6 +97,7 @@ jobs:
         env:
           COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
           COMMIT_AUTHOR: ${{ github.event.head_commit.author.username }}
+          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
 
   build:
     name: target (${{ matrix.pretty }},${{ matrix.os }})
diff --git a/ci/build_release.sh b/ci/build_release.sh
index 7e3b899..858248d 100755
--- a/ci/build_release.sh
+++ b/ci/build_release.sh
@@ -19,7 +19,7 @@ rm -rf "${BUILD_BINARIESDIRECTORY}"
 mkdir "${BUILD_BINARIESDIRECTORY}"
 
 if [[ -f "target/${TARGET}/release/cross.exe" ]]; then
-    mv "target/${TARGET}/release/cross.exe" "${BUILD_BINARIESDIRECTORY}/"
+  mv "target/${TARGET}/release/cross.exe" "${BUILD_BINARIESDIRECTORY}/"
 else
-    mv "target/${TARGET}/release/cross" "${BUILD_BINARIESDIRECTORY}/"
+  mv "target/${TARGET}/release/cross" "${BUILD_BINARIESDIRECTORY}/"
 fi
diff --git a/ci/shared.sh b/ci/shared.sh
index 39f8824..c6c736c 100755
--- a/ci/shared.sh
+++ b/ci/shared.sh
@@ -8,43 +8,43 @@ CARGO_TMP_DIR="${PROJECT_HOME}/target/tmp"
 export CARGO_TMP_DIR
 
 if [[ -n "${CROSS_CONTAINER_ENGINE}" ]]; then
-    CROSS_ENGINE="${CROSS_CONTAINER_ENGINE}"
+  CROSS_ENGINE="${CROSS_CONTAINER_ENGINE}"
 elif command -v docker >/dev/null 2>&1; then
-    CROSS_ENGINE=docker
+  CROSS_ENGINE=docker
 else
-    CROSS_ENGINE=podman
+  CROSS_ENGINE=podman
 fi
 export CROSS_ENGINE
 
 function retry {
-    local tries="${TRIES-5}"
-    local timeout="${TIMEOUT-1}"
-    local try=0
-    local exit_code=0
+  local tries="${TRIES-5}"
+  local timeout="${TIMEOUT-1}"
+  local try=0
+  local exit_code=0
 
-    while (( try < tries )); do
-        if "${@}"; then
-            return 0
-        else
-            exit_code=$?
-        fi
+  while (( try < tries )); do
+    if "${@}"; then
+      return 0
+    else
+      exit_code=$?
+    fi
 
-        sleep "${timeout}"
-        echo "Retrying ..." 1>&2
-        try=$(( try + 1 ))
-        timeout=$(( timeout * 2 ))
-    done
+    sleep "${timeout}"
+    echo "Retrying ..." 1>&2
+    try=$(( try + 1 ))
+    timeout=$(( timeout * 2 ))
+  done
 
-    return ${exit_code}
+  return ${exit_code}
 }
 
 function mkcargotemp {
-    local td=
-    td="$CARGO_TMP_DIR"/$(mktemp -u "${@}" | xargs basename)
-    mkdir -p "$td"
-    echo '# Cargo.toml
-    [workspace]
-    members = ["'"$(basename "$td")"'"]
-    ' > "$CARGO_TMP_DIR"/Cargo.toml
-    echo "$td"
+  local td=
+  td="$CARGO_TMP_DIR"/$(mktemp -u "${@}" | xargs basename)
+  mkdir -p "$td"
+  echo '# Cargo.toml
+  [workspace]
+  members = ["'"$(basename "$td")"'"]
+   ' > "$CARGO_TMP_DIR"/Cargo.toml
+  echo "$td"
 }
diff --git a/docker/Dockerfile.aarch64-linux-android b/docker/Dockerfile.aarch64-linux-android
index 412fe0d..ea85d5d 100644
--- a/docker/Dockerfile.aarch64-linux-android
+++ b/docker/Dockerfile.aarch64-linux-android
@@ -20,8 +20,7 @@ RUN /android-system.sh arm64
 COPY qemu.sh /
 RUN /qemu.sh aarch64
 
-ENV CROSS_SYSROOT=/android-ndk/sysroot
-RUN cp $CROSS_SYSROOT/usr/lib/aarch64-linux-android/28/libz.so /system/lib/
+RUN cp /android-ndk/sysroot/usr/lib/aarch64-linux-android/28/libz.so /system/lib/
 
 COPY android-runner /
 
@@ -31,8 +30,8 @@ ENV CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER=aarch64-linux-android-gcc \
     CARGO_TARGET_AARCH64_LINUX_ANDROID_RUNNER="/android-runner aarch64" \
     CC_aarch64_linux_android=aarch64-linux-android-gcc \
     CXX_aarch64_linux_android=aarch64-linux-android-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_aarch64_linux_android="--sysroot=$CROSS_SYSROOT" \
-    DEP_Z_INCLUDE="$CROSS_SYSROOT/usr/include"/ \
+    BINDGEN_EXTRA_CLANG_ARGS_aarch64_linux_android="--sysroot=/android-ndk/sysroot" \
+    DEP_Z_INCLUDE=/android-ndk/sysroot/usr/include/ \
     RUST_TEST_THREADS=1 \
     HOME=/tmp/ \
     TMPDIR=/tmp/ \
diff --git a/docker/Dockerfile.aarch64-unknown-linux-gnu b/docker/Dockerfile.aarch64-unknown-linux-gnu
index a703514..2480cd6 100644
--- a/docker/Dockerfile.aarch64-unknown-linux-gnu
+++ b/docker/Dockerfile.aarch64-unknown-linux-gnu
@@ -30,12 +30,11 @@ RUN /linux-image.sh aarch64
 
 COPY linux-runner base-runner.sh /
 
-ENV CROSS_SYSROOT=/usr/aarch64-linux-gnu
 ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \
     CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER="/linux-runner aarch64" \
     CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc \
     CXX_aarch64_unknown_linux_gnu=aarch64-linux-gnu-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_aarch64_unknown_linux_gnu="--sysroot=$CROSS_SYSROOT" \
-    QEMU_LD_PREFIX="$CROSS_SYSROOT" \
+    BINDGEN_EXTRA_CLANG_ARGS_aarch64_unknown_linux_gnu="--sysroot=/usr/aarch64-linux-gnu" \
+    QEMU_LD_PREFIX=/usr/aarch64-linux-gnu \
     RUST_TEST_THREADS=1 \
     PKG_CONFIG_PATH="/usr/lib/aarch64-linux-gnu/pkgconfig/:${PKG_CONFIG_PATH}"
diff --git a/docker/Dockerfile.aarch64-unknown-linux-gnu.centos b/docker/Dockerfile.aarch64-unknown-linux-gnu.centos
index cc96418..5fef9a3 100644
--- a/docker/Dockerfile.aarch64-unknown-linux-gnu.centos
+++ b/docker/Dockerfile.aarch64-unknown-linux-gnu.centos
@@ -29,12 +29,12 @@ COPY linux-runner base-runner.sh /
 
 COPY aarch64-linux-gnu-glibc.sh /
 RUN /aarch64-linux-gnu-glibc.sh
+   
 
-ENV CROSS_SYSROOT=/usr/aarch64-linux-gnu
 ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \
     CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER="/linux-runner aarch64" \
     CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc \
     CXX_aarch64_unknown_linux_gnu=aarch64-linux-gnu-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_aarch64_unknown_linux_gnu="--sysroot=$CROSS_SYSROOT" \
-    QEMU_LD_PREFIX="$CROSS_SYSROOT" \
+    BINDGEN_EXTRA_CLANG_ARGS_aarch64_unknown_linux_gnu="--sysroot=/usr/aarch64-linux-gnu" \
+    QEMU_LD_PREFIX=/usr/aarch64-linux-gnu \
     RUST_TEST_THREADS=1
diff --git a/docker/Dockerfile.aarch64-unknown-linux-musl b/docker/Dockerfile.aarch64-unknown-linux-musl
index 98c374e..7dc97b7 100644
--- a/docker/Dockerfile.aarch64-unknown-linux-musl
+++ b/docker/Dockerfile.aarch64-unknown-linux-musl
@@ -16,9 +16,9 @@ RUN /qemu.sh aarch64
 COPY musl.sh /
 RUN /musl.sh TARGET=aarch64-linux-musl
 
-ENV CROSS_SYSROOT=/usr/local/aarch64-linux-musl
+ENV CROSS_MUSL_SYSROOT=/usr/local/aarch64-linux-musl
 COPY musl-symlink.sh /
-RUN /musl-symlink.sh $CROSS_SYSROOT aarch64
+RUN /musl-symlink.sh $CROSS_MUSL_SYSROOT aarch64
 
 COPY aarch64-linux-musl-gcc.sh /usr/bin/
 COPY rustc_info.sh /
@@ -29,6 +29,6 @@ ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_LINKER=aarch64-linux-musl-gcc.sh \
     CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_RUNNER="/qemu-runner aarch64" \
     CC_aarch64_unknown_linux_musl=aarch64-linux-musl-gcc \
     CXX_aarch64_unknown_linux_musl=aarch64-linux-musl-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_aarch64_unknown_linux_musl="--sysroot=$CROSS_SYSROOT" \
-    QEMU_LD_PREFIX="$CROSS_SYSROOT" \
+    BINDGEN_EXTRA_CLANG_ARGS_aarch64_unknown_linux_musl="--sysroot=$CROSS_MUSL_SYSROOT" \
+    QEMU_LD_PREFIX=$CROSS_MUSL_SYSROOT \
     RUST_TEST_THREADS=1
diff --git a/docker/Dockerfile.arm-linux-androideabi b/docker/Dockerfile.arm-linux-androideabi
index ac35c47..3faae94 100644
--- a/docker/Dockerfile.arm-linux-androideabi
+++ b/docker/Dockerfile.arm-linux-androideabi
@@ -20,8 +20,7 @@ RUN /android-system.sh arm
 COPY qemu.sh /
 RUN /qemu.sh arm
 
-ENV CROSS_SYSROOT=/android-ndk/sysroot
-RUN cp $CROSS_SYSROOT/usr/lib/arm-linux-androideabi/28/libz.so /system/lib/
+RUN cp /android-ndk/sysroot/usr/lib/arm-linux-androideabi/28/libz.so /system/lib/
 
 COPY android-runner /
 
@@ -31,8 +30,8 @@ ENV CARGO_TARGET_ARM_LINUX_ANDROIDEABI_LINKER=arm-linux-androideabi-gcc \
     CARGO_TARGET_ARM_LINUX_ANDROIDEABI_RUNNER="/android-runner arm" \
     CC_arm_linux_androideabi=arm-linux-androideabi-gcc \
     CXX_arm_linux_androideabi=arm-linux-androideabi-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_arm_linux_androideabi="--sysroot=$CROSS_SYSROOT" \
-    DEP_Z_INCLUDE="$CROSS_SYSROOT/usr/include/" \
+    BINDGEN_EXTRA_CLANG_ARGS_arm_linux_androideabi="--sysroot=/android-ndk/sysroot" \
+    DEP_Z_INCLUDE=/android-ndk/sysroot/usr/include/ \
     RUST_TEST_THREADS=1 \
     HOME=/tmp/ \
     TMPDIR=/tmp/ \
diff --git a/docker/Dockerfile.arm-unknown-linux-gnueabi b/docker/Dockerfile.arm-unknown-linux-gnueabi
index cb8162f..db370a6 100644
--- a/docker/Dockerfile.arm-unknown-linux-gnueabi
+++ b/docker/Dockerfile.arm-unknown-linux-gnueabi
@@ -24,12 +24,11 @@ RUN /qemu.sh arm
 
 COPY qemu-runner base-runner.sh /
 
-ENV CROSS_SYSROOT=/usr/arm-linux-gnueabi
 ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_LINKER=arm-linux-gnueabi-gcc \
     CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_RUNNER="/qemu-runner arm" \
     CC_arm_unknown_linux_gnueabi=arm-linux-gnueabi-gcc \
     CXX_arm_unknown_linux_gnueabi=arm-linux-gnueabi-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_arm_unknown_linux_gnueabi="--sysroot=$CROSS_SYSROOT" \
-    QEMU_LD_PREFIX="$CROSS_SYSROOT" \
+    BINDGEN_EXTRA_CLANG_ARGS_arm_unknown_linux_gnueabi="--sysroot=/usr/arm-linux-gnueabi" \
+    QEMU_LD_PREFIX=/usr/arm-linux-gnueabi \
     RUST_TEST_THREADS=1 \
     PKG_CONFIG_PATH="/usr/lib/arm-linux-gnueabi/pkgconfig/:${PKG_CONFIG_PATH}"
diff --git a/docker/Dockerfile.arm-unknown-linux-gnueabihf b/docker/Dockerfile.arm-unknown-linux-gnueabihf
index 53b7976..e5217c3 100644
--- a/docker/Dockerfile.arm-unknown-linux-gnueabihf
+++ b/docker/Dockerfile.arm-unknown-linux-gnueabihf
@@ -25,11 +25,10 @@ RUN /qemu.sh arm
 
 COPY qemu-runner base-runner.sh /
 
-ENV CROSS_SYSROOT=/x-tools/arm-unknown-linux-gnueabihf/arm-unknown-linux-gnueabihf/sysroot/
 ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-unknown-linux-gnueabihf-gcc \
     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=$CROSS_SYSROOT" \
-    QEMU_LD_PREFIX="$CROSS_SYSROOT" \
+    BINDGEN_EXTRA_CLANG_ARGS_arm_unknown_linux_gnueabihf="--sysroot=/x-tools/arm-unknown-linux-gnueabihf/arm-unknown-linux-gnueabihf/sysroot/" \
+    QEMU_LD_PREFIX=/x-tools/arm-unknown-linux-gnueabihf/arm-unknown-linux-gnueabihf/sysroot/ \
     RUST_TEST_THREADS=1
diff --git a/docker/Dockerfile.arm-unknown-linux-musleabi b/docker/Dockerfile.arm-unknown-linux-musleabi
index 90c57fc..1fbbe8e 100644
--- a/docker/Dockerfile.arm-unknown-linux-musleabi
+++ b/docker/Dockerfile.arm-unknown-linux-musleabi
@@ -20,9 +20,9 @@ RUN /musl.sh \
                       --with-float=soft \
                       --with-mode=arm"
 
-ENV CROSS_SYSROOT=/usr/local/arm-linux-musleabi
+ENV CROSS_MUSL_SYSROOT=/usr/local/arm-linux-musleabi
 COPY musl-symlink.sh /
-RUN /musl-symlink.sh $CROSS_SYSROOT arm
+RUN /musl-symlink.sh $CROSS_MUSL_SYSROOT arm
 
 COPY qemu-runner base-runner.sh /
 
@@ -30,6 +30,6 @@ ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_MUSLEABI_LINKER=arm-linux-musleabi-gcc \
     CARGO_TARGET_ARM_UNKNOWN_LINUX_MUSLEABI_RUNNER="/qemu-runner arm" \
     CC_arm_unknown_linux_musleabi=arm-linux-musleabi-gcc \
     CXX_arm_unknown_linux_musleabi=arm-linux-musleabi-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_arm_unknown_linux_musleabi="--sysroot=$CROSS_SYSROOT" \
-    QEMU_LD_PREFIX="$CROSS_SYSROOT" \
+    BINDGEN_EXTRA_CLANG_ARGS_arm_unknown_linux_musleabi="--sysroot=$CROSS_MUSL_SYSROOT" \
+    QEMU_LD_PREFIX=$CROSS_MUSL_SYSROOT \
     RUST_TEST_THREADS=1
diff --git a/docker/Dockerfile.arm-unknown-linux-musleabihf b/docker/Dockerfile.arm-unknown-linux-musleabihf
index 509742a..e7ae937 100644
--- a/docker/Dockerfile.arm-unknown-linux-musleabihf
+++ b/docker/Dockerfile.arm-unknown-linux-musleabihf
@@ -21,9 +21,9 @@ RUN /musl.sh \
                       --with-float=hard \
                       --with-mode=arm"
 
-ENV CROSS_SYSROOT=/usr/local/arm-linux-musleabihf
+ENV CROSS_MUSL_SYSROOT=/usr/local/arm-linux-musleabihf
 COPY musl-symlink.sh /
-RUN /musl-symlink.sh $CROSS_SYSROOT armhf
+RUN /musl-symlink.sh $CROSS_MUSL_SYSROOT armhf
 
 COPY qemu-runner base-runner.sh /
 
@@ -31,6 +31,6 @@ ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_MUSLEABIHF_LINKER=arm-linux-musleabihf-gcc \
     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_SYSROOT" \
-    QEMU_LD_PREFIX="$CROSS_SYSROOT" \
+    BINDGEN_EXTRA_CLANG_ARGS_arm_unknown_linux_musleabihf="--sysroot=$CROSS_MUSL_SYSROOT" \
+    QEMU_LD_PREFIX=$CROSS_MUSL_SYSROOT \
     RUST_TEST_THREADS=1
diff --git a/docker/Dockerfile.armv5te-unknown-linux-gnueabi b/docker/Dockerfile.armv5te-unknown-linux-gnueabi
index fe974f6..91ab30d 100644
--- a/docker/Dockerfile.armv5te-unknown-linux-gnueabi
+++ b/docker/Dockerfile.armv5te-unknown-linux-gnueabi
@@ -25,12 +25,11 @@ RUN /qemu.sh arm
 
 COPY qemu-runner base-runner.sh /
 
-ENV CROSS_SYSROOT=/usr/arm-linux-gnueabi
 ENV CARGO_TARGET_ARMV5TE_UNKNOWN_LINUX_GNUEABI_LINKER=arm-linux-gnueabi-gcc \
     CARGO_TARGET_ARMV5TE_UNKNOWN_LINUX_GNUEABI_RUNNER="/qemu-runner arm" \
     CC_armv5te_unknown_linux_gnueabi=arm-linux-gnueabi-gcc \
     CXX_armv5te_unknown_linux_gnueabi=arm-linux-gnueabi-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_armv5te_unknown_linux_gnueabi="--sysroot=$CROSS_SYSROOT" \
-    QEMU_LD_PREFIX="$CROSS_SYSROOT" \
+    BINDGEN_EXTRA_CLANG_ARGS_armv5te_unknown_linux_gnueabi="--sysroot=/usr/arm-linux-gnueabi" \
+    QEMU_LD_PREFIX=/usr/arm-linux-gnueabi \
     RUST_TEST_THREADS=1 \
     PKG_CONFIG_PATH="/usr/lib/arm-linux-gnueabi/pkgconfig/:${PKG_CONFIG_PATH}"
diff --git a/docker/Dockerfile.armv5te-unknown-linux-musleabi b/docker/Dockerfile.armv5te-unknown-linux-musleabi
index 6688ded..5e8ef3b 100644
--- a/docker/Dockerfile.armv5te-unknown-linux-musleabi
+++ b/docker/Dockerfile.armv5te-unknown-linux-musleabi
@@ -20,9 +20,9 @@ RUN /musl.sh \
                       --with-float=soft \
                       --with-mode=arm"
 
-ENV CROSS_SYSROOT=/usr/local/arm-linux-musleabi
+ENV CROSS_MUSL_SYSROOT=/usr/local/arm-linux-musleabi
 COPY musl-symlink.sh /
-RUN /musl-symlink.sh $CROSS_SYSROOT arm
+RUN /musl-symlink.sh $CROSS_MUSL_SYSROOT arm
 
 COPY qemu-runner base-runner.sh /
 
@@ -33,6 +33,6 @@ ENV CARGO_TARGET_ARMV5TE_UNKNOWN_LINUX_MUSLEABI_LINKER=arm-linux-musleabi-gcc.sh
     CARGO_TARGET_ARMV5TE_UNKNOWN_LINUX_MUSLEABI_RUNNER="/qemu-runner arm" \
     CC_armv5te_unknown_linux_musleabi=arm-linux-musleabi-gcc \
     CXX_armv5te_unknown_linux_musleabi=arm-linux-musleabi-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_armv5te_unknown_linux_musleabi="--sysroot=$CROSS_SYSROOT" \
-    QEMU_LD_PREFIX="$CROSS_SYSROOT" \
+    BINDGEN_EXTRA_CLANG_ARGS_armv5te_unknown_linux_musleabi="--sysroot=$CROSS_MUSL_SYSROOT" \
+    QEMU_LD_PREFIX=$CROSS_MUSL_SYSROOT \
     RUST_TEST_THREADS=1
diff --git a/docker/Dockerfile.armv7-linux-androideabi b/docker/Dockerfile.armv7-linux-androideabi
index 6d226c4..3b2b276 100644
--- a/docker/Dockerfile.armv7-linux-androideabi
+++ b/docker/Dockerfile.armv7-linux-androideabi
@@ -20,8 +20,7 @@ RUN /android-system.sh arm
 COPY qemu.sh /
 RUN /qemu.sh arm
 
-ENV CROSS_SYSROOT=/android-ndk/sysroot
-RUN cp $CROSS_SYSROOT/usr/lib/arm-linux-androideabi/28/libz.so /system/lib/
+RUN cp /android-ndk/sysroot/usr/lib/arm-linux-androideabi/28/libz.so /system/lib/
 
 COPY android-runner /
 
@@ -31,8 +30,8 @@ ENV CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER=arm-linux-androideabi-gcc \
     CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_RUNNER="/android-runner arm" \
     CC_armv7_linux_androideabi=arm-linux-androideabi-gcc \
     CXX_armv7_linux_androideabi=arm-linux-androideabi-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_armv7_linux_androideabi="--sysroot=$CROSS_SYSROOT" \
-    DEP_Z_INCLUDE="$CROSS_SYSROOT/usr/include/" \
+    BINDGEN_EXTRA_CLANG_ARGS_armv7_linux_androideabi="--sysroot=/android-ndk/sysroot" \
+    DEP_Z_INCLUDE=/android-ndk/sysroot/usr/include/ \
     RUST_TEST_THREADS=1 \
     HOME=/tmp/ \
     TMPDIR=/tmp/ \
diff --git a/docker/Dockerfile.armv7-unknown-linux-gnueabi b/docker/Dockerfile.armv7-unknown-linux-gnueabi
index a6eafdc..7704338 100644
--- a/docker/Dockerfile.armv7-unknown-linux-gnueabi
+++ b/docker/Dockerfile.armv7-unknown-linux-gnueabi
@@ -19,12 +19,11 @@ RUN /qemu.sh arm
 
 COPY qemu-runner base-runner.sh /
 
-ENV CROSS_SYSROOT=/usr/arm-linux-gnueabi
 ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABI_LINKER=arm-linux-gnueabi-gcc \
     CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABI_RUNNER="/qemu-runner armv7" \
     CC_armv7_unknown_linux_gnueabi=arm-linux-gnueabi-gcc \
     CXX_armv7_unknown_linux_gnueabi=arm-linux-gnueabi-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_armv7_unknown_linux_gnueabi="--sysroot=$CROSS_SYSROOT" \
-    QEMU_LD_PREFIX="$CROSS_SYSROOT" \
+    BINDGEN_EXTRA_CLANG_ARGS_armv7_unknown_linux_gnueabi="--sysroot=/usr/arm-linux-gnueabi" \
+    QEMU_LD_PREFIX=/usr/arm-linux-gnueabi \
     RUST_TEST_THREADS=1 \
     PKG_CONFIG_PATH="/usr/lib/arm-linux-gnueabi/pkgconfig/:${PKG_CONFIG_PATH}"
diff --git a/docker/Dockerfile.armv7-unknown-linux-gnueabihf b/docker/Dockerfile.armv7-unknown-linux-gnueabihf
index efe4829..f532b86 100644
--- a/docker/Dockerfile.armv7-unknown-linux-gnueabihf
+++ b/docker/Dockerfile.armv7-unknown-linux-gnueabihf
@@ -30,12 +30,11 @@ RUN /linux-image.sh armv7
 
 COPY linux-runner base-runner.sh /
 
-ENV CROSS_SYSROOT=/usr/arm-linux-gnueabihf
 ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \
     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=$CROSS_SYSROOT" \
-    QEMU_LD_PREFIX="$CROSS_SYSROOT" \
+    BINDGEN_EXTRA_CLANG_ARGS_armv7_unknown_linux_gnueabihf="--sysroot=/usr/arm-linux-gnueabihf" \
+    QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \
     RUST_TEST_THREADS=1 \
     PKG_CONFIG_PATH="/usr/lib/arm-linux-gnueabihf/pkgconfig/:${PKG_CONFIG_PATH}"
diff --git a/docker/Dockerfile.armv7-unknown-linux-musleabi b/docker/Dockerfile.armv7-unknown-linux-musleabi
index d3c5376..d03bddb 100644
--- a/docker/Dockerfile.armv7-unknown-linux-musleabi
+++ b/docker/Dockerfile.armv7-unknown-linux-musleabi
@@ -21,9 +21,9 @@ RUN /musl.sh \
                       --with-mode=thumb \
                       --with-mode=arm"
 
-ENV CROSS_SYSROOT=/usr/local/arm-linux-musleabi
+ENV CROSS_MUSL_SYSROOT=/usr/local/arm-linux-musleabi
 COPY musl-symlink.sh /
-RUN /musl-symlink.sh $CROSS_SYSROOT arm
+RUN /musl-symlink.sh $CROSS_MUSL_SYSROOT arm
 
 COPY qemu-runner base-runner.sh /
 
@@ -31,6 +31,6 @@ ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_MUSLEABI_LINKER=arm-linux-musleabi-gcc \
     CARGO_TARGET_ARMV7_UNKNOWN_LINUX_MUSLEABI_RUNNER="/qemu-runner armv7" \
     CC_armv7_unknown_linux_musleabi=arm-linux-musleabi-gcc \
     CXX_armv7_unknown_linux_musleabi=arm-linux-musleabi-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_armv7_unknown_linux_musleabi="--sysroot=$CROSS_SYSROOT" \
-    QEMU_LD_PREFIX="$CROSS_SYSROOT" \
+    BINDGEN_EXTRA_CLANG_ARGS_armv7_unknown_linux_musleabi="--sysroot=$CROSS_MUSL_SYSROOT" \
+    QEMU_LD_PREFIX=$CROSS_MUSL_SYSROOT \
     RUST_TEST_THREADS=1
diff --git a/docker/Dockerfile.armv7-unknown-linux-musleabihf b/docker/Dockerfile.armv7-unknown-linux-musleabihf
index 938afcb..fb85b02 100644
--- a/docker/Dockerfile.armv7-unknown-linux-musleabihf
+++ b/docker/Dockerfile.armv7-unknown-linux-musleabihf
@@ -21,9 +21,9 @@ RUN /musl.sh \
                       --with-mode=thumb \
                       --with-fpu=vfp"
 
-ENV CROSS_SYSROOT=/usr/local/arm-linux-musleabihf
+ENV CROSS_MUSL_SYSROOT=/usr/local/arm-linux-musleabihf
 COPY musl-symlink.sh /
-RUN /musl-symlink.sh $CROSS_SYSROOT armhf
+RUN /musl-symlink.sh $CROSS_MUSL_SYSROOT armhf
 
 COPY qemu-runner base-runner.sh /
 
@@ -31,6 +31,6 @@ ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_MUSLEABIHF_LINKER=arm-linux-musleabihf-gcc
     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_SYSROOT" \
-    QEMU_LD_PREFIX="$CROSS_SYSROOT" \
+    BINDGEN_EXTRA_CLANG_ARGS_armv7_unknown_linux_musleabihf="--sysroot=$CROSS_MUSL_SYSROOT" \
+    QEMU_LD_PREFIX=$CROSS_MUSL_SYSROOT \
     RUST_TEST_THREADS=1
diff --git a/docker/Dockerfile.asmjs-unknown-emscripten b/docker/Dockerfile.asmjs-unknown-emscripten
index ae4b06b..31781fc 100644
--- a/docker/Dockerfile.asmjs-unknown-emscripten
+++ b/docker/Dockerfile.asmjs-unknown-emscripten
@@ -11,10 +11,9 @@ RUN /cmake.sh
 COPY xargo.sh /
 RUN /xargo.sh
 
-RUN apt-get update && apt-get install --assume-yes --no-install-recommends \
-    libxml2 \
-    python
+RUN apt-get update && apt-get update && apt-get install --assume-yes --no-install-recommends \
+  libxml2 \
+  python
 
-ENV CROSS_SYSROOT=/emsdk/upstream/emscripten/cache/sysroot
 ENV CARGO_TARGET_ASMJS_UNKNOWN_EMSCRIPTEN_RUNNER=node \
-    BINDGEN_EXTRA_CLANG_ARGS_asmjs_unknown_emscripten="--sysroot=$CROSS_SYSROOT"
+  BINDGEN_EXTRA_CLANG_ARGS_asmjs_unknown_emscripten="--sysroot=/emsdk/upstream/emscripten/cache/sysroot"
diff --git a/docker/Dockerfile.i586-unknown-linux-gnu b/docker/Dockerfile.i586-unknown-linux-gnu
index 78da206..2f16f50 100644
--- a/docker/Dockerfile.i586-unknown-linux-gnu
+++ b/docker/Dockerfile.i586-unknown-linux-gnu
@@ -24,12 +24,11 @@ RUN /qemu.sh i386
 
 COPY qemu-runner base-runner.sh /
 
-ENV CROSS_SYSROOT=/usr/i686-linux-gnu
 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=$CROSS_SYSROOT" \
-    QEMU_LD_PREFIX="$CROSS_SYSROOT" \
+    BINDGEN_EXTRA_CLANG_ARGS_i586_unknown_linux_gnu="--sysroot=/usr/i686-linux-gnu" \
+    QEMU_LD_PREFIX=/usr/i686-linux-gnu \
     RUST_TEST_THREADS=1 \
     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 a3fa5bb..0c58f4e 100644
--- a/docker/Dockerfile.i586-unknown-linux-musl
+++ b/docker/Dockerfile.i586-unknown-linux-musl
@@ -16,9 +16,9 @@ RUN /musl.sh TARGET=i586-linux-musl
 COPY qemu.sh /
 RUN /qemu.sh i386
 
-ENV CROSS_SYSROOT=/usr/local/i586-linux-musl
+ENV CROSS_MUSL_SYSROOT=/usr/local/i586-linux-musl
 COPY musl-symlink.sh /
-RUN /musl-symlink.sh $CROSS_SYSROOT i386
+RUN /musl-symlink.sh $CROSS_MUSL_SYSROOT i386
 
 COPY qemu-runner base-runner.sh /
 
@@ -26,5 +26,5 @@ ENV CARGO_TARGET_I586_UNKNOWN_LINUX_MUSL_LINKER=i586-linux-musl-gcc \
     CARGO_TARGET_I586_UNKNOWN_LINUX_MUSL_RUNNER="/qemu-runner i586" \
     CC_i586_unknown_linux_musl=i586-linux-musl-gcc \
     CXX_i586_unknown_linux_musl=i586-linux-musl-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_i586_unknown_linux_musl="--sysroot=$CROSS_SYSROOT" \
-    QEMU_LD_PREFIX="$CROSS_SYSROOT"
+    BINDGEN_EXTRA_CLANG_ARGS_i586_unknown_linux_musl="--sysroot=$CROSS_MUSL_SYSROOT" \
+    QEMU_LD_PREFIX=$CROSS_MUSL_SYSROOT
diff --git a/docker/Dockerfile.i686-linux-android b/docker/Dockerfile.i686-linux-android
index 1f44118..14e987e 100644
--- a/docker/Dockerfile.i686-linux-android
+++ b/docker/Dockerfile.i686-linux-android
@@ -27,8 +27,7 @@ RUN /android-system.sh x86
 COPY qemu.sh /
 RUN /qemu.sh i386
 
-ENV CROSS_SYSROOT=/android-ndk/sysroot
-RUN cp $CROSS_SYSROOT/usr/lib/i686-linux-android/28/libz.so /system/lib/
+RUN cp /android-ndk/sysroot/usr/lib/i686-linux-android/28/libz.so /system/lib/
 
 COPY android-runner /
 
@@ -38,8 +37,8 @@ ENV CARGO_TARGET_I686_LINUX_ANDROID_LINKER=i686-linux-android-gcc \
     CARGO_TARGET_I686_LINUX_ANDROID_RUNNER="/android-runner i686" \
     CC_i686_linux_android=i686-linux-android-gcc \
     CXX_i686_linux_android=i686-linux-android-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_i686_linux_android="--sysroot=$CROSS_SYSROOT" \
-    DEP_Z_INCLUDE="$CROSS_SYSROOT/usr/include/" \
+    BINDGEN_EXTRA_CLANG_ARGS_i686_linux_android="--sysroot=/android-ndk/sysroot" \
+    DEP_Z_INCLUDE=/android-ndk/sysroot/usr/include/ \
     LIBZ_SYS_STATIC=1 \
     RUST_TEST_THREADS=1 \
     HOME=/tmp/ \
diff --git a/docker/Dockerfile.i686-pc-windows-gnu b/docker/Dockerfile.i686-pc-windows-gnu
index 91d671c..0d9da94 100644
--- a/docker/Dockerfile.i686-pc-windows-gnu
+++ b/docker/Dockerfile.i686-pc-windows-gnu
@@ -34,9 +34,8 @@ RUN mkdir -p /usr/lib/binfmt-support/ && \
 COPY windows-entry.sh /
 ENTRYPOINT ["/windows-entry.sh"]
 
-ENV CROSS_SYSROOT=/usr/i686-w64-mingw32
 ENV CARGO_TARGET_I686_PC_WINDOWS_GNU_LINKER=i686-w64-mingw32-gcc \
     CARGO_TARGET_I686_PC_WINDOWS_GNU_RUNNER=wine \
     CC_i686_pc_windows_gnu=i686-w64-mingw32-gcc-posix \
     CXX_i686_pc_windows_gnu=i686-w64-mingw32-g++-posix \
-    BINDGEN_EXTRA_CLANG_ARGS_i686_pc_windows_gnu="--sysroot=$CROSS_SYSROOT"
+    BINDGEN_EXTRA_CLANG_ARGS_i686_pc_windows_gnu="--sysroot=/usr/i686-w64-mingw32"
diff --git a/docker/Dockerfile.i686-unknown-freebsd b/docker/Dockerfile.i686-unknown-freebsd
index f31c2de..b84b874 100644
--- a/docker/Dockerfile.i686-unknown-freebsd
+++ b/docker/Dockerfile.i686-unknown-freebsd
@@ -21,9 +21,8 @@ RUN /freebsd-extras.sh
 
 COPY i686-unknown-freebsd12-gcc.sh /usr/bin
 
-ENV CROSS_SYSROOT=/usr/local/i686-unknown-freebsd12
 ENV CARGO_TARGET_I686_UNKNOWN_FREEBSD_LINKER=i686-unknown-freebsd12-gcc.sh \
     CC_i686_unknown_freebsd=i686-unknown-freebsd12-gcc \
     CXX_i686_unknown_freebsd=i686-unknown-freebsd12-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_i686_unknown_freebsd="--sysroot=$CROSS_SYSROOT" \
-    I686_UNKNOWN_FREEBSD_OPENSSL_DIR="$CROSS_SYSROOT"
+    BINDGEN_EXTRA_CLANG_ARGS_i686_unknown_freebsd="--sysroot=/usr/local/i686-unknown-freebsd12" \
+    I686_UNKNOWN_FREEBSD_OPENSSL_DIR=/usr/local/i686-unknown-freebsd12/
diff --git a/docker/Dockerfile.i686-unknown-linux-gnu b/docker/Dockerfile.i686-unknown-linux-gnu
index 21b3f18..aa6fe57 100644
--- a/docker/Dockerfile.i686-unknown-linux-gnu
+++ b/docker/Dockerfile.i686-unknown-linux-gnu
@@ -30,12 +30,11 @@ RUN /linux-image.sh i686
 
 COPY linux-runner base-runner.sh /
 
-ENV CROSS_SYSROOT=/usr/i686-linux-gnu
 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=$CROSS_SYSROOT" \
-    QEMU_LD_PREFIX="$CROSS_SYSROOT" \
+    BINDGEN_EXTRA_CLANG_ARGS_i686_unknown_linux_gnu="--sysroot=/usr/i686-linux-gnu" \
+    QEMU_LD_PREFIX=/usr/i686-linux-gnu \
     RUST_TEST_THREADS=1 \
     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 06def38..373ea9f 100644
--- a/docker/Dockerfile.i686-unknown-linux-musl
+++ b/docker/Dockerfile.i686-unknown-linux-musl
@@ -16,9 +16,9 @@ RUN /musl.sh TARGET=i686-linux-musl
 COPY qemu.sh /
 RUN /qemu.sh i386
 
-ENV CROSS_SYSROOT=/usr/local/i686-linux-musl
+ENV CROSS_MUSL_SYSROOT=/usr/local/i686-linux-musl
 COPY musl-symlink.sh /
-RUN /musl-symlink.sh $CROSS_SYSROOT i386
+RUN /musl-symlink.sh $CROSS_MUSL_SYSROOT i386
 
 COPY qemu-runner base-runner.sh /
 
@@ -26,5 +26,5 @@ ENV CARGO_TARGET_I686_UNKNOWN_LINUX_MUSL_LINKER=i686-linux-musl-gcc \
     CARGO_TARGET_I686_UNKNOWN_LINUX_MUSL_RUNNER="/qemu-runner i686" \
     CC_i686_unknown_linux_musl=i686-linux-musl-gcc \
     CXX_i686_unknown_linux_musl=i686-linux-musl-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_i686_unknown_linux_musl="--sysroot=$CROSS_SYSROOT" \
-    QEMU_LD_PREFIX="$CROSS_SYSROOT"
+    BINDGEN_EXTRA_CLANG_ARGS_i686_unknown_linux_musl="--sysroot=$CROSS_MUSL_SYSROOT" \
+    QEMU_LD_PREFIX=$CROSS_MUSL_SYSROOT
diff --git a/docker/Dockerfile.mips-unknown-linux-gnu b/docker/Dockerfile.mips-unknown-linux-gnu
index d75caef..4b5f4aa 100644
--- a/docker/Dockerfile.mips-unknown-linux-gnu
+++ b/docker/Dockerfile.mips-unknown-linux-gnu
@@ -19,12 +19,11 @@ RUN /qemu.sh mips
 
 COPY qemu-runner base-runner.sh /
 
-ENV CROSS_SYSROOT=/usr/mips-linux-gnu
 ENV CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_LINKER=mips-linux-gnu-gcc \
     CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_RUNNER="/qemu-runner mips" \
     CC_mips_unknown_linux_gnu=mips-linux-gnu-gcc \
     CXX_mips_unknown_linux_gnu=mips-linux-gnu-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_mips_unknown_linux_gnu="--sysroot=$CROSS_SYSROOT" \
-    QEMU_LD_PREFIX="$CROSS_SYSROOT" \
+    BINDGEN_EXTRA_CLANG_ARGS_mips_unknown_linux_gnu="--sysroot=/usr/mips-linux-gnu" \
+    QEMU_LD_PREFIX=/usr/mips-linux-gnu \
     RUST_TEST_THREADS=1 \
     PKG_CONFIG_PATH="/usr/lib/mips-linux-gnu/pkgconfig/:${PKG_CONFIG_PATH}"
diff --git a/docker/Dockerfile.mips-unknown-linux-musl b/docker/Dockerfile.mips-unknown-linux-musl
index 387c6fc..a7c4eaa 100644
--- a/docker/Dockerfile.mips-unknown-linux-musl
+++ b/docker/Dockerfile.mips-unknown-linux-musl
@@ -20,9 +20,9 @@ RUN /musl.sh \
     TARGET=mips-linux-muslsf \
     "COMMON_CONFIG += -with-arch=mips32r2"
 
-ENV CROSS_SYSROOT=/usr/local/mips-linux-muslsf
+ENV CROSS_MUSL_SYSROOT=/usr/local/mips-linux-muslsf
 COPY musl-symlink.sh /
-RUN /musl-symlink.sh $CROSS_SYSROOT mips-sf
+RUN /musl-symlink.sh $CROSS_MUSL_SYSROOT mips-sf
 
 COPY qemu-runner base-runner.sh /
 
@@ -30,6 +30,6 @@ ENV CARGO_TARGET_MIPS_UNKNOWN_LINUX_MUSL_LINKER=mips-linux-muslsf-gcc \
     CARGO_TARGET_MIPS_UNKNOWN_LINUX_MUSL_RUNNER="/qemu-runner mips" \
     CC_mips_unknown_linux_musl=mips-linux-muslsf-gcc \
     CXX_mips_unknown_linux_musl=mips-linux-muslsf-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_mips_unknown_linux_musl="--sysroot=$CROSS_SYSROOT" \
-    QEMU_LD_PREFIX="$CROSS_SYSROOT" \
+    BINDGEN_EXTRA_CLANG_ARGS_mips_unknown_linux_musl="--sysroot=$CROSS_MUSL_SYSROOT" \
+    QEMU_LD_PREFIX=$CROSS_MUSL_SYSROOT \
     RUST_TEST_THREADS=1
diff --git a/docker/Dockerfile.mips64-unknown-linux-gnuabi64 b/docker/Dockerfile.mips64-unknown-linux-gnuabi64
index caed068..585da05 100644
--- a/docker/Dockerfile.mips64-unknown-linux-gnuabi64
+++ b/docker/Dockerfile.mips64-unknown-linux-gnuabi64
@@ -24,12 +24,11 @@ RUN /qemu.sh mips64
 
 COPY qemu-runner base-runner.sh /
 
-ENV CROSS_SYSROOT=/usr/mips64-linux-gnuabi64
 ENV CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_LINKER=mips64-linux-gnuabi64-gcc \
     CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_RUNNER="/qemu-runner mips64" \
     CC_mips64_unknown_linux_gnuabi64=mips64-linux-gnuabi64-gcc \
     CXX_mips64_unknown_linux_gnuabi64=mips64-linux-gnuabi64-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_mips64_unknown_linux_gnuabi64="--sysroot=$CROSS_SYSROOT" \
-    QEMU_LD_PREFIX="$CROSS_SYSROOT" \
+    BINDGEN_EXTRA_CLANG_ARGS_mips64_unknown_linux_gnuabi64="--sysroot=/usr/mips64-linux-gnuabi64" \
+    QEMU_LD_PREFIX=/usr/mips64-linux-gnuabi64 \
     RUST_TEST_THREADS=1 \
     PKG_CONFIG_PATH="/usr/lib/mips64-linux-gnuabi64/pkgconfig/:${PKG_CONFIG_PATH}"
diff --git a/docker/Dockerfile.mips64-unknown-linux-muslabi64 b/docker/Dockerfile.mips64-unknown-linux-muslabi64
index 119c932..3e05753 100644
--- a/docker/Dockerfile.mips64-unknown-linux-muslabi64
+++ b/docker/Dockerfile.mips64-unknown-linux-muslabi64
@@ -19,13 +19,13 @@ RUN /musl.sh \
     TARGET=mips64-linux-musl \
     "COMMON_CONFIG += -with-arch=mips64r2"
 
-ENV CROSS_SYSROOT=/usr/local/mips64-linux-musl
+ENV CROSS_MUSL_SYSROOT=/usr/local/mips64-linux-musl
 COPY musl-symlink.sh /
-RUN /musl-symlink.sh $CROSS_SYSROOT mips64
-RUN mkdir -p $CROSS_SYSROOT/usr/lib64
+RUN /musl-symlink.sh $CROSS_MUSL_SYSROOT mips64
+RUN mkdir -p $CROSS_MUSL_SYSROOT/usr/lib64
 # needed for the C/C++ runners
-RUN ln -s $CROSS_SYSROOT/usr/lib/libc.so $CROSS_SYSROOT/usr/lib64/libc.so
-RUN ln -s $CROSS_SYSROOT/usr/lib/libc.so.1 $CROSS_SYSROOT/usr/lib64/libc.so.1
+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
 
 COPY mips64-linux-musl-gcc.sh /usr/bin/
 COPY rustc_info.sh /
@@ -36,6 +36,6 @@ ENV CARGO_TARGET_MIPS64_UNKNOWN_LINUX_MUSLABI64_LINKER=mips64-linux-musl-gcc.sh
     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++ \
-    BINDGEN_EXTRA_CLANG_ARGS_mips64_unknown_linux_muslabi64="--sysroot=$CROSS_SYSROOT" \
-    QEMU_LD_PREFIX="$CROSS_SYSROOT" \
+    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 b36f551..eb08531 100644
--- a/docker/Dockerfile.mips64el-unknown-linux-gnuabi64
+++ b/docker/Dockerfile.mips64el-unknown-linux-gnuabi64
@@ -30,12 +30,11 @@ RUN /linux-image.sh mips64el
 
 COPY linux-runner base-runner.sh /
 
-ENV CROSS_SYSROOT=/usr/mips64el-linux-gnuabi64
 ENV CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_LINKER=mips64el-linux-gnuabi64-gcc \
     CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_RUNNER="/linux-runner mips64el" \
     CC_mips64el_unknown_linux_gnuabi64=mips64el-linux-gnuabi64-gcc \
     CXX_mips64el_unknown_linux_gnuabi64=mips64el-linux-gnuabi64-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_mips64el_unknown_linux_gnuabi64="--sysroot=$CROSS_SYSROOT" \
-    QEMU_LD_PREFIX="$CROSS_SYSROOT" \
+    BINDGEN_EXTRA_CLANG_ARGS_mips64el_unknown_linux_gnuabi64="--sysroot=/usr/mips64el-linux-gnuabi64" \
+    QEMU_LD_PREFIX=/usr/mips64el-linux-gnuabi64 \
     RUST_TEST_THREADS=1 \
     PKG_CONFIG_PATH="/usr/lib/mips64el-linux-gnuabi64/pkgconfig/:${PKG_CONFIG_PATH}"
diff --git a/docker/Dockerfile.mips64el-unknown-linux-muslabi64 b/docker/Dockerfile.mips64el-unknown-linux-muslabi64
index d744b4e..6b6c608 100644
--- a/docker/Dockerfile.mips64el-unknown-linux-muslabi64
+++ b/docker/Dockerfile.mips64el-unknown-linux-muslabi64
@@ -19,13 +19,13 @@ RUN /musl.sh \
     TARGET=mips64el-linux-musl \
     "COMMON_CONFIG += -with-arch=mips64r2"
 
-ENV CROSS_SYSROOT=/usr/local/mips64el-linux-musl
+ENV CROSS_MUSL_SYSROOT=/usr/local/mips64el-linux-musl
 COPY musl-symlink.sh /
-RUN /musl-symlink.sh $CROSS_SYSROOT mips64el
-RUN mkdir -p $CROSS_SYSROOT/usr/lib64
+RUN /musl-symlink.sh $CROSS_MUSL_SYSROOT mips64el
+RUN mkdir -p $CROSS_MUSL_SYSROOT/usr/lib64
 # needed for the C/C++ runners
-RUN ln -s $CROSS_SYSROOT/usr/lib/libc.so $CROSS_SYSROOT/usr/lib64/libc.so
-RUN ln -s $CROSS_SYSROOT/usr/lib/libc.so.1 $CROSS_SYSROOT/usr/lib64/libc.so.1
+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
 
 COPY mips64el-linux-musl-gcc.sh /usr/bin/
 COPY rustc_info.sh /
@@ -36,6 +36,6 @@ ENV CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_MUSLABI64_LINKER=mips64el-linux-musl-gcc
     CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_MUSLABI64_RUNNER="/qemu-runner mips64el" \
     CC_mips64el_unknown_linux_muslabi64=mips64el-linux-musl-gcc \
     CXX_mips64el_unknown_linux_muslabi64=mips64el-linux-musl-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_mips64el_unknown_linux_muslabi64="--sysroot=$CROSS_SYSROOT" \
-    QEMU_LD_PREFIX="$CROSS_SYSROOT" \
+    BINDGEN_EXTRA_CLANG_ARGS_mips64el_unknown_linux_muslabi64="--sysroot=$CROSS_MUSL_SYSROOT" \
+    QEMU_LD_PREFIX=$CROSS_MUSL_SYSROOT \
     RUST_TEST_THREADS=1
diff --git a/docker/Dockerfile.mipsel-unknown-linux-gnu b/docker/Dockerfile.mipsel-unknown-linux-gnu
index 9cb983c..5646106 100644
--- a/docker/Dockerfile.mipsel-unknown-linux-gnu
+++ b/docker/Dockerfile.mipsel-unknown-linux-gnu
@@ -30,12 +30,11 @@ RUN /linux-image.sh mipsel
 
 COPY linux-runner base-runner.sh /
 
-ENV CROSS_SYSROOT=/usr/mipsel-linux-gnu
 ENV CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_LINKER=mipsel-linux-gnu-gcc \
     CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_RUNNER="/linux-runner mipsel" \
     CC_mipsel_unknown_linux_gnu=mipsel-linux-gnu-gcc \
     CXX_mipsel_unknown_linux_gnu=mipsel-linux-gnu-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_mipsel_unknown_linux_gnu="--sysroot=$CROSS_SYSROOT" \
-    QEMU_LD_PREFIX="$CROSS_SYSROOT" \
+    BINDGEN_EXTRA_CLANG_ARGS_mipsel_unknown_linux_gnu="--sysroot=/usr/mipsel-linux-gnu" \
+    QEMU_LD_PREFIX=/usr/mipsel-linux-gnu \
     RUST_TEST_THREADS=1 \
     PKG_CONFIG_PATH="/usr/lib/mipsel-linux-gnu/pkgconfig/:${PKG_CONFIG_PATH}"
diff --git a/docker/Dockerfile.mipsel-unknown-linux-musl b/docker/Dockerfile.mipsel-unknown-linux-musl
index 3dadbf7..ab34456 100644
--- a/docker/Dockerfile.mipsel-unknown-linux-musl
+++ b/docker/Dockerfile.mipsel-unknown-linux-musl
@@ -20,9 +20,9 @@ RUN /musl.sh \
     TARGET=mipsel-linux-muslsf \
     "COMMON_CONFIG += -with-arch=mips32r2"
 
-ENV CROSS_SYSROOT=/usr/local/mipsel-linux-muslsf
+ENV CROSS_MUSL_SYSROOT=/usr/local/mipsel-linux-muslsf
 COPY musl-symlink.sh /
-RUN /musl-symlink.sh $CROSS_SYSROOT mipsel-sf
+RUN /musl-symlink.sh $CROSS_MUSL_SYSROOT mipsel-sf
 
 COPY qemu-runner base-runner.sh /
 
@@ -30,6 +30,6 @@ ENV CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_MUSL_LINKER=mipsel-linux-muslsf-gcc \
     CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_MUSL_RUNNER="/qemu-runner mipsel" \
     CC_mipsel_unknown_linux_musl=mipsel-linux-muslsf-gcc \
     CXX_mipsel_unknown_linux_musl=mipsel-linux-muslsf-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_mipsel_unknown_linux_musl="--sysroot=$CROSS_SYSROOT" \
-    QEMU_LD_PREFIX="$CROSS_SYSROOT" \
+    BINDGEN_EXTRA_CLANG_ARGS_mipsel_unknown_linux_musl="--sysroot=$CROSS_MUSL_SYSROOT" \
+    QEMU_LD_PREFIX=$CROSS_MUSL_SYSROOT \
     RUST_TEST_THREADS=1
diff --git a/docker/Dockerfile.native b/docker/Dockerfile.native
index 71949b1..291848f 100644
--- a/docker/Dockerfile.native
+++ b/docker/Dockerfile.native
@@ -28,5 +28,4 @@ COPY linux-runner native-linux-runner base-runner.sh /
 
 ENV CROSS_TARGETARCH=$TARGETARCH
 ENV CROSS_TARGETVARIANT=$TARGETVARIANT
-ENV CROSS_SYSROOT=/
 ENV CARGO_TARGET_${CROSS_TARGET_TRIPLE}_RUNNER="/native-linux-runner"
diff --git a/docker/Dockerfile.native.centos b/docker/Dockerfile.native.centos
index 2b5734f..c92b565 100644
--- a/docker/Dockerfile.native.centos
+++ b/docker/Dockerfile.native.centos
@@ -37,5 +37,4 @@ COPY linux-runner native-linux-runner base-runner.sh /
 
 ENV CROSS_TARGETARCH=$TARGETARCH
 ENV CROSS_TARGETVARIANT=$TARGETVARIANT
-ENV CROSS_SYSROOT=/
 ENV CARGO_TARGET_${CROSS_TARGET_TRIPLE}_RUNNER="/native-linux-runner"
diff --git a/docker/Dockerfile.powerpc-unknown-linux-gnu b/docker/Dockerfile.powerpc-unknown-linux-gnu
index 3751624..d0a3173 100644
--- a/docker/Dockerfile.powerpc-unknown-linux-gnu
+++ b/docker/Dockerfile.powerpc-unknown-linux-gnu
@@ -30,12 +30,11 @@ RUN /linux-image.sh powerpc
 
 COPY linux-runner base-runner.sh /
 
-ENV CROSS_SYSROOT=/usr/powerpc-linux-gnu
 ENV CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_LINKER=powerpc-linux-gnu-gcc \
     CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_RUNNER="/linux-runner powerpc" \
     CC_powerpc_unknown_linux_gnu=powerpc-linux-gnu-gcc \
     CXX_powerpc_unknown_linux_gnu=powerpc-linux-gnu-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_powerpc_unknown_linux_gnu="--sysroot=$CROSS_SYSROOT" \
-    QEMU_LD_PREFIX="$CROSS_SYSROOT" \
+    BINDGEN_EXTRA_CLANG_ARGS_powerpc_unknown_linux_gnu="--sysroot=/usr/powerpc-linux-gnu" \
+    QEMU_LD_PREFIX=/usr/powerpc-linux-gnu \
     RUST_TEST_THREADS=1 \
     PKG_CONFIG_PATH="/usr/lib/powerpc-linux-gnu/pkgconfig/:${PKG_CONFIG_PATH}"
diff --git a/docker/Dockerfile.powerpc64-unknown-linux-gnu b/docker/Dockerfile.powerpc64-unknown-linux-gnu
index 5fd506e..ea71968 100644
--- a/docker/Dockerfile.powerpc64-unknown-linux-gnu
+++ b/docker/Dockerfile.powerpc64-unknown-linux-gnu
@@ -30,12 +30,11 @@ RUN /linux-image.sh powerpc64
 
 COPY linux-runner base-runner.sh /
 
-ENV CROSS_SYSROOT=/usr/powerpc64-linux-gnu
 ENV CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_LINKER=powerpc64-linux-gnu-gcc \
     CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_RUNNER="/linux-runner powerpc64" \
     CC_powerpc64_unknown_linux_gnu=powerpc64-linux-gnu-gcc \
     CXX_powerpc64_unknown_linux_gnu=powerpc64-linux-gnu-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_powerpc64_unknown_linux_gnu="--sysroot=$CROSS_SYSROOT" \
-    QEMU_LD_PREFIX="$CROSS_SYSROOT" \
+    BINDGEN_EXTRA_CLANG_ARGS_powerpc64_unknown_linux_gnu="--sysroot=/usr/powerpc64-linux-gnu" \
+    QEMU_LD_PREFIX=/usr/powerpc64-linux-gnu \
     RUST_TEST_THREADS=1 \
     PKG_CONFIG_PATH="/usr/lib/powerpc64-linux-gnu/pkgconfig/:${PKG_CONFIG_PATH}"
diff --git a/docker/Dockerfile.powerpc64le-unknown-linux-gnu b/docker/Dockerfile.powerpc64le-unknown-linux-gnu
index 1bae8e8..ab3eb74 100644
--- a/docker/Dockerfile.powerpc64le-unknown-linux-gnu
+++ b/docker/Dockerfile.powerpc64le-unknown-linux-gnu
@@ -30,12 +30,11 @@ RUN /linux-image.sh powerpc64le
 
 COPY linux-runner base-runner.sh /
 
-ENV CROSS_SYSROOT=/usr/powerpc64le-linux-gnu
 ENV CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_LINKER=powerpc64le-linux-gnu-gcc \
     CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_RUNNER="/linux-runner powerpc64le" \
     CC_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-gcc \
     CXX_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_powerpc64le_unknown_linux_gnu="--sysroot=$CROSS_SYSROOT" \
-    QEMU_LD_PREFIX="$CROSS_SYSROOT" \
+    BINDGEN_EXTRA_CLANG_ARGS_powerpc64le_unknown_linux_gnu="--sysroot=/usr/powerpc64le-linux-gnu" \
+    QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu \
     RUST_TEST_THREADS=1 \
     PKG_CONFIG_PATH="/usr/lib/powerpc64le-linux-gnu/pkgconfig/:${PKG_CONFIG_PATH}"
diff --git a/docker/Dockerfile.riscv64gc-unknown-linux-gnu b/docker/Dockerfile.riscv64gc-unknown-linux-gnu
index 077e401..215d569 100644
--- a/docker/Dockerfile.riscv64gc-unknown-linux-gnu
+++ b/docker/Dockerfile.riscv64gc-unknown-linux-gnu
@@ -30,12 +30,11 @@ RUN /linux-image.sh riscv64
 
 COPY linux-runner base-runner.sh /
 
-ENV CROSS_SYSROOT=/usr/riscv64-linux-gnu
 ENV CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_LINKER=riscv64-linux-gnu-gcc \
     CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_RUNNER="/linux-runner riscv64" \
     CC_riscv64gc_unknown_linux_gnu=riscv64-linux-gnu-gcc \
     CXX_riscv64gc_unknown_linux_gnu=riscv64-linux-gnu-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_riscv64gc_unknown_linux_gnu="--sysroot=$CROSS_SYSROOT" \
-    QEMU_LD_PREFIX="$CROSS_SYSROOT" \
+    BINDGEN_EXTRA_CLANG_ARGS_riscv64gc_unknown_linux_gnu="--sysroot=/usr/riscv64-linux-gnu" \
+    QEMU_LD_PREFIX=/usr/riscv64-linux-gnu \
     RUST_TEST_THREADS=1 \
     PKG_CONFIG_PATH="/usr/lib/riscv64-linux-gnu/pkgconfig/:${PKG_CONFIG_PATH}"
diff --git a/docker/Dockerfile.s390x-unknown-linux-gnu b/docker/Dockerfile.s390x-unknown-linux-gnu
index 896e82f..8bb2673 100644
--- a/docker/Dockerfile.s390x-unknown-linux-gnu
+++ b/docker/Dockerfile.s390x-unknown-linux-gnu
@@ -30,12 +30,11 @@ RUN /linux-image.sh s390x
 
 COPY linux-runner base-runner.sh /
 
-ENV CROSS_SYSROOT=/usr/s390x-linux-gnu
 ENV CARGO_TARGET_S390X_UNKNOWN_LINUX_GNU_LINKER=s390x-linux-gnu-gcc \
     CARGO_TARGET_S390X_UNKNOWN_LINUX_GNU_RUNNER="/linux-runner s390x" \
     CC_s390x_unknown_linux_gnu=s390x-linux-gnu-gcc \
     CXX_s390x_unknown_linux_gnu=s390x-linux-gnu-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_s390x_unknown_linux_gnu="--sysroot=$CROSS_SYSROOT" \
-    QEMU_LD_PREFIX="$CROSS_SYSROOT" \
+    BINDGEN_EXTRA_CLANG_ARGS_s390x_unknown_linux_gnu="--sysroot=/usr/s390x-linux-gnu" \
+    QEMU_LD_PREFIX=/usr/s390x-linux-gnu \
     RUST_TEST_THREADS=1 \
     PKG_CONFIG_PATH="/usr/lib/s390x-linux-gnu/pkgconfig/:${PKG_CONFIG_PATH}"
diff --git a/docker/Dockerfile.sparc64-unknown-linux-gnu b/docker/Dockerfile.sparc64-unknown-linux-gnu
index 523ba63..15a6ee1 100644
--- a/docker/Dockerfile.sparc64-unknown-linux-gnu
+++ b/docker/Dockerfile.sparc64-unknown-linux-gnu
@@ -30,12 +30,11 @@ RUN /linux-image.sh sparc64
 
 COPY linux-runner base-runner.sh /
 
-ENV CROSS_SYSROOT=/usr/sparc64-linux-gnu
 ENV CARGO_TARGET_SPARC64_UNKNOWN_LINUX_GNU_LINKER=sparc64-linux-gnu-gcc \
     CARGO_TARGET_SPARC64_UNKNOWN_LINUX_GNU_RUNNER="/linux-runner sparc64" \
     CC_sparc64_unknown_linux_gnu=sparc64-linux-gnu-gcc \
     CXX_sparc64_unknown_linux_gnu=sparc64-linux-gnu-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_sparc64_unknown_linux_gnu="--sysroot=$CROSS_SYSROOT" \
-    QEMU_LD_PREFIX="$CROSS_SYSROOT" \
+    BINDGEN_EXTRA_CLANG_ARGS_sparc64_unknown_linux_gnu="--sysroot=/usr/sparc64-linux-gnu" \
+    QEMU_LD_PREFIX=/usr/sparc64-linux-gnu \
     RUST_TEST_THREADS=1 \
     PKG_CONFIG_PATH="/usr/lib/sparc64-linux-gnu/pkgconfig/:${PKG_CONFIG_PATH}"
diff --git a/docker/Dockerfile.sparcv9-sun-solaris b/docker/Dockerfile.sparcv9-sun-solaris
index 1d12af2..4cf2701 100644
--- a/docker/Dockerfile.sparcv9-sun-solaris
+++ b/docker/Dockerfile.sparcv9-sun-solaris
@@ -13,8 +13,7 @@ RUN /xargo.sh
 COPY solaris.sh /
 RUN /solaris.sh sparcv9
 
-ENV CROSS_SYSROOT=/usr/local/sparcv9-sun-solaris2.10
 ENV CARGO_TARGET_SPARCV9_SUN_SOLARIS_LINKER=sparcv9-sun-solaris2.10-gcc \
     CC_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-gcc \
     CXX_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_sparcv9_sun_solaris="--sysroot=$CROSS_SYSROOT"
+    BINDGEN_EXTRA_CLANG_ARGS_sparcv9_sun_solaris="--sysroot=/usr/local/sparcv9-sun-solaris2.10"
diff --git a/docker/Dockerfile.thumbv7neon-linux-androideabi b/docker/Dockerfile.thumbv7neon-linux-androideabi
index 3a36895..203392d 100644
--- a/docker/Dockerfile.thumbv7neon-linux-androideabi
+++ b/docker/Dockerfile.thumbv7neon-linux-androideabi
@@ -20,8 +20,7 @@ RUN /android-system.sh arm
 COPY qemu.sh /
 RUN /qemu.sh arm
 
-ENV CROSS_SYSROOT=/android-ndk/sysroot
-RUN cp $CROSS_SYSROOT/usr/lib/arm-linux-androideabi/28/libz.so /system/lib/
+RUN cp /android-ndk/sysroot/usr/lib/arm-linux-androideabi/28/libz.so /system/lib/
 
 COPY android-runner /
 
@@ -45,8 +44,8 @@ ENV CARGO_TARGET_THUMBV7NEON_LINUX_ANDROIDEABI_LINKER=arm-linux-androideabi-gcc
     SIZE_thumbv7neon_linux_androideabi=arm-linux-androideabi-size \
     STRINGS_thumbv7neon_linux_androideabi=arm-linux-androideabi-strings \
     STRIP_thumbv7neon_linux_androideabi=arm-linux-androideabi-strip \
-    BINDGEN_EXTRA_CLANG_ARGS_thumbv7neon_linux_androideabi="--sysroot=$CROSS_SYSROOT" \
-    DEP_Z_INCLUDE="$CROSS_SYSROOT/usr/include/" \
+    BINDGEN_EXTRA_CLANG_ARGS_thumbv7neon_linux_androideabi="--sysroot=/android-ndk/sysroot" \
+    DEP_Z_INCLUDE=/android-ndk/sysroot/usr/include/ \
     RUST_TEST_THREADS=1 \
     HOME=/tmp/ \
     TMPDIR=/tmp/ \
diff --git a/docker/Dockerfile.thumbv7neon-unknown-linux-gnueabihf b/docker/Dockerfile.thumbv7neon-unknown-linux-gnueabihf
index 9433ee1..d9cfbd6 100644
--- a/docker/Dockerfile.thumbv7neon-unknown-linux-gnueabihf
+++ b/docker/Dockerfile.thumbv7neon-unknown-linux-gnueabihf
@@ -26,7 +26,6 @@ RUN /linux-image.sh armv7
 COPY linux-runner base-runner.sh /
 
 # Export all target binutils just in case required.
-ENV CROSS_SYSROOT=/usr/arm-linux-gnueabihf
 ENV CARGO_TARGET_THUMBV7NEON_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \
     CARGO_TARGET_THUMBV7NEON_UNKNOWN_LINUX_GNUEABIHF_RUNNER="/linux-runner armv7hf" \
     AR_thumbv7neon_unknown_linux_gnueabihf=arm-linux-gnueabihf-ar \
@@ -42,7 +41,7 @@ ENV CARGO_TARGET_THUMBV7NEON_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-
     SIZE_thumbv7neon_unknown_linux_gnueabihf=arm-linux-gnueabihf-size \
     STRINGS_thumbv7neon_unknown_linux_gnueabihf=arm-linux-gnueabihf-strings \
     STRIP_thumbv7neon_unknown_linux_gnueabihf=arm-linux-gnueabihf-strip \
-    BINDGEN_EXTRA_CLANG_ARGS_thumbv7neon_unknown_linux_gnueabihf="--sysroot=$CROSS_SYSROOT" \
-    QEMU_LD_PREFIX="$CROSS_SYSROOT" \
+    BINDGEN_EXTRA_CLANG_ARGS_thumbv7neon_unknown_linux_gnueabihf="--sysroot=/usr/arm-linux-gnueabihf" \
+    QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \
     RUST_TEST_THREADS=1 \
     PKG_CONFIG_PATH="/usr/lib/arm-linux-gnueabihf/pkgconfig/:${PKG_CONFIG_PATH}"
diff --git a/docker/Dockerfile.wasm32-unknown-emscripten b/docker/Dockerfile.wasm32-unknown-emscripten
index 6600312..2d040a7 100644
--- a/docker/Dockerfile.wasm32-unknown-emscripten
+++ b/docker/Dockerfile.wasm32-unknown-emscripten
@@ -15,6 +15,5 @@ RUN apt-get update && apt-get install --assume-yes --no-install-recommends \
   libxml2 \
   python
 
-ENV CROSS_SYSROOT=/emsdk/upstream/emscripten/cache/sysroot
 ENV CARGO_TARGET_WASM32_UNKNOWN_EMSCRIPTEN_RUNNER=node \
-  BINDGEN_EXTRA_CLANG_ARGS_wasm32_unknown_emscripten="--sysroot=$CROSS_SYSROOT"
+  BINDGEN_EXTRA_CLANG_ARGS_wasm32_unknown_emscripten="--sysroot=/emsdk/upstream/emscripten/cache/sysroot"
diff --git a/docker/Dockerfile.x86_64-linux-android b/docker/Dockerfile.x86_64-linux-android
index 06698ee..00efc61 100644
--- a/docker/Dockerfile.x86_64-linux-android
+++ b/docker/Dockerfile.x86_64-linux-android
@@ -21,8 +21,7 @@ RUN /android-system.sh x86_64
 COPY qemu.sh /
 RUN /qemu.sh x86_64
 
-ENV CROSS_SYSROOT=/android-ndk/sysroot
-RUN cp $CROSS_SYSROOT/usr/lib/x86_64-linux-android/28/libz.so /system/lib/
+RUN cp /android-ndk/sysroot/usr/lib/x86_64-linux-android/28/libz.so /system/lib/
 
 COPY android-runner /
 
@@ -32,8 +31,8 @@ ENV CARGO_TARGET_X86_64_LINUX_ANDROID_LINKER=x86_64-linux-android-gcc \
     CARGO_TARGET_X86_64_LINUX_ANDROID_RUNNER="/android-runner x86_64" \
     CC_x86_64_linux_android=x86_64-linux-android-gcc \
     CXX_x86_64_linux_android=x86_64-linux-android-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_x86_64_linux_android="--sysroot=$CROSS_SYSROOT" \
-    DEP_Z_INCLUDE="$CROSS_SYSROOT/usr/include/" \
+    BINDGEN_EXTRA_CLANG_ARGS_x86_64_linux_android="--sysroot=/android-ndk/sysroot" \
+    DEP_Z_INCLUDE=/android-ndk/sysroot/usr/include/ \
     RUST_TEST_THREADS=1 \
     HOME=/tmp/ \
     TMPDIR=/tmp/ \
diff --git a/docker/Dockerfile.x86_64-pc-windows-gnu b/docker/Dockerfile.x86_64-pc-windows-gnu
index dd21772..d2b2f16 100644
--- a/docker/Dockerfile.x86_64-pc-windows-gnu
+++ b/docker/Dockerfile.x86_64-pc-windows-gnu
@@ -32,9 +32,8 @@ RUN mkdir -p /usr/lib/binfmt-support/ && \
 COPY windows-entry.sh /
 ENTRYPOINT ["/windows-entry.sh"]
 
-ENV CROSS_SYSROOT=/usr/x86_64-w64-mingw32
 ENV CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER=x86_64-w64-mingw32-gcc \
     CARGO_TARGET_X86_64_PC_WINDOWS_GNU_RUNNER=wine \
     CC_x86_64_pc_windows_gnu=x86_64-w64-mingw32-gcc-posix \
     CXX_x86_64_pc_windows_gnu=x86_64-w64-mingw32-g++-posix \
-    BINDGEN_EXTRA_CLANG_ARGS_x86_64_pc_windows_gnu="--sysroot=$CROSS_SYSROOT"
+    BINDGEN_EXTRA_CLANG_ARGS_x86_64_pc_windows_gnu="--sysroot=/usr/x86_64-w64-mingw32"
diff --git a/docker/Dockerfile.x86_64-sun-solaris b/docker/Dockerfile.x86_64-sun-solaris
index 3036331..a290c31 100644
--- a/docker/Dockerfile.x86_64-sun-solaris
+++ b/docker/Dockerfile.x86_64-sun-solaris
@@ -13,8 +13,7 @@ RUN /xargo.sh
 COPY solaris.sh /
 RUN /solaris.sh x86_64
 
-ENV CROSS_SYSROOT=/usr/local/x86_64-sun-solaris2.10
 ENV CARGO_TARGET_X86_64_SUN_SOLARIS_LINKER=x86_64-sun-solaris2.10-gcc \
     CC_x86_64_sun_solaris=x86_64-sun-solaris2.10-gcc \
     CXX_x86_64_sun_solaris=x86_64-sun-solaris2.10-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_x86_64_sun_solaris="--sysroot=$CROSS_SYSROOT"
+    BINDGEN_EXTRA_CLANG_ARGS_x86_64_sun_solaris="--sysroot=/usr/local/x86_64-sun-solaris2.10"
diff --git a/docker/Dockerfile.x86_64-unknown-dragonfly b/docker/Dockerfile.x86_64-unknown-dragonfly
index 605e753..6a60522 100644
--- a/docker/Dockerfile.x86_64-unknown-dragonfly
+++ b/docker/Dockerfile.x86_64-unknown-dragonfly
@@ -13,8 +13,7 @@ RUN /xargo.sh
 COPY dragonfly.sh /
 RUN /dragonfly.sh 5
 
-ENV CROSS_SYSROOT=/usr/local/x86_64-unknown-dragonfly
 ENV CARGO_TARGET_X86_64_UNKNOWN_DRAGONFLY_LINKER=x86_64-unknown-dragonfly-gcc \
     CC_x86_64_unknown_dragonfly=x86_64-unknown-dragonfly-gcc \
     CXX_x86_64_unknown_dragonfly=x86_64-unknown-dragonfly-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_x86_64_unknown_dragonfly="--sysroot=$CROSS_SYSROOT"
+    BINDGEN_EXTRA_CLANG_ARGS_x86_64_unknown_dragonfly="--sysroot=/usr/local/x86_64-unknown-dragonfly"
diff --git a/docker/Dockerfile.x86_64-unknown-freebsd b/docker/Dockerfile.x86_64-unknown-freebsd
index 2c35f00..ed901d8 100644
--- a/docker/Dockerfile.x86_64-unknown-freebsd
+++ b/docker/Dockerfile.x86_64-unknown-freebsd
@@ -21,9 +21,8 @@ RUN /freebsd-extras.sh
 
 COPY x86_64-unknown-freebsd12-gcc.sh /usr/bin
 
-ENV CROSS_SYSROOT=/usr/local/x86_64-unknown-freebsd12
 ENV CARGO_TARGET_X86_64_UNKNOWN_FREEBSD_LINKER=x86_64-unknown-freebsd12-gcc.sh \
     CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-gcc \
     CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_x86_64_unknown_freebsd="--sysroot=$CROSS_SYSROOT" \
-    X86_64_UNKNOWN_FREEBSD_OPENSSL_DIR="$CROSS_SYSROOT"
+    BINDGEN_EXTRA_CLANG_ARGS_x86_64_unknown_freebsd="--sysroot=/usr/local/x86_64-unknown-freebsd12" \
+    X86_64_UNKNOWN_FREEBSD_OPENSSL_DIR=/usr/local/x86_64-unknown-freebsd12/
diff --git a/docker/Dockerfile.x86_64-unknown-illumos b/docker/Dockerfile.x86_64-unknown-illumos
index 47662c5..922cf52 100644
--- a/docker/Dockerfile.x86_64-unknown-illumos
+++ b/docker/Dockerfile.x86_64-unknown-illumos
@@ -12,10 +12,9 @@ RUN /xargo.sh
 COPY illumos.sh /
 RUN /illumos.sh x86_64
 
-ENV CROSS_SYSROOT=/usr/local/x86_64-unknown-illumos/sysroot
 ENV PATH=$PATH:/usr/local/x86_64-unknown-illumos/bin/ \
     CARGO_TARGET_X86_64_UNKNOWN_ILLUMOS_LINKER=x86_64-unknown-illumos-gcc \
     AR_x86_64_unknown_illumos=x86_64-unknown-illumos-ar \
     CC_x86_64_unknown_illumos=x86_64-unknown-illumos-gcc \
     CXX_x86_64_unknown_illumos=x86_64-unknown-illumos-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_sparcv9_sun_solaris="--sysroot=$CROSS_SYSROOT"
+    BINDGEN_EXTRA_CLANG_ARGS_sparcv9_sun_solaris="--sysroot=/usr/local/x86_64-unknown-illumos/sysroot"
diff --git a/docker/Dockerfile.x86_64-unknown-linux-gnu b/docker/Dockerfile.x86_64-unknown-linux-gnu
index 9f71d13..d0fa70e 100644
--- a/docker/Dockerfile.x86_64-unknown-linux-gnu
+++ b/docker/Dockerfile.x86_64-unknown-linux-gnu
@@ -30,12 +30,11 @@ RUN /linux-image.sh x86_64
 
 COPY linux-runner base-runner.sh /
 
-ENV CROSS_SYSROOT=/usr/x86_64-linux-gnu
 ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=x86_64-linux-gnu-gcc \
     CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="/linux-runner x86_64" \
     CC_x86_64_unknown_linux_gnu=x86_64-linux-gnu-gcc \
     CXX_x86_64_unknown_linux_gnu=x86_64-linux-gnu-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_x86_64_unknown_linux_gnu="--sysroot=$CROSS_SYSROOT" \
-    QEMU_LD_PREFIX="$CROSS_SYSROOT" \
+    BINDGEN_EXTRA_CLANG_ARGS_x86_64_unknown_linux_gnu="--sysroot=/usr/x86_64-linux-gnu" \
+    QEMU_LD_PREFIX=/usr/x86_64-linux-gnu \
     RUST_TEST_THREADS=1 \
     PKG_CONFIG_PATH="/usr/lib/x86_64-linux-gnu/pkgconfig/:${PKG_CONFIG_PATH}"
diff --git a/docker/Dockerfile.x86_64-unknown-linux-gnu.centos b/docker/Dockerfile.x86_64-unknown-linux-gnu.centos
index 321d66a..52a8e38 100644
--- a/docker/Dockerfile.x86_64-unknown-linux-gnu.centos
+++ b/docker/Dockerfile.x86_64-unknown-linux-gnu.centos
@@ -26,5 +26,4 @@ COPY --from=0 /qemu /qemu
 
 COPY linux-runner base-runner.sh /
 
-ENV CROSS_SYSROOT=/
 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 4a0ffb2..2712be9 100644
--- a/docker/Dockerfile.x86_64-unknown-linux-musl
+++ b/docker/Dockerfile.x86_64-unknown-linux-musl
@@ -16,9 +16,9 @@ RUN /musl.sh TARGET=x86_64-linux-musl
 COPY qemu.sh /
 RUN /qemu.sh x86_64
 
-ENV CROSS_SYSROOT=/usr/local/x86_64-linux-musl
+ENV CROSS_MUSL_SYSROOT=/usr/local/x86_64-linux-musl
 COPY musl-symlink.sh /
-RUN /musl-symlink.sh $CROSS_SYSROOT x86_64
+RUN /musl-symlink.sh $CROSS_MUSL_SYSROOT x86_64
 
 COPY qemu-runner base-runner.sh /
 
@@ -26,5 +26,5 @@ 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" \
     CC_x86_64_unknown_linux_musl=x86_64-linux-musl-gcc \
     CXX_x86_64_unknown_linux_musl=x86_64-linux-musl-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_x86_64_unknown_linux_musl="--sysroot=$CROSS_SYSROOT" \
-    QEMU_LD_PREFIX="$CROSS_SYSROOT"
+    BINDGEN_EXTRA_CLANG_ARGS_x86_64_unknown_linux_musl="--sysroot=$CROSS_MUSL_SYSROOT" \
+    QEMU_LD_PREFIX=$CROSS_MUSL_SYSROOT
diff --git a/docker/Dockerfile.x86_64-unknown-netbsd b/docker/Dockerfile.x86_64-unknown-netbsd
index 4215d86..d1c89af 100644
--- a/docker/Dockerfile.x86_64-unknown-netbsd
+++ b/docker/Dockerfile.x86_64-unknown-netbsd
@@ -13,8 +13,7 @@ RUN /xargo.sh
 COPY netbsd.sh /
 RUN /netbsd.sh
 
-ENV CROSS_SYSROOT=/usr/local/x86_64-unknown-netbsd
 ENV CARGO_TARGET_X86_64_UNKNOWN_NETBSD_LINKER=x86_64-unknown-netbsd-gcc \
     CC_x86_64_unknown_netbsd=x86_64-unknown-netbsd-gcc \
     CXX_x86_64_unknown_netbsd=x86_64-unknown-netbsd-g++ \
-    BINDGEN_EXTRA_CLANG_ARGS_x86_64_unknown_netbsd="--sysroot=$CROSS_SYSROOT"
+    BINDGEN_EXTRA_CLANG_ARGS_x86_64_unknown_netbsd="--sysroot=/usr/local/x86_64-unknown-netbsd"
diff --git a/docker/aarch64-linux-gnu-glibc.sh b/docker/aarch64-linux-gnu-glibc.sh
index a071eb5..eab096a 100755
--- a/docker/aarch64-linux-gnu-glibc.sh
+++ b/docker/aarch64-linux-gnu-glibc.sh
@@ -42,22 +42,22 @@ main() {
     yum install -y epel-release
     yum install -y gcc-aarch64-linux-gnu gcc-c++-aarch64-linux-gnu binutils-aarch64-linux-gnu binutils gcc-c++ glibc-devel
     yum clean all
-
+     
     local td
     td="$(mktemp -d)"
-
+  
     pushd "${td}"
-
+    
     local target=aarch64-linux-gnu
     local prefix="/usr/${target}"
     local kernel_v4="4.18.20"
-
+    
     curl --retry 3 "https://mirrors.edge.kernel.org/pub/linux/kernel/v4.x/linux-${kernel_v4}.tar.xz" -O
     tar -xvf "linux-${kernel_v4}.tar.xz"
     pushd "linux-${kernel_v4}"
     make ARCH=arm64 INSTALL_HDR_PATH="${prefix}" headers_install
     popd
-
+    
     curl --retry 3 http://ftp.gnu.org/gnu/glibc/glibc-2.17.tar.xz -O
     tar -xvf glibc-2.17.tar.xz
     mkdir build
@@ -76,13 +76,13 @@ main() {
         --with-headers="${prefix}/include" \
         --libdir="${prefix}/lib" \
         --libexecdir="${prefix}/lib"
-
+    
     make -j && make install
     popd
 
     mkdir -p "${prefix}"/{include,lib}
     mkdir -p "/usr/lib/gcc/aarch64-linux-gnu"/{4.8.2,4.8.5}
-
+    
     mkdir libgcc
     pushd libgcc
     unpack_rpm "libgcc-4.8.5-44.el7.aarch64.rpm"
@@ -113,7 +113,7 @@ main() {
     # these are currently empty, but might contain content later
     mv "${redhat_485}/bits"/* "${cpp_485}/bits" || true
     mv "${redhat_485}/ext"/* "${cpp_485}/ext" || true
-
+    
     popd
 
     rm -rf "${td}"
diff --git a/docker/android-ndk.sh b/docker/android-ndk.sh
index 49b3dff..ff1b7e0 100755
--- a/docker/android-ndk.sh
+++ b/docker/android-ndk.sh
@@ -10,7 +10,7 @@ NDK_URL=https://dl.google.com/android/repository/android-ndk-r21d-linux-x86_64.z
 
 main() {
     local arch="${1}" \
-        api="${2}"
+          api="${2}"
 
     install_packages curl unzip python
 
@@ -23,32 +23,32 @@ main() {
     rm android-ndk-*.zip
     pushd android-ndk-*
     ./build/tools/make_standalone_toolchain.py \
-        --install-dir /android-ndk \
-        --arch "${arch}" \
-        --api "${api}"
+      --install-dir /android-ndk \
+      --arch "${arch}" \
+      --api "${api}"
 
     # clean up unused toolchains to reduce image size
     local triple
     local triples
     local triple_arch="${arch}"
     case "${arch}" in
-        arm64)
-            triple_arch="aarch64"
-            ;;
-        x86)
-            triple_arch="i686"
-            ;;
+      arm64)
+        triple_arch="aarch64"
+        ;;
+      x86)
+        triple_arch="i686"
+        ;;
     esac
     triples=(
-        "aarch64-linux-android"
-        "arm-linux-androideabi"
-        "i686-linux-android"
-        "x86_64-linux-android"
+      "aarch64-linux-android"
+      "arm-linux-androideabi"
+      "i686-linux-android"
+      "x86_64-linux-android"
     )
     for triple in "${triples[@]}"; do
-        if ! [[ "${triple}" =~ ^"${triple_arch}".* ]]; then
-            rm -rf "/android-ndk/sysroot/usr/lib/${triple}"
-        fi
+      if ! [[ "${triple}" =~ ^"${triple_arch}".* ]]; then
+        rm -rf "/android-ndk/sysroot/usr/lib/${triple}"
+      fi
     done
 
     purge_packages
diff --git a/docker/crosstool-config/arm-unknown-linux-gnueabihf.config b/docker/crosstool-config/arm-unknown-linux-gnueabihf.config
index e8988f4..0b40388 100644
--- a/docker/crosstool-config/arm-unknown-linux-gnueabihf.config
+++ b/docker/crosstool-config/arm-unknown-linux-gnueabihf.config
@@ -260,6 +260,7 @@ CT_LINUX_PATCH_ORDER="global"
 CT_LINUX_V_4_19=y
 # CT_LINUX_NO_VERSIONS is not set
 CT_LINUX_VERSION="4.19.21"
+
 CT_LINUX_MIRRORS="$(CT_Mirrors kernel.org linux ${CT_LINUX_VERSION})"
 CT_LINUX_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
 CT_LINUX_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
@@ -271,6 +272,7 @@ CT_LINUX_later_than_3_7=y
 CT_LINUX_3_7_or_later=y
 CT_LINUX_later_than_3_2=y
 CT_LINUX_3_2_or_later=y
+
 CT_KERNEL_LINUX_VERBOSITY_0=y
 # CT_KERNEL_LINUX_VERBOSITY_1 is not set
 # CT_KERNEL_LINUX_VERBOSITY_2 is not set
@@ -368,6 +370,7 @@ CT_GLIBC_PATCH_ORDER="global"
 CT_GLIBC_V_2_17=y
 # CT_GLIBC_NO_VERSIONS is not set
 CT_GLIBC_VERSION="2.17"
+
 CT_GLIBC_MIRRORS="$(CT_Mirrors GNU glibc)"
 CT_GLIBC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
 CT_GLIBC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
@@ -391,6 +394,7 @@ CT_GLIBC_2_17_or_later=y
 CT_GLIBC_2_17_or_older=y
 CT_GLIBC_later_than_2_14=y
 CT_GLIBC_2_14_or_later=y
+
 CT_GLIBC_DEP_KERNEL_HEADERS_VERSION=y
 CT_GLIBC_DEP_BINUTILS=y
 CT_GLIBC_DEP_GCC=y
@@ -455,6 +459,7 @@ CT_GCC_PATCH_ORDER="global"
 CT_GCC_V_8=y
 # CT_GCC_NO_VERSIONS is not set
 CT_GCC_VERSION="8.3.0"
+
 CT_GCC_MIRRORS="$(CT_Mirrors GNU gcc/gcc-${CT_GCC_VERSION}) $(CT_Mirrors sourceware gcc/releases/gcc-${CT_GCC_VERSION})"
 CT_GCC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
 CT_GCC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
@@ -470,6 +475,7 @@ CT_GCC_later_than_4_9=y
 CT_GCC_4_9_or_later=y
 CT_GCC_later_than_4_8=y
 CT_GCC_4_8_or_later=y
+
 CT_CC_GCC_HAS_LIBMPX=y
 CT_CC_GCC_ENABLE_CXX_FLAGS=""
 CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY=""
@@ -716,4 +722,3 @@ CT_ZLIB=y
 # CT_COMP_TOOLS_M4 is not set
 # CT_COMP_TOOLS_MAKE is not set
 CT_ALL_COMP_TOOLS_CHOICES="AUTOCONF AUTOMAKE BISON DTC LIBTOOL M4 MAKE"
-
diff --git a/docker/dragonfly.sh b/docker/dragonfly.sh
index 75652e4..1644ecb 100755
--- a/docker/dragonfly.sh
+++ b/docker/dragonfly.sh
@@ -9,9 +9,9 @@ set -euo pipefail
 main() {
     local nproc=
     local binutils=2.32 \
-        dragonfly=6.0.1_REL \
-        gcc=10.3.0 \
-        target=x86_64-unknown-dragonfly
+          dragonfly=6.0.1_REL \
+          gcc=10.3.0 \
+          target=x86_64-unknown-dragonfly
     if [[ $# != "0" ]]; then
         nproc="${1}"
     fi
diff --git a/docker/dropbear.sh b/docker/dropbear.sh
index 5351cc8..ff213a2 100755
--- a/docker/dropbear.sh
+++ b/docker/dropbear.sh
@@ -36,15 +36,15 @@ main() {
     sed -i '/failed to identify current user/d' cli-runopts.c
 
     ./configure \
-        --disable-syslog \
-        --disable-shadow \
-        --disable-lastlog \
-        --disable-utmp \
-        --disable-utmpx \
-        --disable-wtmp \
-        --disable-wtmpx \
-        --disable-pututline \
-        --disable-pututxline
+       --disable-syslog \
+       --disable-shadow \
+       --disable-lastlog \
+       --disable-utmp \
+       --disable-utmpx \
+       --disable-wtmp \
+       --disable-wtmpx \
+       --disable-pututline \
+       --disable-pututxline
 
     make "-j$(nproc)" PROGRAMS=dbclient
     cp dbclient /usr/local/bin/
diff --git a/docker/freebsd.sh b/docker/freebsd.sh
index 339bd0b..423e0d0 100755
--- a/docker/freebsd.sh
+++ b/docker/freebsd.sh
@@ -48,8 +48,8 @@ bsd_http="http://${bsd_ftp}"
 
 main() {
     local binutils=2.32 \
-        gcc=6.4.0 \
-        target="${ARCH}-unknown-freebsd${BSD_MAJOR}"
+          gcc=6.4.0 \
+          target="${ARCH}-unknown-freebsd${BSD_MAJOR}"
 
     install_packages ca-certificates \
         curl \
diff --git a/docker/linux-image.sh b/docker/linux-image.sh
index 225c820..907d862 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-16
 
     local debsource="deb http://http.debian.net/debian/ bullseye main"
     debsource="${debsource}\ndeb http://security.debian.org/ bullseye-security main"
@@ -78,7 +78,7 @@ main() {
             ;;
         armv7)
             arch=armhf
-            kernel='5.*-armmp'
+            kernel="5.*-armmp"
             deps=(libcrypt1:"${arch}")
             ;;
         i686)
@@ -91,15 +91,15 @@ main() {
             libgcc="libgcc1"
             debsource="deb http://http.debian.net/debian/ buster main"
             debsource="${debsource}\ndeb http://security.debian.org/ buster/updates main"
-            kernel='4.*-4kc-malta'
+            kernel="4.*-4kc-malta"
             ncurses="=6.1*"
             ;;
         mipsel)
-            kernel='5.*-4kc-malta'
+            kernel="5.*-4kc-malta"
             deps=(libcrypt1:"${arch}")
             ;;
         mips64el)
-            kernel='5.*-5kc-malta'
+            kernel="5.*-5kc-malta"
             deps=(libcrypt1:"${arch}")
             ;;
         powerpc)
@@ -123,7 +123,7 @@ main() {
             # there is no stable port
             arch=ppc64
             # https://packages.debian.org/en/sid/linux-image-powerpc64
-            kernel='6.*-powerpc64'
+            kernel='5.*-powerpc64'
             debsource="deb http://ftp.ports.debian.org/debian-ports unstable main"
             debsource="${debsource}\ndeb http://ftp.ports.debian.org/debian-ports unreleased main"
             # sid version of dropbear requires these dependencies
@@ -131,24 +131,24 @@ main() {
             ;;
         powerpc64le)
             arch=ppc64el
-            kernel='5.*-powerpc64le'
+            kernel="5.*-powerpc64le"
             deps=(libcrypt1:"${arch}")
             ;;
         riscv64)
-            kernel='6.*-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'
+            kernel="5.*-s390x"
             deps=(libcrypt1:"${arch}")
             ;;
         sparc64)
             # there is no stable port
             # https://packages.debian.org/en/sid/linux-image-sparc64
-            kernel='6.*-sparc64'
+            kernel='5.*-sparc64'
             debsource="deb http://ftp.ports.debian.org/debian-ports unstable main"
             debsource="${debsource}\ndeb http://ftp.ports.debian.org/debian-ports unreleased main"
             # sid version of dropbear requires these dependencies
@@ -204,8 +204,8 @@ main() {
     curl --retry 3 -sSfL 'https://www.ports.debian.org/archive_{2020,2021,2022}.key' -O
 
     for key in *.asc *.key; do
-        apt-key add "${key}"
-        rm "${key}"
+      apt-key add "${key}"
+      rm "${key}"
     done
 
     # allow apt-get to retry downloads
diff --git a/docker/mingw.sh b/docker/mingw.sh
index 9dfef0e..92d6ddd 100755
--- a/docker/mingw.sh
+++ b/docker/mingw.sh
@@ -21,7 +21,7 @@ main() {
 
     local dependencies=(build-essential)
     while IFS='' read -r dep; do dependencies+=("${dep}"); done < \
-        <(apt-cache showsrc gcc-mingw-w64-i686 | grep Build | cut -d: -f2 | tr , '\n' | cut -d' ' -f2 | sort | uniq)
+      <(apt-cache showsrc gcc-mingw-w64-i686 | grep Build | cut -d: -f2 | tr , '\n' | cut -d' ' -f2 | sort | uniq)
 
     install_packages "${dependencies[@]}"
 
diff --git a/docker/musl-symlink.sh b/docker/musl-symlink.sh
index f67497f..a02dd7a 100755
--- a/docker/musl-symlink.sh
+++ b/docker/musl-symlink.sh
@@ -49,10 +49,6 @@ main() {
         fi
     done
 
-    # ensure we statically link libstdc++, so avoid segfaults with c++
-    # https://github.com/cross-rs/cross/issues/902
-    rm "${sysroot}"/lib/libstdc++.so* || true
-
     echo "${sysroot}/lib" >> "/etc/ld-musl-${arch}.path"
 
     rm -rf "${0}"
diff --git a/docker/musl.sh b/docker/musl.sh
index 2c51ff7..54d8163 100755
--- a/docker/musl.sh
+++ b/docker/musl.sh
@@ -9,9 +9,9 @@ set -euo pipefail
 hide_output() {
     set +x
     trap "
-        echo 'ERROR: An error was encountered with the build.'
-        cat /tmp/build.log
-        exit 1
+      echo 'ERROR: An error was encountered with the build.'
+      cat /tmp/build.log
+      exit 1
     " ERR
     bash -c 'while true; do sleep 30; echo $(date) - building ...; done' &
     PING_LOOP_PID=$!
@@ -36,20 +36,13 @@ main() {
     # Don't depend on the mirrors of sabotage linux that musl-cross-make uses.
     local linux_headers_site=https://ci-mirrors.rust-lang.org/rustc/sabotage-linux-tarballs
 
-    # alpine GCC is built with `--enable-default-pie`, so we want to
-    # ensure we use that. we want support for shared runtimes except for
-    # libstdc++, however, the only way to do that is to simply remove
-    # the shared libraries later. on alpine, binaries use static-pie
-    # linked, so our behavior has maximum portability, and is consistent
-    # with popular musl distros.
     hide_output make install "-j$(nproc)" \
         GCC_VER=9.2.0 \
         MUSL_VER=1.1.24 \
         BINUTILS_VER=2.33.1 \
         DL_CMD='curl --retry 3 -sSfL -C - -o' \
-        LINUX_HEADERS_SITE="${linux_headers_site}" \
+        LINUX_HEADERS_SITE=$linux_headers_site \
         OUTPUT=/usr/local/ \
-        "GCC_CONFIG += --enable-default-pie" \
         "${@}"
 
     purge_packages
diff --git a/docker/netbsd.sh b/docker/netbsd.sh
index 7eb1b27..0b9cac5 100755
--- a/docker/netbsd.sh
+++ b/docker/netbsd.sh
@@ -8,8 +8,8 @@ set -euo pipefail
 
 main() {
     local binutils=2.36.1 \
-        gcc=9.4.0 \
-        target=x86_64-unknown-netbsd
+          gcc=9.4.0 \
+          target=x86_64-unknown-netbsd
 
     install_packages bzip2 \
         ca-certificates \
diff --git a/docker/qemu.sh b/docker/qemu.sh
index 562491a..7feec31 100755
--- a/docker/qemu.sh
+++ b/docker/qemu.sh
@@ -115,7 +115,7 @@ main() {
     if_centos version=4.2.1
 
     local arch="${1}" \
-        softmmu="${2:-}"
+          softmmu="${2:-}"
 
     install_packages \
         autoconf \
diff --git a/docker/solaris.sh b/docker/solaris.sh
index 68796eb..5c485f6 100755
--- a/docker/solaris.sh
+++ b/docker/solaris.sh
@@ -10,8 +10,8 @@ main() {
     local arch="${1}"
 
     local binutils=2.28.1 \
-        gcc=8.4.0 \
-        target="${arch}-sun-solaris2.10"
+          gcc=8.4.0 \
+          target="${arch}-sun-solaris2.10"
 
     install_packages bzip2 \
         ca-certificates \
@@ -61,22 +61,22 @@ main() {
     apt-get update
     # shellcheck disable=SC2046
     apt-get download $(apt-cache depends --recurse --no-replaces \
-        "libc:${apt_arch}"            \
-        "liblgrp-dev:${apt_arch}"     \
-        "liblgrp:${apt_arch}"         \
-        "libm-dev:${apt_arch}"        \
-        "libpthread:${apt_arch}"      \
-        "libresolv:${apt_arch}"       \
-        "librt:${apt_arch}"           \
-        "libsendfile-dev:${apt_arch}" \
-        "libsendfile:${apt_arch}"     \
-        "libsocket:${apt_arch}"       \
-        "system-crt:${apt_arch}"      \
-        "system-header:${apt_arch}"   \
-        | grep "^\w")
+      "libc:${apt_arch}"            \
+      "liblgrp-dev:${apt_arch}"     \
+      "liblgrp:${apt_arch}"         \
+      "libm-dev:${apt_arch}"        \
+      "libpthread:${apt_arch}"      \
+      "libresolv:${apt_arch}"       \
+      "librt:${apt_arch}"           \
+      "libsendfile-dev:${apt_arch}" \
+      "libsendfile:${apt_arch}"     \
+      "libsocket:${apt_arch}"       \
+      "system-crt:${apt_arch}"      \
+      "system-header:${apt_arch}"   \
+      | grep "^\w")
 
     for deb in *"${apt_arch}.deb"; do
-        dpkg -x "${deb}" "${td}/solaris"
+      dpkg -x "${deb}" "${td}/solaris"
     done
 
     cd binutils-build
diff --git a/src/bin/commands/containers.rs b/src/bin/commands/containers.rs
index 0043280..1d6e226 100644
--- a/src/bin/commands/containers.rs
+++ b/src/bin/commands/containers.rs
@@ -396,7 +396,7 @@ pub fn create_persistent_volume(
     if let Some(channel) = channel {
         toolchain.channel = channel.channel.clone();
     };
-    let mount_finder = docker::MountFinder::create(engine, msg_info)?;
+    let mount_finder = docker::MountFinder::create(engine)?;
     let dirs = docker::ToolchainDirectories::assemble(&mount_finder, toolchain.clone())?;
     let container_id = dirs.unique_container_identifier(&toolchain.host().target)?;
     let volume_id = dirs.unique_toolchain_identifier()?;
@@ -445,9 +445,9 @@ pub fn create_persistent_volume(
     docker.run_and_get_status(msg_info, true)?;
 
     let data_volume = docker::ContainerDataVolume::new(engine, &container_id, &dirs);
-    data_volume.copy_xargo(mount_prefix, msg_info)?;
-    data_volume.copy_cargo(mount_prefix, copy_registry, msg_info)?;
-    data_volume.copy_rust(None, mount_prefix, msg_info)?;
+    data_volume.copy_xargo(mount_prefix.as_ref(), msg_info)?;
+    data_volume.copy_cargo(mount_prefix.as_ref(), copy_registry, msg_info)?;
+    data_volume.copy_rust(None, mount_prefix.as_ref(), msg_info)?;
 
     docker::ChildContainer::finish_static(is_tty, msg_info);
 
@@ -464,7 +464,7 @@ pub fn remove_persistent_volume(
     if let Some(channel) = channel {
         toolchain.channel = channel.channel.clone();
     };
-    let mount_finder = docker::MountFinder::create(engine, msg_info)?;
+    let mount_finder = docker::MountFinder::create(engine)?;
     let dirs = docker::ToolchainDirectories::assemble(&mount_finder, toolchain)?;
     let volume_id = dirs.unique_toolchain_identifier()?;
     let volume = docker::DockerVolume::new(engine, &volume_id);
diff --git a/src/bin/commands/images.rs b/src/bin/commands/images.rs
index c511b50..fa59f83 100644
--- a/src/bin/commands/images.rs
+++ b/src/bin/commands/images.rs
@@ -1,6 +1,5 @@
 use std::collections::{BTreeMap, BTreeSet};
 
-use clap::builder::PossibleValue;
 use clap::{Args, Subcommand};
 use cross::docker::{self, CROSS_CUSTOM_DOCKERFILE_IMAGE_PREFIX};
 use cross::shell::MessageInfo;
@@ -27,9 +26,6 @@ pub struct ListImages {
     /// Container engine (such as docker or podman).
     #[clap(long)]
     pub engine: Option<String>,
-    /// Output format
-    #[clap(long, default_value = "human")]
-    pub format: OutputFormat,
     /// Only list images for specific target(s). By default, list all targets.
     pub targets: Vec<String>,
 }
@@ -40,25 +36,6 @@ impl ListImages {
     }
 }
 
-#[derive(Clone, Debug)]
-pub enum OutputFormat {
-    Human,
-    Json,
-}
-
-impl clap::ValueEnum for OutputFormat {
-    fn value_variants<'a>() -> &'a [Self] {
-        &[Self::Human, Self::Json]
-    }
-
-    fn to_possible_value(&self) -> Option<PossibleValue> {
-        match self {
-            OutputFormat::Human => Some(PossibleValue::new("human")),
-            OutputFormat::Json => Some(PossibleValue::new("json")),
-        }
-    }
-}
-
 #[derive(Args, Debug)]
 pub struct RemoveImages {
     /// If not provided, remove all images.
@@ -141,7 +118,7 @@ impl Images {
     }
 }
 
-#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, serde::Serialize)]
+#[derive(Debug, PartialOrd, Ord, PartialEq, Eq)]
 struct Image {
     repository: String,
     tag: String,
@@ -281,9 +258,7 @@ fn get_image_target(
 }
 
 pub fn list_images(
-    ListImages {
-        targets, format, ..
-    }: ListImages,
+    ListImages { targets, .. }: ListImages,
     engine: &docker::Engine,
     msg_info: &mut MessageInfo,
 ) -> cross::Result<()> {
@@ -306,55 +281,45 @@ pub fn list_images(
     let mut keys: Vec<&str> = map.keys().map(|k| k.as_ref()).collect();
     keys.sort_unstable();
 
-    match format {
-        OutputFormat::Json => {
-            msg_info.info(format_args!("{}", serde_json::to_string(&map)?))?;
-        }
-        OutputFormat::Human => {
-            let print_string =
-                |col1: &str, col2: &str, fill: char, info: &mut MessageInfo| -> cross::Result<()> {
-                    let mut row = String::new();
-                    row.push('|');
-                    row.push(fill);
-                    row.push_str(col1);
-                    let spaces = max_target_len.max(col1.len()) + 1 - col1.len();
-                    for _ in 0..spaces {
-                        row.push(fill);
-                    }
-                    row.push('|');
-                    row.push(fill);
-                    row.push_str(col2);
-                    let spaces = max_image_len.max(col2.len()) + 1 - col2.len();
-                    for _ in 0..spaces {
-                        row.push(fill);
-                    }
-                    row.push('|');
-                    info.print(row)
-                };
-
-            if targets.len() != 1 {
-                print_string("Targets", "Images", ' ', msg_info)?;
-                print_string("-------", "------", '-', msg_info)?;
+    let print_string =
+        |col1: &str, col2: &str, fill: char, info: &mut MessageInfo| -> cross::Result<()> {
+            let mut row = String::new();
+            row.push('|');
+            row.push(fill);
+            row.push_str(col1);
+            let spaces = max_target_len.max(col1.len()) + 1 - col1.len();
+            for _ in 0..spaces {
+                row.push(fill);
             }
+            row.push('|');
+            row.push(fill);
+            row.push_str(col2);
+            let spaces = max_image_len.max(col2.len()) + 1 - col2.len();
+            for _ in 0..spaces {
+                row.push(fill);
+            }
+            row.push('|');
+            info.print(row)
+        };
+
+    if targets.len() != 1 {
+        print_string("Targets", "Images", ' ', msg_info)?;
+        print_string("-------", "------", '-', msg_info)?;
+    }
 
-            let print_single = |_: &str,
-                                image: &Image,
-                                info: &mut MessageInfo|
-             -> cross::Result<()> { info.print(image) };
-            let print_table =
-                |target: &str, image: &Image, info: &mut MessageInfo| -> cross::Result<()> {
-                    let name = image.name();
-                    print_string(target, &name, ' ', info)
-                };
-
-            for target in keys {
-                for image in map.get(target).expect("map must have key").iter() {
-                    if targets.len() == 1 {
-                        print_single(target, image, msg_info)?;
-                    } else {
-                        print_table(target, image, msg_info)?;
-                    }
-                }
+    let print_single =
+        |_: &str, image: &Image, info: &mut MessageInfo| -> cross::Result<()> { info.print(image) };
+    let print_table = |target: &str, image: &Image, info: &mut MessageInfo| -> cross::Result<()> {
+        let name = image.name();
+        print_string(target, &name, ' ', info)
+    };
+
+    for target in keys {
+        for image in map.get(target).expect("map must have key").iter() {
+            if targets.len() == 1 {
+                print_single(target, image, msg_info)?;
+            } else {
+                print_table(target, image, msg_info)?;
             }
         }
     }
diff --git a/src/bin/cross.rs b/src/bin/cross.rs
index 64536d2..9210683 100644
--- a/src/bin/cross.rs
+++ b/src/bin/cross.rs
@@ -18,7 +18,13 @@ pub fn main() -> cross::Result<()> {
     let target_list = rustc::target_list(&mut Verbosity::Quiet.into())?;
     let args = cli::parse(&target_list)?;
     let subcommand = args.subcommand;
-    let mut msg_info = shell::MessageInfo::create(args.verbose, args.quiet, args.color.as_deref())?;
+    let mut msg_info = shell::MessageInfo::create(
+        args.verbose
+            + cross::config::bool_from_envvar(&std::env::var("CROSS_DEBUG").unwrap_or_default())
+                as u8,
+        args.quiet,
+        args.color.as_deref(),
+    )?;
     let status = match cross::run(args, target_list, &mut msg_info)? {
         Some(status) => status,
         None => {
diff --git a/src/docker/custom.rs b/src/docker/custom.rs
index 2a7173a..259de44 100644
--- a/src/docker/custom.rs
+++ b/src/docker/custom.rs
@@ -259,7 +259,7 @@ fn docker_tag_name(file_name: &str) -> String {
     let mut consecutive_underscores = 0;
     for c in file_name.chars() {
         match c {
-            'a'..='z' | '0'..='9' | '.' | '-' => {
+            'a'..='z' | '.' | '-' => {
                 consecutive_underscores = 0;
                 result.push(c);
             }
@@ -278,11 +278,7 @@ fn docker_tag_name(file_name: &str) -> String {
         }
     }
 
-    // in case all characters were invalid or we had all non-ASCII
-    // characters followed by a `-`, we use a non-empty filename
-    if result.ends_with('-') {
-        result.pop();
-    }
+    // in case all characters were invalid, use a non-empty filename
     if result.is_empty() {
         result = "empty".to_owned();
     }
@@ -316,8 +312,5 @@ mod tests {
             docker_tag_name("pAcKaGe---test.name"),
             s!("package---test.name")
         );
-
-        assert_eq!(docker_tag_name("foo-123"), s!("foo-123"));
-        assert_eq!(docker_tag_name("foo-123-"), s!("foo-123"));
     }
 }
diff --git a/src/docker/remote.rs b/src/docker/remote.rs
index 2a05553..cba7565 100644
--- a/src/docker/remote.rs
+++ b/src/docker/remote.rs
@@ -1,6 +1,6 @@
 use std::collections::BTreeMap;
 use std::io::{self, BufRead, Read, Write};
-use std::path::Path;
+use std::path::{Path, PathBuf};
 use std::process::{Command, ExitStatus};
 use std::{env, fs, time};
 
@@ -29,58 +29,38 @@ macro_rules! bail_container_exited {
     }};
 }
 
-#[track_caller]
 fn subcommand_or_exit(engine: &Engine, cmd: &str) -> Result<Command> {
     bail_container_exited!();
     Ok(engine.subcommand(cmd))
 }
 
-pub fn posix_parent(path: &str) -> Option<&str> {
-    Path::new(path).parent()?.to_str()
-}
-
 impl<'a, 'b, 'c> ContainerDataVolume<'a, 'b, 'c> {
-    // NOTE: `reldir` should be a relative POSIX path to the root directory
-    // on windows, this should be something like `mnt/c`. that is, all paths
-    // inside the container should not have the mount prefix.
-    #[track_caller]
-    fn create_dir(
-        &self,
-        reldir: &str,
-        mount_prefix: &str,
-        msg_info: &mut MessageInfo,
-    ) -> Result<ExitStatus> {
+    fn create_dir(&self, dir: &Path, msg_info: &mut MessageInfo) -> Result<ExitStatus> {
         // make our parent directory if needed
         subcommand_or_exit(self.engine, "exec")?
             .arg(self.container)
-            .args(["sh", "-c", &format!("mkdir -p '{mount_prefix}/{reldir}'")])
+            .args([
+                "sh",
+                "-c",
+                &format!("mkdir -p '{}'", dir.as_posix_absolute()?),
+            ])
             .run_and_get_status(msg_info, false)
     }
 
     // copy files for a docker volume, for remote host support
-    // NOTE: `reldst` has the same caveats as `reldir` in `create_dir`.
-    #[track_caller]
-    fn copy_files(
-        &self,
-        src: &Path,
-        reldst: &str,
-        mount_prefix: &str,
-        msg_info: &mut MessageInfo,
-    ) -> Result<ExitStatus> {
+    fn copy_files(&self, src: &Path, dst: &Path, msg_info: &mut MessageInfo) -> Result<ExitStatus> {
         subcommand_or_exit(self.engine, "cp")?
             .arg("-a")
             .arg(src.to_utf8()?)
-            .arg(format!("{}:{mount_prefix}/{reldst}", self.container))
+            .arg(format!("{}:{}", self.container, dst.as_posix_absolute()?))
             .run_and_get_status(msg_info, false)
     }
 
     // copy files for a docker volume, for remote host support
-    #[track_caller]
     fn copy_files_nocache(
         &self,
         src: &Path,
-        reldst: &str,
-        mount_prefix: &str,
+        dst: &Path,
         copy_symlinks: bool,
         msg_info: &mut MessageInfo,
     ) -> Result<ExitStatus> {
@@ -91,17 +71,15 @@ impl<'a, 'b, 'c> ContainerDataVolume<'a, 'b, 'c> {
         let temppath = tempdir.path();
         let had_symlinks = copy_dir(src, temppath, copy_symlinks, 0, |e, _| is_cachedir(e))?;
         warn_symlinks(had_symlinks, msg_info)?;
-        self.copy_files(&temppath.join("."), reldst, mount_prefix, msg_info)
+        self.copy_files(&temppath.join("."), dst, msg_info)
     }
 
     // copy files for a docker volume, for remote host support
     // provides a list of files relative to src.
-    #[track_caller]
     fn copy_file_list(
         &self,
         src: &Path,
-        reldst: &str,
-        mount_prefix: &str,
+        dst: &Path,
         files: &[&str],
         msg_info: &mut MessageInfo,
     ) -> Result<ExitStatus> {
@@ -116,16 +94,14 @@ impl<'a, 'b, 'c> ContainerDataVolume<'a, 'b, 'c> {
         }
         // if copying from a src directory to dst directory with docker, to
         // copy the contents from `src` into `dst`, `src` must end with `/.`
-        self.copy_files(&temppath.join("."), reldst, mount_prefix, msg_info)
+        self.copy_files(&temppath.join("."), dst, msg_info)
     }
 
     // removed files from a docker volume, for remote host support
     // provides a list of files relative to src.
-    #[track_caller]
     fn remove_file_list(
         &self,
-        reldst: &str,
-        mount_prefix: &str,
+        dst: &Path,
         files: &[&str],
         msg_info: &mut MessageInfo,
     ) -> Result<ExitStatus> {
@@ -146,7 +122,7 @@ impl<'a, 'b, 'c> ContainerDataVolume<'a, 'b, 'c> {
         // SAFETY: safe, single-threaded execution.
         let mut tempfile = unsafe { temp::TempFile::new()? };
         for file in files {
-            writeln!(tempfile.file(), "{mount_prefix}/{reldst}/{file}")?;
+            writeln!(tempfile.file(), "{}", dst.join(file).as_posix_relative()?)?;
         }
 
         // need to avoid having hundreds of files on the command, so
@@ -162,64 +138,49 @@ impl<'a, 'b, 'c> ContainerDataVolume<'a, 'b, 'c> {
             .run_and_get_status(msg_info, true)
     }
 
-    #[track_caller]
-    fn container_path_exists(
-        &self,
-        relpath: &str,
-        mount_prefix: &str,
-        msg_info: &mut MessageInfo,
-    ) -> Result<bool> {
+    fn container_path_exists(&self, path: &Path, msg_info: &mut MessageInfo) -> Result<bool> {
         Ok(subcommand_or_exit(self.engine, "exec")?
             .arg(self.container)
             .args([
                 "bash",
                 "-c",
-                &format!("[[ -d '{mount_prefix}/{relpath}' ]]"),
+                &format!("[[ -d '{}' ]]", path.as_posix_absolute()?),
             ])
             .run_and_get_status(msg_info, true)?
             .success())
     }
 
-    #[track_caller]
-    pub fn copy_xargo(&self, mount_prefix: &str, msg_info: &mut MessageInfo) -> Result<()> {
+    pub fn copy_xargo(&self, mount_prefix: &Path, msg_info: &mut MessageInfo) -> Result<()> {
         let dirs = &self.toolchain_dirs;
-        let reldst = dirs.xargo_mount_path_relative()?;
+        let dst = mount_prefix.join(&dirs.xargo_mount_path_relative()?);
         if dirs.xargo().exists() {
             self.create_dir(
-                // this always works, even if we have `/xargo`, since
-                // this will be an absolute path. passing an empty path
-                // to `create_dir` isn't an issue.
-                posix_parent(dirs.xargo_mount_path())
-                    .expect("destination should have a parent")
-                    .strip_prefix('/')
-                    .expect("parent directory must be absolute"),
-                mount_prefix,
+                dst.parent().expect("destination should have a parent"),
                 msg_info,
             )?;
-            self.copy_files(dirs.xargo(), &reldst, mount_prefix, msg_info)?;
+            self.copy_files(dirs.xargo(), &dst, msg_info)?;
         }
 
         Ok(())
     }
 
-    #[track_caller]
     pub fn copy_cargo(
         &self,
-        mount_prefix: &str,
+        mount_prefix: &Path,
         copy_registry: bool,
         msg_info: &mut MessageInfo,
     ) -> Result<()> {
         let dirs = &self.toolchain_dirs;
-        let reldst = dirs.cargo_mount_path_relative()?;
+        let dst = mount_prefix.join(&dirs.cargo_mount_path_relative()?);
         let copy_registry = env::var("CROSS_REMOTE_COPY_REGISTRY")
             .map(|s| bool_from_envvar(&s))
             .unwrap_or(copy_registry);
 
         if copy_registry {
-            self.copy_files(dirs.cargo(), &reldst, mount_prefix, msg_info)?;
+            self.copy_files(dirs.cargo(), &dst, msg_info)?;
         } else {
             // can copy a limit subset of files: the rest is present.
-            self.create_dir(&reldst, mount_prefix, msg_info)?;
+            self.create_dir(&dst, msg_info)?;
             for entry in fs::read_dir(dirs.cargo())
                 .wrap_err_with(|| format!("when reading directory {:?}", dirs.cargo()))?
             {
@@ -230,7 +191,7 @@ impl<'a, 'b, 'c> ContainerDataVolume<'a, 'b, 'c> {
                     .wrap_err_with(|| format!("when reading file {file:?}"))?
                     .to_owned();
                 if !basename.starts_with('.') && !matches!(basename.as_ref(), "git" | "registry") {
-                    self.copy_files(&file.path(), &reldst, mount_prefix, msg_info)?;
+                    self.copy_files(&file.path(), &dst, msg_info)?;
                 }
             }
         }
@@ -239,18 +200,17 @@ impl<'a, 'b, 'c> ContainerDataVolume<'a, 'b, 'c> {
     }
 
     // copy over files needed for all targets in the toolchain that should never change
-    #[track_caller]
-    fn copy_rust_base(&self, mount_prefix: &str, msg_info: &mut MessageInfo) -> Result<()> {
+    fn copy_rust_base(&self, mount_prefix: &Path, msg_info: &mut MessageInfo) -> Result<()> {
         let dirs = &self.toolchain_dirs;
 
         // the rust toolchain is quite large, but most of it isn't needed
         // we need the bin, libexec, and etc directories, and part of the lib directory.
-        let reldst = dirs.sysroot_mount_path_relative()?;
-        let rustlib = "lib/rustlib";
-        self.create_dir(&format!("{reldst}/{}", rustlib), mount_prefix, msg_info)?;
+        let dst = mount_prefix.join(&dirs.sysroot_mount_path_relative()?);
+        let rustlib = Path::new("lib").join("rustlib");
+        self.create_dir(&dst.join(&rustlib), msg_info)?;
         for basename in ["bin", "libexec", "etc"] {
             let file = dirs.get_sysroot().join(basename);
-            self.copy_files(&file, &reldst, mount_prefix, msg_info)?;
+            self.copy_files(&file, &dst, msg_info)?;
         }
 
         // the lib directories are rather large, so we want only a subset.
@@ -261,7 +221,7 @@ impl<'a, 'b, 'c> ContainerDataVolume<'a, 'b, 'c> {
         // SAFETY: safe, single-threaded execution.
         let tempdir = unsafe { temp::TempDir::new()? };
         let temppath = tempdir.path();
-        file::create_dir_all(&temppath.join(rustlib))?;
+        file::create_dir_all(&temppath.join(&rustlib))?;
         let mut had_symlinks = copy_dir(
             &dirs.get_sysroot().join("lib"),
             &temppath.join("lib"),
@@ -272,71 +232,69 @@ impl<'a, 'b, 'c> ContainerDataVolume<'a, 'b, 'c> {
 
         // next, copy the src/etc directories inside rustlib
         had_symlinks |= copy_dir(
-            &dirs.get_sysroot().join(rustlib),
-            &temppath.join(rustlib),
+            &dirs.get_sysroot().join(&rustlib),
+            &temppath.join(&rustlib),
             true,
             0,
             |e, d| d == 0 && !(e.file_name() == "src" || e.file_name() == "etc"),
         )?;
-        self.copy_files(&temppath.join("lib"), &reldst, mount_prefix, msg_info)?;
+        self.copy_files(&temppath.join("lib"), &dst, msg_info)?;
 
         warn_symlinks(had_symlinks, msg_info)
     }
 
-    #[track_caller]
-    fn copy_rust_manifest(&self, mount_prefix: &str, msg_info: &mut MessageInfo) -> Result<()> {
+    fn copy_rust_manifest(&self, mount_prefix: &Path, msg_info: &mut MessageInfo) -> Result<()> {
         let dirs = &self.toolchain_dirs;
 
         // copy over all the manifest files in rustlib
         // these are small text files containing names/paths to toolchains
-        let reldst = dirs.sysroot_mount_path_relative()?;
-        let rustlib = "lib/rustlib";
+        let dst = mount_prefix.join(&dirs.sysroot_mount_path_relative()?);
+        let rustlib = Path::new("lib").join("rustlib");
 
         // SAFETY: safe, single-threaded execution.
         let tempdir = unsafe { temp::TempDir::new()? };
         let temppath = tempdir.path();
-        file::create_dir_all(&temppath.join(rustlib))?;
+        file::create_dir_all(&temppath.join(&rustlib))?;
         let had_symlinks = copy_dir(
-            &dirs.get_sysroot().join(rustlib),
-            &temppath.join(rustlib),
+            &dirs.get_sysroot().join(&rustlib),
+            &temppath.join(&rustlib),
             true,
             0,
             |e, d| d != 0 || e.file_type().map(|t| !t.is_file()).unwrap_or(true),
         )?;
-        self.copy_files(&temppath.join("lib"), &reldst, mount_prefix, msg_info)?;
+        self.copy_files(&temppath.join("lib"), &dst, msg_info)?;
 
         warn_symlinks(had_symlinks, msg_info)
     }
 
     // copy over the toolchain for a specific triple
-    #[track_caller]
     fn copy_rust_triple(
         &self,
         target_triple: &TargetTriple,
-        mount_prefix: &str,
+        mount_prefix: &Path,
         skip_exists: bool,
         msg_info: &mut MessageInfo,
     ) -> Result<()> {
         let dirs = &self.toolchain_dirs;
 
         // copy over the files for a specific triple
-        let reldst = &dirs.sysroot_mount_path_relative()?;
-        let rustlib = "lib/rustlib";
-        let reldst_rustlib = format!("{reldst}/{rustlib}");
+        let dst = mount_prefix.join(&dirs.sysroot_mount_path_relative()?);
+        let rustlib = Path::new("lib").join("rustlib");
+        let dst_rustlib = dst.join(&rustlib);
         let src_toolchain = dirs
             .get_sysroot()
-            .join(Path::new(rustlib))
+            .join(&rustlib)
             .join(target_triple.triple());
-        let reldst_toolchain = format!("{reldst_rustlib}/{}", target_triple.triple());
+        let dst_toolchain = dst_rustlib.join(target_triple.triple());
 
         // skip if the toolchain target component already exists. for the host toolchain
         // or the first run of the target toolchain, we know it doesn't exist.
         let mut skip = false;
         if skip_exists {
-            skip = self.container_path_exists(&reldst_toolchain, mount_prefix, msg_info)?;
+            skip = self.container_path_exists(&dst_toolchain, msg_info)?;
         }
         if !skip {
-            self.copy_files(&src_toolchain, &reldst_rustlib, mount_prefix, msg_info)?;
+            self.copy_files(&src_toolchain, &dst_rustlib, msg_info)?;
         }
         if !skip && skip_exists {
             // this means we have a persistent data volume and we have a
@@ -347,11 +305,10 @@ impl<'a, 'b, 'c> ContainerDataVolume<'a, 'b, 'c> {
         Ok(())
     }
 
-    #[track_caller]
     pub fn copy_rust(
         &self,
         target_triple: Option<&TargetTriple>,
-        mount_prefix: &str,
+        mount_prefix: &Path,
         msg_info: &mut MessageInfo,
     ) -> Result<()> {
         let dirs = &self.toolchain_dirs;
@@ -368,21 +325,19 @@ impl<'a, 'b, 'c> ContainerDataVolume<'a, 'b, 'c> {
         Ok(())
     }
 
-    #[track_caller]
     fn copy_mount(
         &self,
         src: &Path,
-        reldst: &str,
-        mount_prefix: &str,
+        dst: &Path,
         volume: &VolumeId,
         copy_cache: bool,
         msg_info: &mut MessageInfo,
     ) -> Result<()> {
         let copy_all = |info: &mut MessageInfo| {
             if copy_cache {
-                self.copy_files(src, reldst, mount_prefix, info)
+                self.copy_files(src, dst, info)
             } else {
-                self.copy_files_nocache(src, reldst, mount_prefix, true, info)
+                self.copy_files_nocache(src, dst, true, info)
             }
         };
         match volume {
@@ -396,16 +351,14 @@ impl<'a, 'b, 'c> ContainerDataVolume<'a, 'b, 'c> {
                 let current = Fingerprint::read_dir(src, copy_cache)?;
                 // need to check if the container path exists, otherwise we might
                 // have stale data: the persistent volume was deleted & recreated.
-                if fingerprint.exists()
-                    && self.container_path_exists(reldst, mount_prefix, msg_info)?
-                {
+                if fingerprint.exists() && self.container_path_exists(dst, msg_info)? {
                     let previous = Fingerprint::read_file(&fingerprint)?;
                     let (to_copy, to_remove) = previous.difference(&current);
                     if !to_copy.is_empty() {
-                        self.copy_file_list(src, reldst, mount_prefix, &to_copy, msg_info)?;
+                        self.copy_file_list(src, dst, &to_copy, msg_info)?;
                     }
                     if !to_remove.is_empty() {
-                        self.remove_file_list(reldst, mount_prefix, &to_remove, msg_info)?;
+                        self.remove_file_list(dst, &to_remove, msg_info)?;
                     }
 
                     // write fingerprint afterwards, in case any failure so we
@@ -779,23 +732,24 @@ pub(crate) fn run(
     let copy_cache = env::var("CROSS_REMOTE_COPY_CACHE")
         .map(|s| bool_from_envvar(&s))
         .unwrap_or_default();
-    let copy = |src, reldst: &str, info: &mut MessageInfo| {
-        data_volume.copy_mount(src, reldst, mount_prefix, &volume, copy_cache, info)
+    let copy = |src, dst: &PathBuf, info: &mut MessageInfo| {
+        data_volume.copy_mount(src, dst, &volume, copy_cache, info)
     };
+    let mount_prefix_path = mount_prefix.as_ref();
     if let VolumeId::Discard = volume {
         data_volume
-            .copy_xargo(mount_prefix, msg_info)
+            .copy_xargo(mount_prefix_path, msg_info)
             .wrap_err("when copying xargo")?;
         data_volume
-            .copy_cargo(mount_prefix, false, msg_info)
+            .copy_cargo(mount_prefix_path, false, msg_info)
             .wrap_err("when copying cargo")?;
         data_volume
-            .copy_rust(Some(target.target()), mount_prefix, msg_info)
+            .copy_rust(Some(target.target()), mount_prefix_path, msg_info)
             .wrap_err("when copying rust")?;
     } else {
         // need to copy over the target triple if it hasn't been previously copied
         data_volume
-            .copy_rust_triple(target.target(), mount_prefix, true, msg_info)
+            .copy_rust_triple(target.target(), mount_prefix_path, true, msg_info)
             .wrap_err("when copying rust target files")?;
     }
     // cannot panic: absolute unix path, must have root
@@ -803,41 +757,46 @@ pub(crate) fn run(
         .mount_root()
         .strip_prefix('/')
         .expect("mount root should be absolute");
+    let mount_root = mount_prefix_path.join(rel_mount_root);
     if !rel_mount_root.is_empty() {
         data_volume
             .create_dir(
-                posix_parent(rel_mount_root).expect("mount root should have a parent directory"),
-                mount_prefix,
+                mount_root
+                    .parent()
+                    .expect("mount root should have a parent directory"),
                 msg_info,
             )
             .wrap_err("when creating mount root")?;
     }
-    copy(package_dirs.host_root(), rel_mount_root, msg_info).wrap_err("when copying project")?;
+    copy(package_dirs.host_root(), &mount_root, msg_info).wrap_err("when copying project")?;
     let sysroot = toolchain_dirs.get_sysroot().to_owned();
     let mut copied = vec![
         (
             toolchain_dirs.xargo(),
-            toolchain_dirs.xargo_mount_path_relative()?,
+            mount_prefix_path.join(&toolchain_dirs.xargo_mount_path_relative()?),
         ),
         (
             toolchain_dirs.cargo(),
-            toolchain_dirs.cargo_mount_path_relative()?,
+            mount_prefix_path.join(&toolchain_dirs.cargo_mount_path_relative()?),
+        ),
+        (
+            &sysroot,
+            mount_prefix_path.join(&toolchain_dirs.sysroot_mount_path_relative()?),
         ),
-        (&sysroot, toolchain_dirs.sysroot_mount_path_relative()?),
-        (package_dirs.host_root(), rel_mount_root.to_owned()),
+        (package_dirs.host_root(), mount_root.clone()),
     ];
     let mut to_symlink = vec![];
     let target_dir = file::canonicalize(package_dirs.target())?;
     let target_dir = if let Ok(relpath) = target_dir.strip_prefix(package_dirs.host_root()) {
-        relpath.as_posix_relative()?
+        mount_root.join(relpath)
     } else {
         // outside project, need to copy the target data over
         // only do if we're copying over cached files.
-        let target_dir = "target".to_owned();
+        let target_dir = mount_prefix_path.join("target");
         if copy_cache {
             copy(package_dirs.target(), &target_dir, msg_info)?;
         } else {
-            data_volume.create_dir(&target_dir, mount_prefix, msg_info)?;
+            data_volume.create_dir(&target_dir, msg_info)?;
         }
 
         copied.push((package_dirs.target(), target_dir.clone()));
@@ -849,21 +808,22 @@ pub(crate) fn run(
             // path has already been copied over
             let relpath = src
                 .strip_prefix(psrc)
-                .expect("source should start with prefix")
-                .as_posix_relative()?;
-            to_symlink.push((format!("{pdst}/{relpath}"), dst));
+                .expect("source should start with prefix");
+            to_symlink.push((pdst.join(relpath), dst));
         } else {
-            let reldst = dst
+            let rel_dst = dst
                 .strip_prefix('/')
                 .expect("destination should be absolute");
-            if !reldst.is_empty() {
+            let mount_dst = mount_prefix_path.join(rel_dst);
+            if !rel_dst.is_empty() {
                 data_volume.create_dir(
-                    posix_parent(reldst).expect("destination should have a parent directory"),
-                    mount_prefix,
+                    mount_dst
+                        .parent()
+                        .expect("destination should have a parent directory"),
                     msg_info,
                 )?;
             }
-            copy(src, reldst, msg_info)?;
+            copy(src, &mount_dst, msg_info)?;
         }
     }
 
@@ -873,17 +833,18 @@ 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()?;
     while let Some(arg) = iter.next() {
         if arg == "--target-dir" {
             has_target_dir = true;
             final_args.push(arg);
             if iter.next().is_some() {
-                final_args.push(target_dir.clone());
+                final_args.push(target_dir_string.clone());
             }
         } else if arg.starts_with("--target-dir=") {
             has_target_dir = true;
             if arg.split_once('=').is_some() {
-                final_args.push(format!("--target-dir={target_dir}"));
+                final_args.push(format!("--target-dir={target_dir_string}"));
             }
         } else {
             final_args.push(arg);
@@ -891,7 +852,7 @@ pub(crate) fn run(
     }
     if !has_target_dir {
         final_args.push("--target-dir".to_owned());
-        final_args.push(target_dir.clone());
+        final_args.push(target_dir_string);
     }
     let mut cmd = options.cargo_variant.safe_command();
     cmd.args(final_args);
@@ -928,7 +889,11 @@ symlink_recurse \"${{prefix}}\"
 "
     ));
     for (src, dst) in to_symlink {
-        symlink.push(format!("ln -s \"{src}\" \"{dst}\"",));
+        symlink.push(format!(
+            "ln -s \"{}\" \"{}\"",
+            src.as_posix_absolute()?,
+            dst
+        ));
     }
     subcommand_or_exit(engine, "exec")?
         .arg(&container_id)
@@ -954,10 +919,13 @@ symlink_recurse \"${{prefix}}\"
         .map(|s| bool_from_envvar(&s))
         .unwrap_or_default();
     bail_container_exited!();
-    if !skip_artifacts && data_volume.container_path_exists(&target_dir, mount_prefix, msg_info)? {
+    if !skip_artifacts && data_volume.container_path_exists(&target_dir, msg_info)? {
         subcommand_or_exit(engine, "cp")?
             .arg("-a")
-            .arg(&format!("{container_id}:{target_dir}",))
+            .arg(&format!(
+                "{container_id}:{}",
+                target_dir.as_posix_absolute()?
+            ))
             .arg(
                 package_dirs
                     .target()
diff --git a/src/docker/shared.rs b/src/docker/shared.rs
index b94836e..1d84f74 100644
--- a/src/docker/shared.rs
+++ b/src/docker/shared.rs
@@ -86,9 +86,6 @@ impl DockerOptions {
         msg_info: &mut MessageInfo,
     ) -> Result<String> {
         let mut image = self.image.clone();
-        if self.target.triple() == "arm-unknown-linux-gnueabihf" {
-            msg_info.note("cannot install armhf system packages via apt for `arm-unknown-linux-gnueabihf`, since they are for ARMv7a targets but this target is ARMv6. installation of all packages for the armhf architecture has been blocked.")?;
-        }
 
         if let Some(path) = self.config.dockerfile(&self.target)? {
             let context = self.config.dockerfile_context(&self.target)?;
@@ -203,9 +200,8 @@ impl DockerPaths {
         metadata: CargoMetadata,
         cwd: PathBuf,
         toolchain: QualifiedToolchain,
-        msg_info: &mut MessageInfo,
     ) -> Result<Self> {
-        let mount_finder = MountFinder::create(engine, msg_info)?;
+        let mount_finder = MountFinder::create(engine)?;
         let (directories, metadata) =
             Directories::assemble(&mount_finder, metadata, &cwd, toolchain)?;
         Ok(Self {
@@ -699,26 +695,22 @@ impl<'a, 'b> DockerVolume<'a, 'b> {
         Self { engine, name }
     }
 
-    #[track_caller]
     pub fn create(&self, msg_info: &mut MessageInfo) -> Result<ExitStatus> {
         self.engine
             .run_and_get_status(&["volume", "create", self.name], msg_info)
     }
 
-    #[track_caller]
     pub fn remove(&self, msg_info: &mut MessageInfo) -> Result<ExitStatus> {
         self.engine
             .run_and_get_status(&["volume", "rm", self.name], msg_info)
     }
 
-    #[track_caller]
     pub fn exists(&self, msg_info: &mut MessageInfo) -> Result<bool> {
         self.engine
             .run_and_get_output(&["volume", "inspect", self.name], msg_info)
             .map(|output| output.status.success())
     }
 
-    #[track_caller]
     pub fn existing(
         engine: &Engine,
         toolchain: &QualifiedToolchain,
@@ -841,7 +833,6 @@ impl Engine {
         command
     }
 
-    #[track_caller]
     pub(crate) fn run_and_get_status(
         &self,
         args: &[&str],
@@ -850,7 +841,6 @@ impl Engine {
         self.command().args(args).run_and_get_status(msg_info, true)
     }
 
-    #[track_caller]
     pub(crate) fn run_and_get_output(
         &self,
         args: &[&str],
@@ -930,7 +920,7 @@ impl CargoVariant {
 }
 
 pub(crate) trait DockerCommandExt {
-    fn add_configuration_envvars(&mut self);
+    fn add_cargo_configuration_envvars(&mut self);
     fn add_envvars(
         &mut self,
         options: &DockerOptions,
@@ -958,8 +948,8 @@ pub(crate) trait DockerCommandExt {
 }
 
 impl DockerCommandExt for Command {
-    fn add_configuration_envvars(&mut self) {
-        let other = &[
+    fn add_cargo_configuration_envvars(&mut self) {
+        let non_cargo_prefix = &[
             "http_proxy",
             "TERM",
             "RUSTDOCFLAGS",
@@ -968,7 +958,6 @@ impl DockerCommandExt for Command {
             "HTTPS_PROXY",
             "HTTP_TIMEOUT",
             "https_proxy",
-            "QEMU_STRACE",
         ];
         let cargo_prefix_skip = &[
             "CARGO_HOME",
@@ -979,22 +968,15 @@ impl DockerCommandExt for Command {
             "CARGO_BUILD_RUSTC_WORKSPACE_WRAPPER",
             "CARGO_BUILD_RUSTDOC",
         ];
-        let cross_prefix_skip = &[
-            "CROSS_RUNNER",
-            "CROSS_RUSTC_MAJOR_VERSION",
-            "CROSS_RUSTC_MINOR_VERSION",
-            "CROSS_RUSTC_PATCH_VERSION",
-        ];
-        let is_passthrough = |key: &str| -> bool {
-            other.contains(&key)
+        let is_cargo_passthrough = |key: &str| -> bool {
+            non_cargo_prefix.contains(&key)
                 || key.starts_with("CARGO_") && !cargo_prefix_skip.contains(&key)
-                || key.starts_with("CROSS_") && !cross_prefix_skip.contains(&key)
         };
 
         // also need to accept any additional flags used to configure
-        // cargo or cross, but only pass what's actually present.
+        // cargo, but only pass what's actually present.
         for (key, _) in env::vars() {
-            if is_passthrough(&key) {
+            if is_cargo_passthrough(&key) {
                 self.args(["-e", &key]);
             }
         }
@@ -1036,12 +1018,20 @@ impl DockerCommandExt for Command {
             // otherwise, zig has a permission error trying to create the cache
             self.args(["-e", "XDG_CACHE_HOME=/target/.zig-cache"]);
         }
-        self.add_configuration_envvars();
+        self.add_cargo_configuration_envvars();
 
         if let Some(username) = id::username().wrap_err("could not get username")? {
             self.args(["-e", &format!("USER={username}")]);
         }
 
+        if let Ok(value) = env::var("QEMU_STRACE") {
+            self.args(["-e", &format!("QEMU_STRACE={value}")]);
+        }
+
+        if let Ok(value) = env::var("CROSS_DEBUG") {
+            self.args(["-e", &format!("CROSS_DEBUG={value}")]);
+        }
+
         if let Ok(value) = env::var("CROSS_CONTAINER_OPTS") {
             if env::var("DOCKER_OPTS").is_ok() {
                 msg_info.warn("using both `CROSS_CONTAINER_OPTS` and `DOCKER_OPTS`.")?;
@@ -1335,10 +1325,7 @@ pub(crate) fn get_image(config: &Config, target: &Target, uses_zig: bool) -> Res
     Ok(image)
 }
 
-fn docker_read_mount_paths(
-    engine: &Engine,
-    msg_info: &mut MessageInfo,
-) -> Result<Vec<MountDetail>> {
+fn docker_read_mount_paths(engine: &Engine) -> Result<Vec<MountDetail>> {
     let hostname = env::var("HOSTNAME").wrap_err("HOSTNAME environment variable not found")?;
 
     let mut docker: Command = {
@@ -1347,7 +1334,7 @@ fn docker_read_mount_paths(
         command
     };
 
-    let output = docker.run_and_get_stdout(msg_info)?;
+    let output = docker.run_and_get_stdout(&mut Verbosity::Quiet.into())?;
     let info = serde_json::from_str(&output).wrap_err("failed to parse docker inspect output")?;
     dockerinfo_parse_mounts(&info)
 }
@@ -1423,9 +1410,9 @@ impl MountFinder {
         MountFinder { mounts }
     }
 
-    pub fn create(engine: &Engine, msg_info: &mut MessageInfo) -> Result<MountFinder> {
+    pub fn create(engine: &Engine) -> Result<MountFinder> {
         Ok(if engine.in_docker {
-            MountFinder::new(docker_read_mount_paths(engine, msg_info)?)
+            MountFinder::new(docker_read_mount_paths(engine)?)
         } else {
             MountFinder::default()
         })
@@ -1638,7 +1625,6 @@ mod tests {
                 &None,
                 &image_platform,
                 &sysroot,
-                false,
             ))
         }
 
@@ -1709,12 +1695,12 @@ mod tests {
                 return Ok(());
             }
 
-            let mount_finder = MountFinder::create(&engine, &mut msg_info)?;
+            let mount_finder = MountFinder::create(&engine)?;
             let metadata = cargo_metadata(true, &mut msg_info)?;
             let (directories, _) = get_directories(metadata, &mount_finder)?;
             let toolchain_dirs = directories.toolchain_directories();
             let package_dirs = directories.package_directories();
-            let mount_finder = MountFinder::new(docker_read_mount_paths(&engine, &mut msg_info)?);
+            let mount_finder = MountFinder::new(docker_read_mount_paths(&engine)?);
             let mount_path = |p| mount_finder.find_mount_path(p);
 
             paths_equal(toolchain_dirs.cargo(), &mount_path(home()?.join(".cargo")))?;
diff --git a/src/extensions.rs b/src/extensions.rs
index e8f7d23..a9c2e8c 100644
--- a/src/extensions.rs
+++ b/src/extensions.rs
@@ -10,19 +10,16 @@ pub const STRIPPED_BINS: &[&str] = &[crate::docker::DOCKER, crate::docker::PODMA
 pub trait CommandExt {
     fn fmt_message(&self, msg_info: &mut MessageInfo) -> String;
 
-    #[track_caller]
     fn print(&self, msg_info: &mut MessageInfo) -> Result<()> {
         let msg = self.fmt_message(msg_info);
         msg_info.print(&msg)
     }
 
-    #[track_caller]
     fn info(&self, msg_info: &mut MessageInfo) -> Result<()> {
         let msg = self.fmt_message(msg_info);
         msg_info.info(&msg)
     }
 
-    #[track_caller]
     fn debug(&self, msg_info: &mut MessageInfo) -> Result<()> {
         let msg = self.fmt_message(msg_info);
         msg_info.debug(&msg)
@@ -34,17 +31,13 @@ pub trait CommandExt {
         status: ExitStatus,
         output: Option<&Output>,
     ) -> Result<(), CommandError>;
-    #[track_caller]
     fn run(&mut self, msg_info: &mut MessageInfo, silence_stdout: bool) -> Result<()>;
-    #[track_caller]
     fn run_and_get_status(
         &mut self,
         msg_info: &mut MessageInfo,
         silence_stdout: bool,
     ) -> Result<ExitStatus>;
-    #[track_caller]
     fn run_and_get_stdout(&mut self, msg_info: &mut MessageInfo) -> Result<String>;
-    #[track_caller]
     fn run_and_get_output(&mut self, msg_info: &mut MessageInfo) -> Result<std::process::Output>;
     fn command_pretty(
         &self,
@@ -91,33 +84,20 @@ impl CommandExt for Command {
         format!("{}", C(self, msg_info, strip))
     }
 
-    #[track_caller]
     fn fmt_message(&self, mut msg_info: &mut MessageInfo) -> String {
-        use std::fmt::Write;
         let msg_info = &mut msg_info;
-        let mut string = String::new();
-        if let Some(caller) = msg_info.caller() {
-            write!(string, "[{}] ->\n+ ", caller).unwrap();
-        } else {
-            write!(string, "+ ").unwrap();
-        };
         if let Some(cwd) = self.get_current_dir() {
-            write!(
-                string,
-                "{:?} {}",
+            format!(
+                "+ {:?} {}",
                 cwd,
                 msg_info.as_verbose(|info| self.command_pretty(info, |_| false))
             )
-            .unwrap();
         } else {
-            write!(
-                string,
-                "{}",
+            format!(
+                "+ {}",
                 msg_info.as_verbose(|info| self.command_pretty(info, |_| false))
             )
-            .unwrap();
         }
-        string
     }
 
     fn status_result(
@@ -147,7 +127,6 @@ impl CommandExt for Command {
     }
 
     /// Runs the command to completion
-    #[track_caller]
     fn run_and_get_status(
         &mut self,
         msg_info: &mut MessageInfo,
@@ -167,7 +146,6 @@ impl CommandExt for Command {
     }
 
     /// Runs the command to completion and returns its stdout
-    #[track_caller]
     fn run_and_get_stdout(&mut self, msg_info: &mut MessageInfo) -> Result<String> {
         let out = self.run_and_get_output(msg_info)?;
         self.status_result(msg_info, out.status, Some(&out))
@@ -180,7 +158,6 @@ impl CommandExt for Command {
     /// # Notes
     ///
     /// This command does not check the status.
-    #[track_caller]
     fn run_and_get_output(&mut self, msg_info: &mut MessageInfo) -> Result<std::process::Output> {
         self.debug(msg_info)?;
         self.output().map_err(|e| {
diff --git a/src/lib.rs b/src/lib.rs
index 6a3b64e..363b013 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -578,10 +578,11 @@ To override the toolchain mounted in the image, set `target.{}.image.toolchain =
             // set the sysroot explicitly to the toolchain
             let mut is_nightly = toolchain.channel.contains("nightly");
 
-            if !toolchain.is_custom
-                && !rustup::installed_toolchains(msg_info)?
-                    .into_iter()
-                    .any(|t| t == toolchain.to_string())
+            let installed_toolchains = rustup::installed_toolchains(msg_info)?;
+
+            if !installed_toolchains
+                .into_iter()
+                .any(|t| t == toolchain.to_string())
             {
                 rustup::install_toolchain(&toolchain, msg_info)?;
             }
@@ -706,13 +707,7 @@ To override the toolchain mounted in the image, set `target.{}.image.toolchain =
                     engine.register_binfmt(&target, msg_info)?;
                 }
 
-                let paths = docker::DockerPaths::create(
-                    &engine,
-                    metadata,
-                    cwd,
-                    toolchain.clone(),
-                    msg_info,
-                )?;
+                let paths = docker::DockerPaths::create(&engine, metadata, cwd, toolchain.clone())?;
                 let options = docker::DockerOptions::new(
                     engine,
                     target.clone(),
diff --git a/src/rustc.rs b/src/rustc.rs
index 86dc99b..97a61a1 100644
--- a/src/rustc.rs
+++ b/src/rustc.rs
@@ -92,18 +92,12 @@ pub struct QualifiedToolchain {
 }
 
 impl QualifiedToolchain {
-    pub fn new(
-        channel: &str,
-        date: &Option<String>,
-        host: &ImagePlatform,
-        sysroot: &Path,
-        is_custom: bool,
-    ) -> Self {
+    pub fn new(channel: &str, date: &Option<String>, host: &ImagePlatform, sysroot: &Path) -> Self {
         let mut this = Self {
             channel: channel.to_owned(),
             date: date.clone(),
             host: host.clone(),
-            is_custom,
+            is_custom: false,
             full: if let Some(date) = date {
                 format!("{}-{}-{}", channel, date, host.target)
             } else {
@@ -111,16 +105,14 @@ impl QualifiedToolchain {
             },
             sysroot: sysroot.to_owned(),
         };
-        if !is_custom {
-            this.sysroot.set_file_name(&this.full);
-        }
+        this.sysroot.set_file_name(&this.full);
         this
     }
 
     /// Replace the host, does nothing if ran on a custom toolchain
     pub fn replace_host(&mut self, host: &ImagePlatform) -> &mut Self {
         if !self.is_custom {
-            *self = Self::new(&self.channel, &self.date, host, &self.sysroot, false);
+            *self = Self::new(&self.channel, &self.date, host, &self.sysroot);
             self.sysroot.set_file_name(&self.full);
         }
         self
@@ -176,8 +168,8 @@ impl QualifiedToolchain {
                 &build_date,
                 &ImagePlatform::from_target(host.into())?,
                 sysroot,
-                true,
             );
+            toolchain.is_custom = true;
             toolchain.full = name.to_owned();
             return Ok(toolchain);
         }
@@ -225,7 +217,6 @@ impl QualifiedToolchain {
             &date,
             &host,
             &self.sysroot,
-            false,
         ))
     }
 
@@ -265,11 +256,7 @@ impl QualifiedToolchain {
             Ok(_) | Err(_) if config.custom_toolchain() => {
                 QualifiedToolchain::custom(toolchain, &sysroot, config, msg_info)
             }
-            Ok(_) => return Err(eyre::eyre!("toolchain is not fully qualified")
-                .with_note(|| "cross expects the toolchain to be a rustup installed toolchain")
-                .with_suggestion(|| {
-                    "if you're using a custom toolchain try setting `CROSS_CUSTOM_TOOLCHAIN=1` or install rust via rustup"
-            })),
+            Ok(_) => eyre::bail!("toolchain is not fully qualified"),
             Err(e) => Err(e),
         }
     }
diff --git a/src/shell.rs b/src/shell.rs
index 0ec20ae..b32eaca 100644
--- a/src/shell.rs
+++ b/src/shell.rs
@@ -6,7 +6,6 @@ use std::fmt;
 use std::io::{self, Write};
 use std::str::FromStr;
 
-use crate::config::bool_from_envvar;
 use crate::errors::Result;
 use owo_colors::{self, OwoColorize};
 
@@ -40,11 +39,8 @@ macro_rules! message {
     (@status $stream:ident, $status:expr, $message:expr, $color:ident, $msg_info:expr $(,)?) => {{
         write_style!($stream, $msg_info, $status, bold, $color);
         write_style!($stream, $msg_info, ":", bold);
-        if let Some(caller) = $msg_info.caller() {
-            write!($stream, " [{}]", caller)?;
-        }
         match $message {
-            Some(message) => writeln!($stream, " {}", message, )?,
+            Some(message) => writeln!($stream, " {}", message)?,
             None => write!($stream, " ")?,
         }
 
@@ -143,20 +139,15 @@ pub struct MessageInfo {
     pub verbosity: Verbosity,
     pub stdout_needs_erase: bool,
     pub stderr_needs_erase: bool,
-    pub cross_debug: bool,
 }
 
 impl MessageInfo {
-    pub fn new(color_choice: ColorChoice, verbosity: Verbosity) -> MessageInfo {
+    pub const fn new(color_choice: ColorChoice, verbosity: Verbosity) -> MessageInfo {
         MessageInfo {
             color_choice,
             verbosity,
             stdout_needs_erase: false,
             stderr_needs_erase: false,
-            cross_debug: std::env::var("CROSS_DEBUG")
-                .as_deref()
-                .map(bool_from_envvar)
-                .unwrap_or_default(),
         }
     }
 
@@ -164,17 +155,12 @@ impl MessageInfo {
         let color_choice = get_color_choice(color)?;
         let verbosity = get_verbosity(color_choice, verbose, quiet)?;
 
-        Ok(Self::new(color_choice, verbosity))
-    }
-
-    #[track_caller]
-    pub fn caller(&mut self) -> Option<impl fmt::Display> {
-        if self.cross_debug {
-            let loc = std::panic::Location::caller();
-            Some(format!("{}:{}", loc.file(), loc.line()))
-        } else {
-            None
-        }
+        Ok(MessageInfo {
+            color_choice,
+            verbosity,
+            stdout_needs_erase: false,
+            stderr_needs_erase: false,
+        })
     }
 
     #[must_use]
@@ -225,7 +211,6 @@ impl MessageInfo {
     }
 
     /// prints a red 'error' message and terminates.
-    #[track_caller]
     pub fn fatal<T: fmt::Display>(&mut self, message: T, code: i32) -> ! {
         self.error(message)
             .expect("could not display fatal message");
@@ -233,14 +218,12 @@ impl MessageInfo {
     }
 
     /// prints a red 'error' message.
-    #[track_caller]
     pub fn error<T: fmt::Display>(&mut self, message: T) -> Result<()> {
         self.stderr_check_erase()?;
         status!(@stderr cross_prefix!("error"), Some(&message), red, self)
     }
 
     /// prints an amber 'warning' message.
-    #[track_caller]
     pub fn warn<T: fmt::Display>(&mut self, message: T) -> Result<()> {
         match self.verbosity {
             Verbosity::Quiet => Ok(()),
@@ -254,7 +237,6 @@ impl MessageInfo {
     }
 
     /// prints a cyan 'note' message.
-    #[track_caller]
     pub fn note<T: fmt::Display>(&mut self, message: T) -> Result<()> {
         match self.verbosity {
             Verbosity::Quiet => Ok(()),
@@ -273,7 +255,6 @@ impl MessageInfo {
     }
 
     /// prints a high-priority message to stdout.
-    #[track_caller]
     pub fn print<T: fmt::Display>(&mut self, message: T) -> Result<()> {
         self.stdout_check_erase()?;
         println!("{}", message);
@@ -281,7 +262,6 @@ impl MessageInfo {
     }
 
     /// prints a normal message to stdout.
-    #[track_caller]
     pub fn info<T: fmt::Display>(&mut self, message: T) -> Result<()> {
         match self.verbosity {
             Verbosity::Quiet => Ok(()),
@@ -293,7 +273,6 @@ impl MessageInfo {
     }
 
     /// prints a debugging message to stdout.
-    #[track_caller]
     pub fn debug<T: fmt::Display>(&mut self, message: T) -> Result<()> {
         match self.verbosity {
             Verbosity::Quiet | Verbosity::Normal => Ok(()),
diff --git a/targets.toml b/targets.toml
index da0bf63..01502f8 100644
--- a/targets.toml
+++ b/targets.toml
@@ -22,11 +22,8 @@ deploy = true
 [[target]]
 target = "x86_64-unknown-linux-musl"
 os = "ubuntu-latest"
-cpp = true
-dylib = true
 std = true
 run = true
-runners = "native qemu-user"
 deploy = true
 
 [[target]]
diff --git a/xtask/src/ci/target_matrix.rs b/xtask/src/ci/target_matrix.rs
index 5739180..99c7641 100644
--- a/xtask/src/ci/target_matrix.rs
+++ b/xtask/src/ci/target_matrix.rs
@@ -1,20 +1,30 @@
+use std::process::Command;
+
 use clap::builder::BoolishValueParser;
 use clap::Parser;
-use serde::Serialize;
+use cross::{shell::Verbosity, CommandExt};
+use serde::{Deserialize, Serialize};
 
 use crate::util::{get_matrix, gha_output, gha_print, CiTarget, ImageTarget};
 
 pub(crate) fn run(message: String, author: String) -> Result<(), color_eyre::Report> {
     let mut matrix: Vec<CiTarget> = get_matrix().clone();
-    if author == "bors[bot]" && message.starts_with("Try #") {
-        if let Some((_, args)) = message.split_once(": ") {
-            let app = TargetMatrixArgs::parse_from(args.split(' '));
-            app.filter(&mut matrix);
-        }
+    let (prs, mut app) = if author == "bors[bot]" {
+        process_bors_message(&message)?
     } else {
-        gha_print("Running all targets.");
+        (vec![], TargetMatrixArgs::default())
+    };
+
+    if !prs.is_empty()
+        && prs.iter().try_fold(true, |b, pr| {
+            Ok::<_, eyre::Report>(b && has_no_ci_target(pr)?)
+        })?
+    {
+        app.none = true;
     }
 
+    app.filter(&mut matrix);
+
     let matrix = matrix
         .iter()
         .map(|target| TargetMatrixElement {
@@ -32,12 +42,68 @@ pub(crate) fn run(message: String, author: String) -> Result<(), color_eyre::Rep
             std: target.std.map(|b| b as u8),
         })
         .collect::<Vec<_>>();
+
     let json = serde_json::to_string(&matrix)?;
     gha_print(&json);
     gha_output("matrix", &json);
     Ok(())
 }
 
+fn parse_gh_labels(pr: &str) -> cross::Result<Vec<String>> {
+    #[derive(Deserialize)]
+    struct PullRequest {
+        labels: Vec<PullRequestLabels>,
+    }
+
+    #[derive(Deserialize)]
+    struct PullRequestLabels {
+        name: String,
+    }
+    eyre::ensure!(
+        pr.chars().all(|c| c.is_ascii_digit()),
+        "pr should be a number, got {:?}",
+        pr
+    );
+    let stdout = Command::new("gh")
+        .args(["pr", "view", pr, "--json", "labels"])
+        .run_and_get_stdout(&mut Verbosity::Quiet.into())?;
+    let pr_info: PullRequest = serde_json::from_str(&stdout)?;
+    Ok(pr_info.labels.into_iter().map(|l| l.name).collect())
+}
+
+fn has_no_ci_target(pr: &str) -> cross::Result<bool> {
+    Ok(parse_gh_labels(pr)?.contains(&"no-ci-targets".to_owned()))
+}
+
+/// Returns the pr(s) associated with this bors commit and the app to use for processing
+fn process_bors_message(message: &str) -> cross::Result<(Vec<&str>, TargetMatrixArgs)> {
+    if let Some(message) = message.strip_prefix("Try #") {
+        let (pr, args) = message
+            .split_once(':')
+            .ok_or_else(|| eyre::eyre!("bors message must start with \"Try #:\""))?;
+        let args = args.trim_start();
+        let app = if !args.is_empty() {
+            TargetMatrixArgs::parse_from(args.split(' '))
+        } else {
+            TargetMatrixArgs::default()
+        };
+        Ok((vec![pr], app))
+    } else if let Some(message) = message.strip_prefix("Merge") {
+        Ok((
+            message
+                .lines()
+                .next()
+                .unwrap_or_default()
+                .split(" #")
+                .skip(1)
+                .collect(),
+            TargetMatrixArgs::default(),
+        ))
+    } else {
+        eyre::bail!("unexpected bors commit message encountered")
+    }
+}
+
 #[derive(Serialize)]
 #[serde(rename_all = "kebab-case")]
 struct TargetMatrixElement<'a> {
@@ -63,7 +129,7 @@ struct TargetMatrixElement<'a> {
     std: Option<u8>,
 }
 
-#[derive(Parser, Debug)]
+#[derive(Parser, Debug, Default, PartialEq, Eq)]
 #[clap(no_binary_name = true)]
 struct TargetMatrixArgs {
     #[clap(long, short, num_args = 0..)]
@@ -84,7 +150,11 @@ struct TargetMatrixArgs {
 
 impl TargetMatrixArgs {
     pub fn filter(&self, matrix: &mut Vec<CiTarget>) {
+        if self == &TargetMatrixArgs::default() {
+            gha_print("Running all targets.");
+        }
         if self.none {
+            gha_print("Running no targets.");
             std::mem::take(matrix);
             return;
         }
@@ -196,4 +266,39 @@ mod tests {
         let matrix = run(["--none"]);
         assert_eq!(&Vec::<CiTarget>::new(), &matrix);
     }
+
+    #[test]
+    fn prs() {
+        assert_eq!(
+            process_bors_message("Merge #1337\n1337: merge").unwrap().0,
+            vec!["1337"]
+        );
+        assert_eq!(
+            process_bors_message("Merge #1337 #42\n1337: merge\n42: merge 2")
+                .unwrap()
+                .0,
+            vec!["1337", "42"]
+        );
+        assert_eq!(
+            // the trailing space is intentional
+            process_bors_message("Try #1337: \n").unwrap().0,
+            vec!["1337"]
+        );
+    }
+
+    #[test]
+    fn full_invocation() {
+        let (prs, app) = process_bors_message("Try #1337: ").unwrap();
+        assert_eq!(prs, vec!["1337"]);
+        assert_eq!(app, TargetMatrixArgs::default());
+        let (prs, app) = process_bors_message("Try #1337: --std 1").unwrap();
+        assert_eq!(prs, vec!["1337"]);
+        assert_eq!(
+            app,
+            TargetMatrixArgs {
+                std: Some(true),
+                ..TargetMatrixArgs::default()
+            }
+        );
+    }
 }
diff --git a/xtask/src/crosstool.rs b/xtask/src/crosstool.rs
index 505f69f..6d12e42 100644
--- a/xtask/src/crosstool.rs
+++ b/xtask/src/crosstool.rs
@@ -1,4 +1,3 @@
-use std::cmp::Ordering;
 use std::fmt::Write;
 use std::fs;
 use std::path::{Path, PathBuf};
@@ -10,9 +9,6 @@ use cross::ToUtf8;
 
 const DEFAULT_GCC_VERSION: &str = "8.3.0";
 const DEFAULT_GLIBC_VERSION: &str = "2.17.0";
-const DEFAULT_UCLIBC_VERSION: &str = "1.0.31";
-const DEFAULT_MUSL_VERSION: &str = "1.1.24";
-const DEFAULT_NEWLIB_VERSION: &str = "3.1.0.20181231";
 const DEFAULT_LINUX_VERSION: &str = "4.19.21";
 const DOCKER: &str = "docker";
 const CT_NG: &str = "crosstool-ng";
@@ -36,15 +32,6 @@ pub struct ConfigureCrosstool {
     /// The glibc version to configure for.
     #[clap(long, env = "GLIBC_VERSION")]
     pub glibc_version: Option<String>,
-    /// The uclibc version to configure for.
-    #[clap(long, env = "UCLIBC_VERSION")]
-    pub uclibc_version: Option<String>,
-    /// The musl version to configure for.
-    #[clap(long, env = "MUSL_VERSION")]
-    pub musl_version: Option<String>,
-    /// The newlib version to configure for.
-    #[clap(long, env = "NEWLIB_VERSION")]
-    pub newlib_version: Option<String>,
     /// The linux version to configure for.
     #[clap(long, env = "LINUX_VERSION")]
     pub linux_version: Option<String>,
@@ -88,238 +75,33 @@ fn read_config_dir(dir: &Path) -> cross::Result<Vec<String>> {
     Ok(targets)
 }
 
-fn configure_glibc(
-    glibc_version: &str,
-) -> cross::Result<(&'static str, String, String, Option<String>)> {
-    // configure the `CT_GLIBC` values
-    let glibc_versions: Vec<&str> = glibc_version.split('.').collect();
-    if !matches!(glibc_versions.len(), 2 | 3) {
-        eyre::bail!("invalid glibc version, got {glibc_version}");
-    }
-
-    let glibc_major = glibc_versions[0].parse::<u32>()?;
-    let glibc_minor = glibc_versions[1].parse::<u32>()?;
-    let _glibc_patch = glibc_versions.get(2).unwrap_or(&"0").parse::<u32>()?;
-    if glibc_major != 2 {
-        eyre::bail!("glibc major versions other than 2 currently unsupported, got {glibc_major}");
-    }
-    let ct_glibc_v = format!(
-        r#"CT_GLIBC_V_{glibc_major}_{glibc_minor}=y
-# CT_GLIBC_NO_VERSIONS is not set
-CT_GLIBC_VERSION="{glibc_major}.{glibc_minor}""#
-    );
-    let mut ct_glibc = String::new();
-    let glibc_older = [29, 27, 26, 25, 24, 23, 20];
-    for minor in glibc_older {
-        if glibc_minor <= minor {
-            write!(ct_glibc, "\nCT_GLIBC_2_{minor}_or_older=y")?;
-        }
-        if glibc_minor < minor {
-            write!(ct_glibc, "\nCT_GLIBC_older_than_2_{minor}=y")?;
-        }
-    }
-    if glibc_minor >= 17 {
-        ct_glibc.push_str("\nCT_GLIBC_2_17_or_later=y");
-    }
-    if glibc_minor <= 17 {
-        ct_glibc.push_str("\nCT_GLIBC_2_17_or_older=y");
-    }
-    if glibc_minor > 14 {
-        ct_glibc.push_str("\nCT_GLIBC_later_than_2_14=y");
-    }
-    if glibc_minor >= 14 {
-        ct_glibc.push_str("\nCT_GLIBC_2_14_or_later=y");
-    }
-
-    Ok(("GLIBC", ct_glibc_v, ct_glibc, None))
-}
-
-fn configure_uclibc(
-    uclibc_version: &str,
-) -> cross::Result<(&'static str, String, String, Option<String>)> {
-    // configure the `CT_UCLIBC` values
-    let uclibc_versions: Vec<&str> = uclibc_version.split('.').collect();
-    if !matches!(uclibc_versions.len(), 3 | 4) {
-        eyre::bail!("invalid uclibc version, got {uclibc_version}");
-    }
-
-    let uclibc_major = uclibc_versions[0].parse::<u32>()?;
-    let uclibc_minor = uclibc_versions[1].parse::<u32>()?;
-    let uclibc_patch = uclibc_versions[2].parse::<u32>()?;
-    let uclibc_dev = uclibc_versions.get(3).unwrap_or(&"0").parse::<u32>()?;
-    let (key, version) = match uclibc_dev {
-        0 => (
-            format!("{uclibc_major}_{uclibc_minor}_{uclibc_patch}"),
-            format!("{uclibc_major}.{uclibc_minor}.{uclibc_patch}"),
-        ),
-        _ => (
-            format!("{uclibc_major}_{uclibc_minor}_{uclibc_patch}_{uclibc_dev}"),
-            format!("{uclibc_major}.{uclibc_minor}.{uclibc_patch}.{uclibc_dev}"),
-        ),
-    };
-    let (ct_uclibc_v, ct_extras) = match uclibc_major {
-        0 => (
-            format!(
-                r#"CT_UCLIBC_V_{key}=y
-# CT_UCLIBC_NO_VERSIONS is not set
-CT_UCLIBC_VERSION="{version}""#
-            ),
-            r#"CT_UCLIBC_USE_UCLIBC_ORG=y
-CT_UCLIBC_USE="UCLIBC"
-CT_UCLIBC_PKG_NAME="uClibc"
-CT_UCLIBC_SRC_RELEASE=y
-CT_UCLIBC_PATCH_ORDER="global"
-CT_UCLIBC_MIRRORS="https://uclibc.org/downloads/"
-CT_UCLIBC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
-CT_UCLIBC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
-CT_UCLIBC_ARCHIVE_FORMATS=".tar.xz .tar.bz2"
-CT_UCLIBC_SIGNATURE_FORMAT="packed/.asc""#,
-        ),
-        _ => (
-            format!(
-                r#"CT_UCLIBC_NG_V_{key}=y
-# CT_UCLIBC_NG_NO_VERSIONS is not set
-CT_UCLIBC_NG_VERSION="{version}""#
-            ),
-            r#"CT_UCLIBC_USE_UCLIBC_NG_ORG=y
-CT_UCLIBC_USE="UCLIBC_NG"
-CT_UCLIBC_NG_PKG_NAME="uClibc-ng"
-CT_UCLIBC_NG_SRC_RELEASE=y
-CT_UCLIBC_NG_PATCH_ORDER="global"
-CT_UCLIBC_NG_MIRRORS="http://downloads.uclibc-ng.org/releases/${CT_UCLIBC_NG_VERSION}"
-CT_UCLIBC_NG_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
-CT_UCLIBC_NG_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
-CT_UCLIBC_NG_ARCHIVE_FORMATS=".tar.xz .tar.lz .tar.bz2 .tar.gz"
-CT_UCLIBC_NG_SIGNATURE_FORMAT="packed/.asc""#,
-        ),
-    };
-
-    let mut ct_uclibc = String::new();
-    let version = (uclibc_major, uclibc_minor, uclibc_patch, uclibc_dev);
-    let uclibc_older = [
-        (1, 0, 23, 0),
-        (1, 0, 21, 0),
-        (1, 0, 15, 0),
-        (1, 0, 0, 0),
-        (0, 9, 33, 2),
-    ];
-    for older in uclibc_older {
-        let cmp = older.cmp(&version);
-        let (major, minor, patch, dev) = older;
-        let key = match dev {
-            0 => format!("{major}_{minor}_{patch}"),
-            _ => format!("{major}_{minor}_{patch}_{dev}"),
-        };
-        match cmp {
-            Ordering::Greater => {
-                write!(ct_uclibc, "\nCT_UCLIBC_{key}_or_older=y")?;
-                write!(ct_uclibc, "\nCT_UCLIBC_older_than_{key}=y")?;
-            }
-            Ordering::Equal => {
-                write!(ct_uclibc, "\nCT_UCLIBC_{key}_or_later=y")?;
-                write!(ct_uclibc, "\nCT_UCLIBC_{key}_or_older=y")?;
-            }
-            Ordering::Less => {
-                write!(ct_uclibc, "\nCT_UCLIBC_{key}_or_later=y")?;
-                write!(ct_uclibc, "\nCT_UCLIBC_later_than_{key}=y")?;
-            }
-        }
-    }
-
-    Ok(("UCLIBC", ct_uclibc_v, ct_uclibc, Some(ct_extras.to_owned())))
-}
-
-fn configure_musl(
-    musl_version: &str,
-) -> cross::Result<(&'static str, String, String, Option<String>)> {
-    let musl_versions: Vec<&str> = musl_version.split('.').collect();
-    if !matches!(musl_versions.len(), 3) {
-        eyre::bail!("invalid musl version, got {musl_version}");
-    }
-
-    let musl_major = musl_versions[0].parse::<u32>()?;
-    let musl_minor = musl_versions[1].parse::<u32>()?;
-    let musl_patch = musl_versions[2].parse::<u32>()?;
-    let ct_musl_v = format!(
-        r#"CT_MUSL_V_{musl_major}_{musl_minor}_{musl_patch}=y
-# CT_MUSL_NO_VERSIONS is not set
-CT_MUSL_VERSION="{musl_major}.{musl_minor}.{musl_patch}""#
-    );
-
-    Ok(("MUSL", ct_musl_v, "".to_owned(), None))
-}
-
-fn configure_newlib(
-    newlib_version: &str,
-) -> cross::Result<(&'static str, String, String, Option<String>)> {
-    let newlib_versions: Vec<&str> = newlib_version.split('.').collect();
-    if !matches!(newlib_versions.len(), 3 | 4) {
-        eyre::bail!("invalid newlib version, got {newlib_version}");
-    }
-
-    let newlib_major = newlib_versions[0].parse::<u32>()?;
-    let newlib_minor = newlib_versions[1].parse::<u32>()?;
-    let newlib_patch = newlib_versions[2].parse::<u32>()?;
-    let newlib_dev = newlib_versions.get(3).unwrap_or(&"0").parse::<u32>()?;
-    let ct_newlib_v = format!(
-        r#"CT_NEWLIB_V_{newlib_major}_{newlib_minor}=y
-# CT_NEWLIB_NO_VERSIONS is not set
-CT_NEWLIB_VERSION="{newlib_major}.{newlib_minor}.{newlib_patch}.{newlib_dev}""#
-    );
-
-    let mut ct_newlib = String::new();
-    let version = (newlib_major, newlib_minor);
-    let newlib_older = [(2, 2), (2, 1), (2, 0)];
-    for older in newlib_older {
-        let cmp = older.cmp(&version);
-        let (major, minor) = older;
-        let key = format!("{major}_{minor}");
-        match cmp {
-            Ordering::Greater => {
-                write!(ct_newlib, "\nCT_NEWLIB_{key}_or_older=y")?;
-                write!(ct_newlib, "\nCT_NEWLIB_older_than_{key}=y")?;
-            }
-            Ordering::Equal => {
-                write!(ct_newlib, "\nCT_NEWLIB_{key}_or_later=y")?;
-                write!(ct_newlib, "\nCT_NEWLIB_{key}_or_older=y")?;
-            }
-            Ordering::Less => {
-                write!(ct_newlib, "\nCT_NEWLIB_{key}_or_later=y")?;
-                write!(ct_newlib, "\nCT_NEWLIB_later_than_{key}=y")?;
-            }
-        }
-    }
-
-    Ok(("NEWLIB", ct_newlib_v, ct_newlib, None))
-}
-
 fn configure_target(
     src_file: &Path,
     gcc_version: &str,
     glibc_version: &str,
-    uclibc_version: &str,
-    musl_version: &str,
-    newlib_version: &str,
     linux_version: &str,
 ) -> cross::Result<String> {
-    let file_name = src_file
-        .file_name()
-        .ok_or(eyre::eyre!("unable to get filename for {src_file:?}"))?
-        .to_utf8()?;
-    let mut contents = fs::read_to_string(src_file)?;
-
-    // configure the `CT_GCC` values
     let gcc_versions: Vec<&str> = gcc_version.split('.').collect();
+    let glibc_versions: Vec<&str> = glibc_version.split('.').collect();
+    let linux_versions: Vec<&str> = linux_version.split('.').collect();
     if !matches!(gcc_versions.len(), 2 | 3) {
         eyre::bail!("invalid GCC version, got {gcc_version}");
     }
+    if !matches!(glibc_versions.len(), 2 | 3) {
+        eyre::bail!("invalid glibc version, got {glibc_version}");
+    }
+    if !matches!(linux_versions.len(), 2 | 3) {
+        eyre::bail!("invalid linux version, got {linux_version}");
+    }
+
+    // configure the `CT_GCC` values
     let gcc_major = gcc_versions[0].parse::<u32>()?;
     let gcc_minor = gcc_versions[1].parse::<u32>()?;
     let gcc_patch = gcc_versions.get(2).unwrap_or(&"0").parse::<u32>()?;
     let ct_gcc_v = format!(
-        r#"CT_GCC_V_{gcc_major}=y
+        "CT_GCC_V_{gcc_major}=y
 # CT_GCC_NO_VERSIONS is not set
-CT_GCC_VERSION="{gcc_major}.{gcc_minor}.{gcc_patch}""#
+CT_GCC_VERSION=\"{gcc_major}.{gcc_minor}.{gcc_patch}\""
     );
     let mut ct_gcc = String::new();
     for major in (5..=7).rev() {
@@ -342,88 +124,84 @@ CT_GCC_VERSION="{gcc_major}.{gcc_minor}.{gcc_patch}""#
     if gcc_major > 4 || (gcc_major == 4 && gcc_major >= 8) {
         ct_gcc.push_str("\nCT_GCC_4_8_or_later=y");
     }
-    if ct_gcc.starts_with('\n') {
-        ct_gcc.remove(0);
-    }
-    contents = contents
-        .replacen("%CT_GCC_V%", &ct_gcc_v, 1)
-        .replacen("%CT_GCC%", &ct_gcc, 1);
 
-    // configure the libc versions
-    let (key, libc_v, mut libc, extras) = if file_name.contains("gnu") {
-        configure_glibc(glibc_version)?
-    } else if file_name.contains("uclibc") {
-        configure_uclibc(uclibc_version)?
-    } else if file_name.contains("musl") {
-        configure_musl(musl_version)?
-    } else if file_name.contains("none") {
-        configure_newlib(newlib_version)?
-    } else {
-        eyre::bail!("unsupported rust target for file {file_name}: unknown libc version");
-    };
-    if libc.starts_with('\n') {
-        libc.remove(0);
+    // configure the `CT_GLIBC` values
+    let glibc_major = glibc_versions[0].parse::<u32>()?;
+    let glibc_minor = glibc_versions[1].parse::<u32>()?;
+    let _glibc_patch = glibc_versions.get(2).unwrap_or(&"0").parse::<u32>()?;
+    if glibc_major != 2 {
+        eyre::bail!("glibc major versions other than 2 currently unsupported, got {glibc_major}");
     }
-    contents = contents
-        .replacen(&format!("%CT_{key}_V%"), &libc_v, 1)
-        .replacen(&format!("%CT_{key}%"), &libc, 1);
-    if let Some(extras) = extras {
-        contents = contents.replacen(&format!("%CT_{key}_EXTRAS%"), &extras, 1);
+    let ct_glibc_v = format!(
+        "CT_GLIBC_V_{glibc_major}_{glibc_minor}=y
+# CT_GLIBC_NO_VERSIONS is not set
+CT_GLIBC_VERSION=\"{glibc_major}.{glibc_minor}\""
+    );
+    let mut ct_glibc = String::new();
+    let glibc_older = [29, 27, 26, 25, 24, 23, 20];
+    for minor in glibc_older {
+        if glibc_minor <= minor {
+            write!(ct_glibc, "\nCT_GLIBC_2_{minor}_or_older=y")?;
+        }
+        if glibc_minor < minor {
+            write!(ct_glibc, "\nCT_GLIBC_older_than_2_{minor}=y")?;
+        }
+    }
+    if glibc_minor >= 17 {
+        ct_glibc.push_str("\nCT_GLIBC_2_17_or_later=y");
+    }
+    if glibc_minor <= 17 {
+        ct_glibc.push_str("\nCT_GLIBC_2_17_or_older=y");
+    }
+    if glibc_minor > 14 {
+        ct_glibc.push_str("\nCT_GLIBC_later_than_2_14=y");
+    }
+    if glibc_minor >= 14 {
+        ct_glibc.push_str("\nCT_GLIBC_2_14_or_later=y");
     }
 
     // configure the `CT_LINUX` values
-    if file_name.contains("linux") {
-        let linux_versions: Vec<&str> = linux_version.split('.').collect();
-        if !matches!(linux_versions.len(), 2 | 3) {
-            eyre::bail!("invalid linux version, got {linux_version}");
-        }
-        let linux_major = linux_versions[0].parse::<u32>()?;
-        let linux_minor = linux_versions[1].parse::<u32>()?;
-        let linux_patch = linux_versions.get(2).unwrap_or(&"0").parse::<u32>()?;
-        let ct_linux_v = format!(
-            r#"CT_LINUX_V_{linux_major}_{linux_minor}=y
+    let linux_major = linux_versions[0].parse::<u32>()?;
+    let linux_minor = linux_versions[1].parse::<u32>()?;
+    let linux_patch = linux_versions.get(2).unwrap_or(&"0").parse::<u32>()?;
+    let ct_linux_v = format!(
+        "CT_LINUX_V_{linux_major}_{linux_minor}=y
 # CT_LINUX_NO_VERSIONS is not set
-CT_LINUX_VERSION="{linux_major}.{linux_minor}.{linux_patch}""#
-        );
-        let mut ct_linux = String::new();
-        if linux_major < 4 || (linux_major == 4 && linux_minor < 8) {
-            ct_linux.push_str("\nCT_LINUX_older_than_4_8=y");
-            ct_linux.push_str("\nCT_LINUX_4_8_or_older=y");
-        } else {
-            ct_linux.push_str("\nCT_LINUX_later_than_4_8=y");
-            ct_linux.push_str("\nCT_LINUX_4_8_or_later=y");
-        }
-        if linux_major < 3 || (linux_major == 3 && linux_minor < 7) {
-            ct_linux.push_str("\nCT_LINUX_older_than_3_7=y");
-            ct_linux.push_str("\nCT_LINUX_3_7_or_older=y");
-            ct_linux.push_str("\nCT_LINUX_older_than_3_2=y");
-            ct_linux.push_str("\nCT_LINUX_3_2_or_older=y");
-        } else {
-            ct_linux.push_str("\nCT_LINUX_later_than_3_7=y");
-            ct_linux.push_str("\nCT_LINUX_3_7_or_later=y");
-            ct_linux.push_str("\nCT_LINUX_later_than_3_2=y");
-            ct_linux.push_str("\nCT_LINUX_3_2_or_later=y");
-        }
-        if ct_linux.starts_with('\n') {
-            ct_linux.remove(0);
-        }
-
-        contents =
-            contents
-                .replacen("%CT_LINUX_V%", &ct_linux_v, 1)
-                .replacen("%CT_LINUX%", &ct_linux, 1);
+CT_LINUX_VERSION=\"{linux_major}.{linux_minor}.{linux_patch}\""
+    );
+    let mut ct_linux = String::new();
+    if linux_major < 4 || (linux_major == 4 && linux_minor < 8) {
+        ct_linux.push_str("\nCT_LINUX_older_than_4_8=y");
+        ct_linux.push_str("\nCT_LINUX_4_8_or_older=y");
+    } else {
+        ct_linux.push_str("\nCT_LINUX_later_than_4_8=y");
+        ct_linux.push_str("\nCT_LINUX_4_8_or_later=y");
+    }
+    if linux_major < 3 || (linux_major == 3 && linux_minor < 7) {
+        ct_linux.push_str("\nCT_LINUX_older_than_3_7=y");
+        ct_linux.push_str("\nCT_LINUX_3_7_or_older=y");
+        ct_linux.push_str("\nCT_LINUX_older_than_3_2=y");
+        ct_linux.push_str("\nCT_LINUX_3_2_or_older=y");
+    } else {
+        ct_linux.push_str("\nCT_LINUX_later_than_3_7=y");
+        ct_linux.push_str("\nCT_LINUX_3_7_or_later=y");
+        ct_linux.push_str("\nCT_LINUX_later_than_3_2=y");
+        ct_linux.push_str("\nCT_LINUX_3_2_or_later=y");
     }
 
-    Ok(contents)
+    Ok(fs::read_to_string(src_file)?
+        .replacen("%CT_GCC_V%", &ct_gcc_v, 1)
+        .replacen("%CT_GCC%", &ct_gcc, 1)
+        .replacen("%CT_GLIBC_V%", &ct_glibc_v, 1)
+        .replacen("%CT_GLIBC%", &ct_glibc, 1)
+        .replacen("%CT_LINUX_V%", &ct_linux_v, 1)
+        .replacen("%CT_LINUX%", &ct_linux, 1))
 }
 
 pub fn configure_crosstool(
     ConfigureCrosstool {
         gcc_version,
         glibc_version,
-        uclibc_version,
-        musl_version,
-        newlib_version,
         linux_version,
         mut targets,
         ..
@@ -432,9 +210,6 @@ pub fn configure_crosstool(
 ) -> cross::Result<()> {
     let gcc_version = gcc_version.as_deref().unwrap_or(DEFAULT_GCC_VERSION);
     let glibc_version = glibc_version.as_deref().unwrap_or(DEFAULT_GLIBC_VERSION);
-    let uclibc_version = uclibc_version.as_deref().unwrap_or(DEFAULT_UCLIBC_VERSION);
-    let musl_version = musl_version.as_deref().unwrap_or(DEFAULT_MUSL_VERSION);
-    let newlib_version = newlib_version.as_deref().unwrap_or(DEFAULT_NEWLIB_VERSION);
     let linux_version = linux_version.as_deref().unwrap_or(DEFAULT_LINUX_VERSION);
 
     let root = project_dir(msg_info)?;
@@ -451,15 +226,7 @@ pub fn configure_crosstool(
         .map(|t| locate_ctng_config(&t, &root, &cross_toolchains_root))
         .collect::<cross::Result<Vec<_>>>()?;
     for (src_file, dst_file) in config_files {
-        let configured = configure_target(
-            &src_file,
-            gcc_version,
-            glibc_version,
-            uclibc_version,
-            musl_version,
-            newlib_version,
-            linux_version,
-        )?;
+        let configured = configure_target(&src_file, gcc_version, glibc_version, linux_version)?;
         write_to_string(&dst_file, &configured)?;
     }
 
diff --git a/xtask/src/target_info.sh b/xtask/src/target_info.sh
index 4be4497..a371612 100755
--- a/xtask/src/target_info.sh
+++ b/xtask/src/target_info.sh
@@ -161,7 +161,7 @@ case "${target}" in
     *-*-netbsd)
         cc_regex=".*gcc \(.*\) ([0-9]+.[0-9]+.[0-9]+).*"
         ;;
-    *-*-dragonfly)
+     *-*-dragonfly)
         cc_regex=".*gcc \(GCC\) ([0-9]+.[0-9]+.[0-9]+).*"
         ;;
     *-*-solaris)
diff --git a/xtask/src/util.rs b/xtask/src/util.rs
index 3e87e38..edac27e 100644
--- a/xtask/src/util.rs
+++ b/xtask/src/util.rs
@@ -276,14 +276,23 @@ pub fn project_dir(msg_info: &mut MessageInfo) -> cross::Result<PathBuf> {
     Ok(cargo_metadata(msg_info)?.workspace_root)
 }
 
+macro_rules! gha_output {
+    ($fmt:literal$(, $args:expr)* $(,)?) => {
+        #[cfg(not(test))]
+        println!($fmt $(, $args)*);
+        #[cfg(test)]
+        eprintln!($fmt $(,$args)*);
+    };
+}
+
 // note: for GHA actions we need to output these tags no matter the verbosity level
 pub fn gha_print(content: &str) {
-    println!("{}", content)
+    gha_output!("{}", content);
 }
 
 // note: for GHA actions we need to output these tags no matter the verbosity level
 pub fn gha_error(content: &str) {
-    println!("::error {}", content)
+    gha_output!("::error {}", content);
 }
 
 #[track_caller]
@@ -292,7 +301,7 @@ pub fn gha_output(tag: &str, content: &str) {
         // https://github.com/actions/toolkit/issues/403
         panic!("output `{tag}` contains newlines, consider serializing with json and deserializing in gha with fromJSON()")
     }
-    println!("::set-output name={tag}::{}", content)
+    gha_output!("::set-output name={tag}::{}", content);
 }
 
 pub fn read_dockerfiles(msg_info: &mut MessageInfo) -> cross::Result<Vec<(PathBuf, String)>> {


Test patch:
diff --git a/ci/test-remote.sh b/ci/test-remote.sh
index b6e506c..8b676f3 100755
--- a/ci/test-remote.sh
+++ b/ci/test-remote.sh
@@ -45,9 +45,7 @@ cross_test_cpp() {
 
     pushd "${td}"
     retry cargo fetch
-    "${CROSS}" run --target "${TARGET}" | grep "Hello, world!"
-    sed -i 's/Hello, world/Hello, test/g' hellopp.cc
-    "${CROSS}" run --target "${TARGET}" | grep "Hello, test!"
+    "${CROSS}" run --target "${TARGET}"
     popd
 
     rm -rf "${td}"
diff --git a/ci/test.sh b/ci/test.sh
index 474d61a..61f764f 100755
--- a/ci/test.sh
+++ b/ci/test.sh
@@ -13,10 +13,10 @@ ci_dir=$(realpath "${ci_dir}")
 . "${ci_dir}"/shared.sh
 
 workspace_test() {
-    "${CROSS[@]}" build --target "${TARGET}" --workspace "$@" ${CROSS_FLAGS}
-    "${CROSS[@]}" run --target "${TARGET}" -p binary "$@" ${CROSS_FLAGS}
-    "${CROSS[@]}" run --target "${TARGET}" --bin dependencies \
-        --features=dependencies "$@" ${CROSS_FLAGS}
+  "${CROSS[@]}" build --target "${TARGET}" --workspace "$@" ${CROSS_FLAGS}
+  "${CROSS[@]}" run --target "${TARGET}" -p binary "$@" ${CROSS_FLAGS}
+  "${CROSS[@]}" run --target "${TARGET}" --bin dependencies \
+    --features=dependencies "$@" ${CROSS_FLAGS}
 }
 
 main() {
@@ -182,21 +182,6 @@ main() {
 
         rm -rf "${td}"
     fi
-
-    # special tests for a shared C runtime, since we disable the shared c++ runtime
-    # https://github.com/cross-rs/cross/issues/902
-    if [[ "${TARGET}" == *-linux-musl* ]]; then
-        td=$(mkcargotemp -d)
-
-        pushd "${td}"
-        cargo init --bin --name hello .
-        retry cargo fetch
-        RUSTFLAGS="-C target-feature=-crt-static" \
-            "${CROSS[@]}" build --target "${TARGET}" ${CROSS_FLAGS}
-        popd
-
-        rm -rf "${td}"
-    fi
 }
 
 cross_run() {
diff --git a/src/tests.rs b/src/tests.rs
index 7a22907..02afac1 100644
--- a/src/tests.rs
+++ b/src/tests.rs
@@ -86,7 +86,6 @@ release: {version}
                     &None,
                     &ImagePlatform::from_const_target(TargetTriple::X86_64UnknownLinuxGnu),
                     Path::new("/toolchains/xxxx-x86_64-unknown-linux-gnu"),
-                    false,
                 ),
                 &target_meta.0,
                 &target_meta.1,