65816-llvm-mos/scripts/installLlvmMos.sh
Scott Duensing da095402ec Updated
2026-06-02 23:17:57 -05:00

127 lines
5.5 KiB
Bash
Executable file

#!/usr/bin/env bash
# Install + build the W65816 toolchain on top of llvm-mos:
# 1. Clone llvm-mos source.
# 2. Download the prebuilt llvm-mos-sdk (reference baseline).
# 3. Apply our W65816 backend INTO the clone (symlinks + patches).
# 4. Configure + build clang + llc + llvm-mc with the W65816 target.
# 5. Build link816 + omfEmit (the linker).
# 6. Build the runtime (libc.o, crt0.o, libgcc.o, etc.).
#
# Flags:
# --build (no-op; retained for backward compat — we always build)
set -euo pipefail
source "$(dirname "$0")/common.sh"
for arg in "$@"; do
case "$arg" in
--build) ;; # no-op; we always build now (see step 4)
*) die "unknown flag: $arg" ;;
esac
done
LLVM_SRC="$TOOLS_DIR/llvm-mos"
LLVM_BUILD="$TOOLS_DIR/llvm-mos-build"
LLVM_SDK="$TOOLS_DIR/llvm-mos-sdk"
SDK_URL="https://github.com/llvm-mos/llvm-mos-sdk/releases/latest/download/llvm-mos-linux.tar.xz"
# 1. Source tree for backend development.
#
# IMPORTANT: this clone is ephemeral scaffolding, not where we do work. Our
# own sources live in $PROJECT_ROOT/src/ and $PROJECT_ROOT/patches/ and are
# stitched into this tree by applyBackend.sh. That means a destructive
# reset here would stomp applied symlinks/patches — so we refuse to touch
# the clone if it looks modified. Use updateLlvmMos.sh to refresh safely.
if [ -d "$LLVM_SRC/.git" ]; then
currentBranch="$(git -C "$LLVM_SRC" rev-parse --abbrev-ref HEAD)"
if [ "$currentBranch" != "main" ]; then
warn "llvm-mos clone is on branch '$currentBranch' (not main); leaving untouched"
elif ! git -C "$LLVM_SRC" diff --quiet || ! git -C "$LLVM_SRC" diff --cached --quiet; then
warn "llvm-mos clone has local modifications; leaving untouched. Use scripts/updateLlvmMos.sh to refresh."
else
log "llvm-mos source already cloned; fetching and fast-forwarding main"
git -C "$LLVM_SRC" fetch --depth=1 origin main
git -C "$LLVM_SRC" merge --ff-only FETCH_HEAD || warn "fast-forward failed; leaving clone as-is"
fi
else
log "cloning llvm-mos (shallow)"
git clone --depth=1 https://github.com/llvm-mos/llvm-mos.git "$LLVM_SRC"
fi
# 2. Prebuilt SDK for testing/reference (smoke tests against the
# vanilla 6502 MOS target; mostly unused once you have a W65816
# build).
if [ -x "$LLVM_SDK/bin/mos-common-clang" ] || [ -x "$LLVM_SDK/bin/clang" ]; then
log "llvm-mos-sdk already extracted"
else
archive="$(fetchCached "$SDK_URL" "llvm-mos-linux.tar.xz")"
log "extracting llvm-mos-sdk"
install -d "$LLVM_SDK"
tar -xJf "$archive" -C "$LLVM_SDK" --strip-components=1
fi
# 3. Apply our W65816 backend INTO the clone (symlinks + patches).
# Must run BEFORE cmake configure so the W65816 target dir + cmake
# patch are present.
log "applying W65816 backend (symlinks + patches)"
bash "$(dirname "$0")/applyBackend.sh"
# 4. Configure + build LLVM with W65816 enabled. We always build —
# without a built clang the rest of the toolchain (runtime, link816)
# can't produce any usable output. --build is kept as a no-op flag
# for backward compat.
needCmd cmake
needCmd ninja
# Existence check covers the full LTO toolchain. llvm-link / llvm-as /
# llvm-dis / opt are required by scripts/ltoLink.sh (Phase 5.2 of
# GAP_CLOSURE_PLAN.md); clang and llc are the always-required core.
if [ -x "$LLVM_BUILD/bin/clang" ] && \
[ -x "$LLVM_BUILD/bin/llc" ] && \
[ -x "$LLVM_BUILD/bin/llvm-link" ] && \
[ -x "$LLVM_BUILD/bin/llvm-as" ] && \
[ -x "$LLVM_BUILD/bin/llvm-dis" ] && \
[ -x "$LLVM_BUILD/bin/opt" ] && \
"$LLVM_BUILD/bin/llc" --version 2>/dev/null | grep -q "^[[:space:]]*w65816[[:space:]]"; then
log "llvm-mos-build/bin/clang already exists and supports w65816 (LTO tools present)"
else
log "configuring llvm-mos build (LLVM + clang + lld; ~5 min after the first cmake)"
install -d "$LLVM_BUILD"
cmake -S "$LLVM_SRC/llvm" -B "$LLVM_BUILD" -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DLLVM_TARGETS_TO_BUILD="" \
-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD="MOS;W65816" \
-DLLVM_ENABLE_PROJECTS="clang;lld" \
-DLLVM_PARALLEL_LINK_JOBS=1 \
-DLLVM_USE_LINKER=lld \
-DLLVM_INCLUDE_TESTS=OFF \
-DLLVM_INCLUDE_EXAMPLES=OFF \
-DLLVM_INCLUDE_BENCHMARKS=OFF
log "building clang, llc, llvm-mc, llvm-objdump (the tools we actually use)"
# LTO chain: llvm-link merges bitcode, opt runs IR-level optimizations
# (including the Layer 2 gate from Phase 1.12), llvm-as / llvm-dis
# are the .bc <-> .ll round-trip for debugging. Phase 5.2.
ninja -C "$LLVM_BUILD" clang llc llvm-mc llvm-objdump llvm-readobj \
llvm-link llvm-as llvm-dis opt
log "llvm build done: $LLVM_BUILD/bin/clang"
fi
# Sanity check: llc must list w65816 as a registered target.
if ! "$LLVM_BUILD/bin/llc" --version 2>/dev/null | grep -q "^[[:space:]]*w65816[[:space:]]"; then
"$LLVM_BUILD/bin/llc" --version 2>/dev/null | head -20
warn "llc built but does NOT list w65816 as a target. Backend symlinks/patches may have failed. Re-run scripts/applyBackend.sh and ninja -C tools/llvm-mos-build."
fi
# 5. Build link816 + omfEmit.
log "building link816 + omfEmit"
make -C "$PROJECT_ROOT/src/link816" all
# 6. Build the runtime (libc.o, crt0.o, libgcc.o, etc.).
log "building runtime"
bash "$PROJECT_ROOT/runtime/build.sh"
log "llvm-mos install done"
log " source: $LLVM_SRC"
log " sdk: $LLVM_SDK"
log " build: $LLVM_BUILD"
log " clang: $LLVM_BUILD/bin/clang"
log " link816: $PROJECT_ROOT/tools/link816"
log " omfEmit: $PROJECT_ROOT/tools/omfEmit"