boot2

Playing with the boostrap
git clone https://git.ryansepassi.com/git/boot2.git
Log | Files | Refs | README

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"