boot5.sh (7673B)
1 #!/bin/sh 2 ## boot5.sh — build musl-1.2.5 with boot4 artifacts and link hello. 3 ## 4 ## Builds on top of boot4's verified-fixed-point tcc (tcc2 == tcc3) and 5 ## demonstrates that the same compiler can produce a working static libc 6 ## from upstream musl source — patched only as far as needed to work 7 ## around tcc's missing GCC extensions (register-asm-variable syscalls, 8 ## attribute(alias) weak refs, _Complex, x86_64 SSE/x87 inline asm). 9 ## 10 ## ─── Inputs ────────────────────────────────────────────────────────── 11 ## build/$ARCH/$DRIVER/boot4/tcc3 — boot4's verified self-host tcc 12 ## build/$ARCH/$DRIVER/boot4/libtcc1.a — boot4's tcc runtime archive 13 ## build/$ARCH/$DRIVER/boot2/{catm, scheme1} 14 ## build/$ARCH/src/src/musl/ — canonical musl tree (overrides 15 ## merged, deletes applied, 16 ## alltypes.h/syscall.h generated, 17 ## per-arch skip filter applied) 18 ## build/$ARCH/src/src/tcc/stdarg-bridge.h 19 ## build/$ARCH/src/src/test-fixtures/boot-hello.c 20 ## 21 ## ─── Tools ──────────────────────────────────────────────────────────── 22 ## scheme1 evaluates a host-generated run.scm (from boot5-gen-runscm.sh) 23 ## against the flat staging root. 24 ## 25 ## ─── Outputs ───────────────────────────────────────────────────────── 26 ## build/$ARCH/$DRIVER/boot5/libc.a 27 ## build/$ARCH/$DRIVER/boot5/{crt1.o, crti.o, crtn.o} 28 ## build/$ARCH/$DRIVER/boot5/hello — static, runs in the container 29 ## 30 ## Usage: scripts/boot5.sh <arch> 31 ## <arch> ∈ {aarch64, amd64, riscv64} for either DRIVER (default podman). 32 33 set -eu 34 35 . scripts/lib-arch.sh 36 bootlib_init boot5 "${1:-}" 37 driver_init empty 38 require_src 39 40 BOOT2=build/$ARCH/$DRIVER/boot2 41 BOOT4=build/$ARCH/$DRIVER/boot4 42 SRC=build/$ARCH/src 43 MUSL_DIR=$SRC/src/musl 44 45 # ── prerequisites ───────────────────────────────────────────────────── 46 require_prev "$BOOT4" tcc3 47 require_prev "$BOOT2" catm scheme1 48 require_file "$BOOT4/libtcc1.a" "run scripts/boot4.sh $ARCH" 49 require_file "$MUSL_DIR" "run scripts/prep-src.sh $ARCH and scripts/prep-musl.sh $ARCH" 50 require_file "$MUSL_DIR/skip.txt" "run scripts/prep-musl.sh $ARCH" 51 require_file "$SRC/src/tcc/stdarg-bridge.h" "run scripts/prep-src.sh $ARCH" 52 53 # ── prepare staging dirs ────────────────────────────────────────────── 54 # $STAGE/in/ — read-only inputs (becomes /work/in or in/ in tmpfs) 55 # $STAGE/out/ — writable outputs (becomes /work/out or out/ in tmpfs) 56 # $STAGE/_host/ — host-side scratch (enumeration outputs); never 57 # visible to the container/kernel. 58 . scripts/lib-runscm.sh 59 runscm_init "$STAGE" "$OUT" 60 mkdir -p "$STAGE/_host" 61 62 # ── enumerate musl sources from the canonical tree ──────────────────── 63 # Mirrors musl's Makefile rule: a per-arch override (under 64 # $d/$MUSL_ARCH/) replaces the same-stem base file (under $d/). The 65 # canonical tree already had the per-arch skip filter applied by 66 # prep-musl.sh, so no skip subtraction is needed here. 67 SRC_TOP="src/aio src/conf src/crypt src/ctype src/dirent 68 src/env src/errno src/exit src/fcntl src/fenv src/internal 69 src/ipc src/legacy src/linux src/locale src/malloc 70 src/malloc/mallocng src/math src/misc src/mman src/mq 71 src/multibyte src/network src/passwd src/prng src/process 72 src/regex src/sched src/search src/select src/setjmp src/signal 73 src/stat src/stdio src/stdlib src/string src/temp src/termios 74 src/thread src/time src/unistd" 75 76 ( 77 cd "$MUSL_DIR" 78 for d in $SRC_TOP; do 79 [ -d "$d" ] || continue 80 for f in $d/*.c; do [ -f "$f" ] && echo "$f"; done 81 done 82 ) > "$STAGE/_host/base.txt" 83 84 ( 85 cd "$MUSL_DIR" 86 for d in $SRC_TOP; do 87 [ -d "$d/$MUSL_ARCH" ] || continue 88 for f in $d/$MUSL_ARCH/*.c $d/$MUSL_ARCH/*.s $d/$MUSL_ARCH/*.S; do 89 [ -f "$f" ] && echo "$f" 90 done 91 done 92 ) > "$STAGE/_host/arch.txt" 93 94 # REPLACED: bases that have arch-specific overrides (drop them from 95 # BASE). KEEP = (BASE - REPLACED) ∪ ARCH. 96 awk -v ARCH="$MUSL_ARCH" ' 97 { 98 sub(/\.[^.]*$/, "") # strip extension 99 slot = "/" ARCH "/" 100 i = index($0, slot) 101 head = substr($0, 1, i - 1) 102 tail = substr($0, i + length(slot)) 103 print head "/" tail 104 } 105 ' "$STAGE/_host/arch.txt" | sort -u > "$STAGE/_host/replaced.txt" 106 107 # Filter base by removing stems that appear in replaced. 108 awk -v REPF="$STAGE/_host/replaced.txt" ' 109 BEGIN { while ((getline l < REPF) > 0) rep[l] = 1 } 110 { 111 stem = $0 112 sub(/\.c$/, "", stem) 113 if (!(stem in rep)) print 114 } 115 ' "$STAGE/_host/base.txt" > "$STAGE/_host/keep_base.txt" 116 117 cat "$STAGE/_host/keep_base.txt" "$STAGE/_host/arch.txt" | sort -u > "$STAGE/_host/build-srcs.txt" 118 119 n_src=$(wc -l < "$STAGE/_host/build-srcs.txt") 120 n_skip=$(grep -cv '^[[:space:]]*\(#\|$\)' "$MUSL_DIR/skip.txt" || true) 121 echo "[$BOOT_TAG] keep=$n_src skip=$n_skip (calibrated)" 122 123 # Record CRT mode (asm vs c) so the gen-runscm step picks the right 124 # crti/crtn source set without re-checking $MUSL_DIR. 125 if [ -f "$MUSL_DIR/crt/$MUSL_ARCH/crti.s" ]; then 126 echo asm > "$STAGE/_host/crt-mode" 127 else 128 echo c > "$STAGE/_host/crt-mode" 129 fi 130 131 # Pre-create per-source obj/ directories under $STAGE/out/obj/musl/ so 132 # scheme1's (run "in/tcc" -c …) doesn't need to mkdir at runtime (tcc 133 # errors out if the parent dir is missing, and scheme1 has no mkdir 134 # primitive). 135 awk ' 136 { 137 sub(/\.[^.]*$/, "") 138 if (match($0, /\/[^\/]*$/)) print substr($0, 1, RSTART - 1) 139 } 140 ' "$STAGE/_host/build-srcs.txt" | sort -u > "$STAGE/_host/build-objdirs.txt" 141 COBJ=$STAGE/out/obj/musl 142 mkdir -p "$COBJ/crt" 143 while read -r d; do mkdir -p "$COBJ/$d"; done < "$STAGE/_host/build-objdirs.txt" 144 145 # ── generate run.scm and stage chain binaries ───────────────────────── 146 runscm_gen scripts/boot5-gen-runscm.sh "$MUSL_ARCH" "$STAGE/_host" 147 148 runscm_scheme1 "$BOOT2/scheme1" 149 runscm_prelude "$SRC/src/scheme1/prelude.scm" 150 151 # Chain binaries staged at flat in/ root (cwd-relative names in run.scm). 152 runscm_input tcc "$BOOT4/tcc3" 153 runscm_input libtcc1.a "$BOOT4/libtcc1.a" 154 runscm_input catm "$BOOT2/catm" 155 runscm_input_from_src tcc/stdarg-bridge.h tcc-stdarg-bridge.h 156 runscm_input_from_src test-fixtures/boot-hello.c hello.c 157 158 # Stage the canonical musl tree under in/musl/. Both drivers pick it 159 # up automatically (podman bind-mounts $STAGE/in; seed packs 160 # `find in -type f` into the cpio). 161 runscm_input_tree_from_src musl musl 162 163 runscm_export libc.a crt1.o crti.o crtn.o hello 164 165 # boot5 has ~1300 spawns + heavy tcc work; bump qemu memory + timeout for 166 # the seed driver. Podman ignores QEMU_MEM and uses host memory directly. 167 QEMU_MEM=${QEMU_MEM:-3072M} runscm_run "${BOOT5_TIMEOUT:-7200}" 168 169 echo "[$BOOT_TAG] sizes: libc.a=$(wc -c <"$OUT/libc.a") hello=$(wc -c <"$OUT/hello")" 170 echo "[$BOOT_TAG] OK -> $OUT/{libc.a, crt1.o, crti.o, crtn.o, hello}"