diff --git a/.github/workflows/ext-test.yml b/.github/workflows/ext-test.yml index 761f67d9..53e8d7ee 100644 --- a/.github/workflows/ext-test.yml +++ b/.github/workflows/ext-test.yml @@ -43,6 +43,12 @@ jobs: matrix: include: - { target: qemux86-64, distro-release: "2024", distro-channel: next } + # Keep a cross-arch leg. A same-arch target cannot catch a host/target + # toolchain mix-up in avocado-cli-compile.sh: on qemux86-64 the target + # gcc runs natively, so picking the wrong one still builds. On aarch64 + # the wrong pick goes through qemu-user and fails every C probe. + # qemuarm64, not a board: CI legs stay on qemu targets. + - { target: qemuarm64, distro-release: "2024", distro-channel: next } uses: avocado-linux/actions/.github/workflows/extension-test.yml@v1 with: target: ${{ matrix.target }} diff --git a/avocado-cli-compile.sh b/avocado-cli-compile.sh index c2af9802..a4d9cc02 100755 --- a/avocado-cli-compile.sh +++ b/avocado-cli-compile.sh @@ -32,6 +32,17 @@ for var in $(env | grep -o 'CARGO_TARGET_[A-Z0-9_]*_RUSTFLAGS'); do unset "$var" done +# Require the SDK vars before touching the tree or deriving any path. Letting +# them expand empty would collapse CROSS_BINDIR to "/usr/bin", where the -x check +# below finds the *host* gcc and quietly produces a native binary packaged as a +# target extension; an empty SDKTARGETSYSROOT would bake a bogus --sysroot into +# .cargo/config.toml. This script runs with `set -e` but not `set -u`, so nothing +# else catches it. Guarding here also means neither abort leaves a half-written +# .cargo/config.toml behind. +: "${OECORE_NATIVE_SYSROOT:?not set -- SDK environment-setup was not sourced}" +: "${SDKTARGETSYSROOT:?not set -- SDK environment-setup was not sourced}" +: "${CROSS_COMPILE:?not set -- SDK environment-setup was not sourced}" + # Remove only the generated cross-compile config, preserving any committed # .cargo files used for development. rm -f .cargo/config.toml @@ -44,13 +55,35 @@ rustflags = ["--sysroot=$SDKTARGETSYSROOT/usr", "-C", "link-arg=--sysroot=$SDKTA EOF # The SDK exports $CC as the cross-compiler command (bare name + target flags + -# --sysroot), but in the `ext build` environment that compiler binary lives in -# the SDK target-sysroot bindir, which is not on PATH. Without this, the `cc` -# crate (pulled in by the remaining C dep aws-lc-sys) can't resolve the compiler -# from $CC and falls back to guessing "-gcc", failing with ToolNotFound. -# Put the SDK compiler bindir on PATH so the build uses exactly the $CC the SDK -# configured. Arch-agnostic: derived from $SDKTARGETSYSROOT, no hardcoded triple. -export PATH="$SDKTARGETSYSROOT/usr/bin:$PATH" +# --sysroot), so the `cc` crate (pulled in by the C dep aws-lc-sys) needs that +# binary on PATH or it fails with ToolNotFound. +# +# It lives in the cross-canadian bindir under the SDK *native* sysroot -- NOT in +# $SDKTARGETSYSROOT/usr/bin, which holds the target-*native* toolchain. Putting +# the target sysroot bindir on PATH resolves "-gcc" to a target ELF; +# binfmt_misc then hands it to qemu-user, which dies on the unresolvable target +# loader ("qemu-aarch64: Could not open '/usr/lib/ld-linux-aarch64.so.1'") and +# fails every compiler probe with exit 255. That is invisible on a same-arch +# target like qemux86-64, where the target gcc happens to run natively. +# +# Arch-agnostic: the triple comes from $CROSS_COMPILE, no hardcoded value. +CROSS_BINDIR="$OECORE_NATIVE_SYSROOT/usr/bin/${CROSS_COMPILE%-}" + +# Name the compiler from $CROSS_COMPILE rather than parsing $CC. oe-core writes +# both from ${TARGET_PREFIX} in toolchain-scripts.bbclass, so $CC's first token +# is byte-identical to this in every SDK we ship against, and meta-clang only +# appends CLANGCC without overriding CC. Deriving it from $CC bought nothing and +# mis-read three real inputs: an empty first token (making -x test the bindir +# itself, so the guard passed), a ccache/distcc wrapper, and an absolute path. +CC_BIN="${CROSS_COMPILE}gcc" +if [ ! -x "$CROSS_BINDIR/$CC_BIN" ]; then + echo "Error: cross compiler '$CC_BIN' not found in $CROSS_BINDIR" >&2 + echo "The SDK is missing the C cross-canadian toolchain. An SDK installed" >&2 + echo "before it was added to avocado.yaml will not have it -- reinstall with:" >&2 + echo " avocado sdk install --force" >&2 + exit 1 +fi +export PATH="$CROSS_BINDIR:$PATH" # --locked: published builds run from staged package_files; fail loudly on a # missing/stale Cargo.lock instead of silently re-resolving dependencies. diff --git a/avocado.yaml b/avocado.yaml index 7ee983eb..073ae806 100644 --- a/avocado.yaml +++ b/avocado.yaml @@ -40,6 +40,11 @@ extensions: nativesdk-rust: '*' nativesdk-git: '*' packagegroup-rust-cross-canadian-avocado-{{ avocado.target }}: '*' + # The rust- packagegroup brings rust-cross-canadian + nativesdk-gcc (a + # HOST compiler); it does NOT bring a C cross-compiler. aws-lc-sys needs + # one, so pull the C cross-canadian toolchain explicitly -- this is what + # provides $OECORE_NATIVE_SYSROOT/usr/bin//-gcc. + packagegroup-cross-canadian-avocado-{{ avocado.target }}: '*' sdk: image: docker.io/avocadolinux/sdk:{{ env.AVOCADO_DISTRO_RELEASE }}