|
| 1 | +#!/usr/bin/env bash |
| 2 | +# Repro for 2026-10-23-target-base-and-execution-host-design.md §1. |
| 3 | +# |
| 4 | +# Builds, from the payloads an mcpp home already holds: |
| 5 | +# toolchain/ gcc 16.1.0 + binutils 2.42.1 in one prefix, pristine specs |
| 6 | +# (a "vendor" gcc: not a path inside mcpp's registry) |
| 7 | +# xgcc/ aarch64-linux-musl-gcc 16.1.0 (a cross toolchain carrying a sysroot) |
| 8 | +# sysroot-glibc244/ glibc 2.44.3 + linux-headers, crosstool-ng layout |
| 9 | +# sysroot-glibc231/ Debian 11 glibc 2.31 (only with FETCH_DEBIAN=1; needs network) |
| 10 | +# and runs the scenario matrix A-K against $MCPP (J and K drive the compilers directly: |
| 11 | +# mcpp has no spelling for a host sysroot yet). |
| 12 | +# |
| 13 | +# Usage: MCPP=/path/to/mcpp [FETCH_DEBIAN=1] [WORK=/tmp/sysroot-demo] bash this.sh |
| 14 | +set -uo pipefail |
| 15 | +MCPP=${MCPP:?set MCPP to the mcpp binary under test} |
| 16 | +WORK=${WORK:-/tmp/sysroot-demo} |
| 17 | +R=${MCPP_HOME:-$HOME/.mcpp}/registry/data/xpkgs |
| 18 | +GCC=$R/xim-x-gcc/16.1.0 |
| 19 | +BINUTILS=$(ls -d $R/xim-x-binutils/* | tail -1) |
| 20 | +GLIBC=$R/xim-x-glibc/2.44.3 |
| 21 | +HEADERS=$(ls -d $R/xim-x-linux-headers/* | tail -1) |
| 22 | +XGCC=$(ls -d $R/xim-x-aarch64-linux-musl-gcc/* | tail -1) |
| 23 | +export MCPP_NO_AUTO_INSTALL=1 MCPP_JOBS=${MCPP_JOBS:-8} |
| 24 | + |
| 25 | +mkdir -p "$WORK" |
| 26 | +T=$WORK/toolchain S=$WORK/sysroot-glibc244 X=$WORK/xgcc |
| 27 | + |
| 28 | +# ── toolchains ───────────────────────────────────────────────────────────── |
| 29 | +rm -rf "$T" "$X" |
| 30 | +cp -a "$GCC" "$T"; chmod -R u+w "$T" |
| 31 | +rm -f "$T"/lib/gcc/x86_64-linux-gnu/*/specs # the registry copy carries baked specs |
| 32 | +mkdir -p "$T/x86_64-linux-gnu/bin" |
| 33 | +for t in as ld ld.bfd ar nm ranlib objcopy objdump strip readelf; do |
| 34 | + cp -a "$BINUTILS/bin/$t" "$T/bin/$t" |
| 35 | + ln -sf "../../bin/$t" "$T/x86_64-linux-gnu/bin/$t" |
| 36 | +done |
| 37 | +cp -a "$XGCC" "$X"; chmod -R u+w "$X" |
| 38 | + |
| 39 | +# ── sysroots (crosstool-ng layout: usr/include, usr/lib64, lib64 -> usr/lib64) ─ |
| 40 | +layout() { mkdir -p "$1/usr/include" "$1/usr/lib64" "$1/lib" "$1/usr/lib"; ln -sfn usr/lib64 "$1/lib64"; } |
| 41 | +relink_scripts() { # $1 sysroot, $2 sed expression; text-only files (-I) |
| 42 | + for f in $(grep -lI "GROUP\|INPUT" "$1"/usr/lib64/*.so 2>/dev/null); do sed -i "$2" "$f"; done |
| 43 | +} |
| 44 | +rm -rf "$S"; layout "$S" |
| 45 | +cp -a "$GLIBC/include/." "$HEADERS/include/." "$S/usr/include/" |
| 46 | +cp -a "$GLIBC/lib/." "$S/usr/lib64/"; chmod -R u+w "$S" |
| 47 | +relink_scripts "$S" "s#$GLIBC/lib/#/lib64/#g" |
| 48 | + |
| 49 | +if [ "${FETCH_DEBIAN:-0}" = 1 ]; then |
| 50 | + O=$WORK/sysroot-glibc231; rm -rf "$O"; mkdir -p "$O/x" "$WORK/dl" |
| 51 | + for f in g/glibc/libc6_2.31-13+deb11u11_amd64.deb g/glibc/libc6-dev_2.31-13+deb11u11_amd64.deb \ |
| 52 | + l/linux/linux-libc-dev_5.10.223-1_amd64.deb; do |
| 53 | + [ -f "$WORK/dl/${f##*/}" ] || curl -sSfL -o "$WORK/dl/${f##*/}" "https://deb.debian.org/debian/pool/main/$f" |
| 54 | + dpkg-deb -x "$WORK/dl/${f##*/}" "$O/x" |
| 55 | + done |
| 56 | + layout "$O" |
| 57 | + cp -a "$O/x/usr/include/." "$O/x/usr/include/x86_64-linux-gnu/." "$O/usr/include/" |
| 58 | + cp -a "$O/x/lib/x86_64-linux-gnu/." "$O/x/usr/lib/x86_64-linux-gnu/." "$O/usr/lib64/" |
| 59 | + rm -rf "$O/x" |
| 60 | + relink_scripts "$O" "s#/usr/lib/x86_64-linux-gnu/#/lib64/#g; s#/lib/x86_64-linux-gnu/#/lib64/#g" |
| 61 | + for l in $(find "$O/usr/lib64" -maxdepth 1 -type l); do |
| 62 | + t=$(readlink "$l"); case $t in /lib/x86_64-linux-gnu/*) ln -sfn "$(basename "$t")" "$l";; esac |
| 63 | + done |
| 64 | +fi |
| 65 | + |
| 66 | +# ── sources ──────────────────────────────────────────────────────────────── |
| 67 | +GLIBC_MAIN='#include <gnu/libc-version.h> |
| 68 | +#include <pthread.h> |
| 69 | +import std; |
| 70 | +int main() { |
| 71 | + std::println("compiled against glibc {}.{}", __GLIBC__, __GLIBC_MINOR__); |
| 72 | + std::println("running on glibc {}", gnu_get_libc_version()); |
| 73 | +#if __GLIBC_PREREQ(2, 42) |
| 74 | + std::println("pthread_gettid_np = {}", pthread_gettid_np(pthread_self())); // GLIBC_2.42 |
| 75 | +#endif |
| 76 | +}' |
| 77 | +PLAIN_MAIN='import std; |
| 78 | +int main() { std::println("hello from a {}-bit target", sizeof(void*) * 8); }' |
| 79 | + |
| 80 | +scenario() { # name, main, manifest-tail, [build args] |
| 81 | + local d=$WORK/m/$1; rm -rf "$d"; mkdir -p "$d/src" |
| 82 | + printf '%s\n' "$2" > "$d/src/main.cpp" |
| 83 | + printf '[package]\nname = "m%s"\nversion = "0.1.0"\n\n%s\n' "$1" "$3" > "$d/mcpp.toml" |
| 84 | + echo "================ $1 ${4:-}"; sed -n '5,$p' "$d/mcpp.toml" |
| 85 | + ( cd "$d" && nice -n 10 "$MCPP" build ${4:-} 2>&1 | grep -v '^\s*\(Index\|Inferred\)' | tail -6 ) |
| 86 | + local b; b=$(ls "$d"/target/*/*/bin/m$1 2>/dev/null | head -1) |
| 87 | + [ -n "$b" ] || return 0 |
| 88 | + file "$b" | cut -d, -f1-2 |
| 89 | + readelf -lW "$b" 2>/dev/null | grep -o 'interpreter: [^]]*' |
| 90 | + readelf -dW "$b" 2>/dev/null | grep -i 'rpath\|runpath' |
| 91 | + file "$b" | grep -q x86-64 && { echo "-- run:"; "$b" 2>&1 | head -3; } |
| 92 | +} |
| 93 | + |
| 94 | +scenario A "$GLIBC_MAIN" "[toolchain.linux] |
| 95 | +path = \"$T\"" |
| 96 | +scenario B "$GLIBC_MAIN" "[toolchain.linux] |
| 97 | +path = \"$T\" |
| 98 | +prefix = \"x86_64-linux-gnu-\"" |
| 99 | +scenario C "$GLIBC_MAIN" "[toolchain.linux] |
| 100 | +path = \"$T\" |
| 101 | +sysroot = \"$S\"" |
| 102 | +scenario D "$GLIBC_MAIN" "[toolchain.linux] |
| 103 | +path = \"$T\" |
| 104 | +sysroot = \"$S\" |
| 105 | +
|
| 106 | +[build] |
| 107 | +ldflags = [\"-Wl,--sysroot=$S\"]" |
| 108 | +scenario E "$GLIBC_MAIN" "[toolchain.linux] |
| 109 | +path = \"$T\" |
| 110 | +sysroot = \"$S\" |
| 111 | +
|
| 112 | +[build] |
| 113 | +ldflags = [\"-Wl,--sysroot=$S\", \"-Wl,--dynamic-linker=$S/lib64/ld-linux-x86-64.so.2\", \"-Wl,-rpath,$S/lib64\"]" |
| 114 | +scenario F "$GLIBC_MAIN" "[toolchain] |
| 115 | +linux = \"gcc@16.1.0\" |
| 116 | +
|
| 117 | +[target.x86_64-linux-gnu] |
| 118 | +sysroot = \"$S\"" |
| 119 | +scenario G "$PLAIN_MAIN" "[toolchain.linux] |
| 120 | +path = \"$X\" |
| 121 | +prefix = \"aarch64-linux-musl-\"" |
| 122 | +scenario H "$PLAIN_MAIN" "[toolchain.linux] |
| 123 | +path = \"$X\" |
| 124 | +prefix = \"aarch64-linux-musl-\" |
| 125 | +sysroot = \"$X/aarch64-linux-musl\"" |
| 126 | +if [ -d "$WORK/sysroot-glibc231" ]; then |
| 127 | + scenario I "$PLAIN_MAIN" "[toolchain.linux] |
| 128 | +path = \"$T\" |
| 129 | +sysroot = \"$WORK/sysroot-glibc231\"" |
| 130 | +fi |
| 131 | + |
| 132 | +# ── J / K: the host's own root as the sysroot (Debian/Ubuntu multiarch) ───── |
| 133 | +# Not through mcpp: `glibc@system` is what the design adds. The ecosystem gcc is |
| 134 | +# built without multiarch (-print-multiarch is empty), so J fails until the |
| 135 | +# multiarch directories are wired; clang (K) resolves them itself. |
| 136 | +LLVM=$(ls -d $R/xim-x-llvm/* 2>/dev/null | tail -1) |
| 137 | +TUPLE=$(/usr/bin/gcc -print-multiarch 2>/dev/null); [ -n "$TUPLE" ] || TUPLE=$(uname -m)-linux-gnu |
| 138 | +mkdir -p "$WORK/m/J"; printf '%s\n' '#include <gnu/libc-version.h>' '#include <stdio.h>' \ |
| 139 | + 'int main(){printf("compiled against %d.%d, running on %s\n",__GLIBC__,__GLIBC_MINOR__,gnu_get_libc_version());}' > "$WORK/m/J/c.c" |
| 140 | +echo "================ J (gcc --sysroot=/)" |
| 141 | +"$T/bin/gcc" --sysroot=/ "$WORK/m/J/c.c" -o "$WORK/m/J/plain" 2>&1 | tail -2 |
| 142 | +echo "-- with the multiarch directories wired:" |
| 143 | +"$T/bin/gcc" --sysroot=/ -B/usr/lib/$TUPLE -L/usr/lib/$TUPLE -L/lib/$TUPLE -isystem /usr/include/$TUPLE \ |
| 144 | + -Wl,-rpath-link,/lib/$TUPLE "$WORK/m/J/c.c" -o "$WORK/m/J/wired" 2>&1 | tail -2 && "$WORK/m/J/wired" |
| 145 | +if [ -n "$LLVM" ]; then |
| 146 | + echo "================ K (clang --sysroot=/)" |
| 147 | + "$LLVM/bin/clang" --no-default-config --sysroot=/ "$WORK/m/J/c.c" -o "$WORK/m/J/clang" 2>&1 | tail -2 && "$WORK/m/J/clang" |
| 148 | +fi |
0 commit comments