musl-vendor.sh (6638B)
1 #!/bin/sh 2 ## musl-vendor.sh — regenerate vendor/musl/overrides/ and 3 ## musl-1.2.5-deletes.txt from the upstream tarball + tcc-compat patch. 4 ## 5 ## NOT on the boot.sh path. This is a vendoring helper run on a dev host 6 ## any time vendor/musl/patches/tcc.patch changes; it requires 7 ## the host's `patch` binary. The output it produces (the overrides 8 ## directory tree + the deletes list) is what boot5.sh consumes — boot5 9 ## itself never invokes `patch`. 10 ## 11 ## What the script does: 12 ## 1. Extract a pristine copy of musl-1.2.5.tar.gz to a scratch dir. 13 ## 2. Apply musl-1.2.5-tcc.patch. 14 ## 3. For every file the patch touched: 15 ## - if non-empty in the patched tree → vendor it into 16 ## musl-1.2.5-overrides/<path>, mirroring the musl-1.2.5/ 17 ## subtree layout. 18 ## - if 0-byte (the patch's deleted-file marker) → record the 19 ## path in musl-1.2.5-deletes.txt. 20 ## 4. Append the per-arch sweep deletes (aarch64+riscv64 overrides 21 ## arm64-asm.c phase 1+2 / riscv64-asm.c can't yet handle). 22 ## 5. Sort + dedupe the deletes list. 23 ## 24 ## Boot4 then mirrors this state at build time without `patch`: 25 ## cp -R overrides/. musl-1.2.5/ 26 ## while read p; do rm -rf "musl-1.2.5/$p"; done < deletes.txt 27 28 set -eu 29 30 ROOT=$(cd "$(dirname "$0")/.." && pwd) 31 cd "$ROOT" 32 33 TARBALL=vendor/musl/1.2.5.tar.gz 34 PATCH_FILE=vendor/musl/patches/tcc.patch 35 OVERRIDES=vendor/musl/overrides 36 DELETES=vendor/musl/deletes.txt 37 GENERATED=vendor/musl/generated 38 MKALLTYPES_AWK=bootprep/mkalltypes.awk 39 40 [ -e "$TARBALL" ] || { echo "missing $TARBALL" >&2; exit 1; } 41 [ -e "$PATCH_FILE" ] || { echo "missing $PATCH_FILE" >&2; exit 1; } 42 command -v patch >/dev/null || { echo "host patch not found" >&2; exit 1; } 43 44 WORK=$(mktemp -d) 45 trap 'rm -rf "$WORK"' EXIT 46 47 # (1) extract 48 tar xzf "$TARBALL" -C "$WORK" 49 SRC=$WORK/musl-1.2.5 50 [ -d "$SRC" ] || { echo "tarball did not produce musl-1.2.5/"; exit 1; } 51 52 # (2) apply patch (cwd = parent of musl-1.2.5/, -p1 strips the a/ prefix) 53 ( cd "$WORK" && patch -p1 < "$ROOT/$PATCH_FILE" ) >"$WORK/patch.log" 2>&1 \ 54 || { tail -40 "$WORK/patch.log" >&2; exit 1; } 55 56 # (3) mirror touched files into overrides/, record empty ones as deletes 57 rm -rf "$OVERRIDES" 58 mkdir -p "$OVERRIDES" 59 : > "$DELETES" 60 61 # Each diff in the patch starts with `diff -urN ... patched_musl/musl-1.2.5/<rel>`. 62 # Strip the "patched_musl/musl-1.2.5/" prefix to get a path under SRC. 63 awk '/^diff -urN/ { 64 sub(/^patched_musl\/musl-1.2.5\//, "", $4); print $4 65 }' "$PATCH_FILE" | 66 while read -r rel; do 67 f=$SRC/$rel 68 if [ -s "$f" ]; then 69 mkdir -p "$OVERRIDES/$(dirname "$rel")" 70 cp "$f" "$OVERRIDES/$rel" 71 else 72 echo "$rel" >> "$DELETES" 73 fi 74 done 75 76 # (4) per-arch sweep: aarch64 + riscv64 files boot5 can't compile yet. 77 # Globs are expanded against the upstream tree, so every entry is a 78 # concrete file path (no glob in the deletes list itself). 79 for f in "$SRC"/src/math/aarch64/*.c; do 80 [ -e "$f" ] && echo "${f#$SRC/}" >> "$DELETES" 81 done 82 for f in "$SRC"/src/math/riscv64/*.c; do 83 [ -e "$f" ] && echo "${f#$SRC/}" >> "$DELETES" 84 done 85 { 86 echo src/string/aarch64/memset.S 87 echo src/string/aarch64/memcpy.S 88 echo src/fenv/aarch64/fenv.s 89 echo src/thread/aarch64/clone.s 90 echo src/thread/aarch64/syscall_cp.s 91 echo src/thread/aarch64/__unmapself.s 92 echo src/setjmp/aarch64/setjmp.s 93 echo src/setjmp/aarch64/longjmp.s 94 echo src/signal/aarch64/sigsetjmp.s 95 echo src/fenv/riscv64/fenv.S 96 echo src/fenv/riscv64/fenv-sf.c 97 echo src/setjmp/riscv64/setjmp.S 98 echo src/setjmp/riscv64/longjmp.S 99 echo src/signal/riscv64/sigsetjmp.s 100 echo src/signal/riscv64/restore.s 101 echo src/thread/riscv64/clone.s 102 echo src/thread/riscv64/syscall_cp.s 103 echo src/thread/riscv64/__unmapself.s 104 echo src/process/riscv64/vfork.s 105 # src/complex/ is gutted by the patch (every .c file becomes 0-byte 106 # in the patched tree, so it's already in DELETES). The dir entry 107 # cleans up the empty directory itself. 108 echo src/complex 109 } >> "$DELETES" 110 111 # (5) sort + dedupe 112 sort -u "$DELETES" -o "$DELETES" 113 114 # (6) pre-generate per-arch alltypes.h + syscall.h. 115 # These are deterministic given the upstream tree + chosen arch (musl's 116 # Makefile runs the same two transformations at build time). Vendoring 117 # them lets the boot5 container drop awk entirely — it just `cp`s the 118 # right file in. mkalltypes runs on the post-overrides tree (overrides 119 # don't touch alltypes.h.in, but applying them keeps the procedure 120 # coherent). Apply overrides + deletes to a fresh post-patch copy and 121 # generate from there. 122 POST=$WORK/post 123 mkdir -p "$POST" 124 cp -R "$SRC" "$POST/" 125 cp -R "$ROOT/$OVERRIDES/." "$POST/musl-1.2.5/" 126 while read -r p; do 127 [ -n "$p" ] && rm -rf "$POST/musl-1.2.5/$p" 128 done < "$ROOT/$DELETES" 129 130 rm -rf "$ROOT/$GENERATED" 131 for MARCH in aarch64 x86_64 riscv64; do 132 out=$ROOT/$GENERATED/$MARCH 133 mkdir -p "$out" 134 # Post-process: simplify struct timespec to drop the trailing 135 # zero-width bitfield (see comment above the awk pipeline below). 136 awk -f "$ROOT/$MKALLTYPES_AWK" \ 137 "$POST/musl-1.2.5/arch/$MARCH/bits/alltypes.h.in" \ 138 "$POST/musl-1.2.5/include/alltypes.h.in" \ 139 | awk ' 140 /^struct timespec \{.*tv_nsec/ { 141 print "struct timespec { time_t tv_sec; long tv_nsec; };" 142 next 143 } 144 { print } 145 ' > "$out/alltypes.h" 146 # Why the post-process: tcc 0.9.26 emits "will touch memory past 147 # end of the struct (internal limitation)" for any struct ending 148 # in a zero-width bitfield. The musl alltypes.h definition wraps 149 # tv_nsec in two bitfield-padding tricks for 32-bit-time_t arches: 150 # 151 # struct timespec { time_t tv_sec; 152 # int :8*(sizeof(time_t)-sizeof(long))*(__BYTE_ORDER==4321); 153 # long tv_nsec; 154 # int :8*(sizeof(time_t)-sizeof(long))*(__BYTE_ORDER!=4321); 155 # }; 156 # 157 # On all three boot5 arches sizeof(time_t)==sizeof(long)==8, so 158 # both bitfields are 0 width and the layout is identical to the 159 # simple two-field form. The leading bitfield does not warn (a 160 # sibling follows); the trailing one does, 387 times per build. 161 cp "$POST/musl-1.2.5/arch/$MARCH/bits/syscall.h.in" "$out/syscall.h" 162 awk 'sub(/__NR_/, "SYS_") { print }' \ 163 < "$POST/musl-1.2.5/arch/$MARCH/bits/syscall.h.in" \ 164 >> "$out/syscall.h" 165 done 166 167 n_files=$(find "$OVERRIDES" -type f | wc -l) 168 n_dels=$(wc -l < "$DELETES") 169 n_gen=$(find "$GENERATED" -type f | wc -l) 170 echo "musl-vendor: overrides=$n_files deletes=$n_dels generated=$n_gen" 171 echo " $OVERRIDES" 172 echo " $DELETES"