#!/usr/bin/env bash # # build-native-sdk.sh — Build the Montauk SDK: binutils + GCC compiled # to run *on* MontaukOS (--host=x86_64-montauk), staged for the OS image. # # Usage: ./toolchain/build-native-sdk.sh (or: make sdk) # # Produces: # toolchain/native/sdk/ — native as/ld/ar/nm/... (stripped) # toolchain/native-gcc/sdk/ — native gcc/g++ driver + cc1/cc1plus/collect2 # # The `devkit` target in programs/GNUmakefile ships these into the OS # image at 0:/sdk. Without them the ISO builds WITHOUT the SDK. # # Requires the x86_64-montauk cross toolchain (build-montauk-toolchain.sh # is invoked automatically; it also downloads/patches the shared sources # and refreshes toolchain/sysroot from the current libc). # # This script is idempotent — each stage is skipped once its output # exists. To force a rebuild (e.g. after libc changes, so the native # tools relink against the fixed libc): # rm -rf toolchain/native toolchain/native-gcc \ # toolchain/build/binutils-native toolchain/build/gcc-native set -euo pipefail BINUTILS_VERSION="2.43.1" GCC_VERSION="14.2.0" HOST="x86_64-montauk" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PREFIX="${SCRIPT_DIR}/local" SRC_DIR="${SCRIPT_DIR}/src" BUILD_DIR="${SCRIPT_DIR}/build" SYSROOT="${SCRIPT_DIR}/sysroot" NATIVE_BINUTILS="${SCRIPT_DIR}/native" NATIVE_GCC="${SCRIPT_DIR}/native-gcc" JOBS="$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4)" bold() { printf '\033[1m%s\033[0m\n' "$*"; } green() { printf '\033[1;32m%s\033[0m\n' "$*"; } bold "=== Building the Montauk SDK (native ${HOST} binutils + GCC) ===" # ── Cross toolchain + sources + sysroot ────────────────────────────────────── # build-montauk-toolchain.sh is idempotent: it downloads and patches the # shared binutils/GCC sources, always refreshes the sysroot from the # current libc, and skips compiler builds once installed. "${SCRIPT_DIR}/build-montauk-toolchain.sh" export PATH="${PREFIX}/bin:${PATH}" # ── Host-build fix-ups in the GCC source tree ──────────────────────────────── # The bundled gmp/mpfr/mpc/isl/gettext carry their own config.sub copies # that predate the montauk target; overwrite each with the patched # top-level one so they configure for --host=x86_64-montauk. GCC_SRC="${SRC_DIR}/gcc-${GCC_VERSION}" for sub in gmp mpfr mpc isl gettext; do for cs in "${GCC_SRC}/${sub}/config.sub" "${GCC_SRC}/${sub}/build-aux/config.sub"; do if [[ -f "${cs}" ]] && ! grep -q montauk "${cs}"; then bold "Patching config.sub: ${cs#"${SRC_DIR}/"}" cp "${GCC_SRC}/config.sub" "${cs}" fi done done # --disable-nls does not skip the bundled gettext, and its gnulib needs # more locale surface than the Montauk libc has. Drop the symlink so the # toplevel treats it as absent. if [[ -L "${GCC_SRC}/gettext" ]]; then bold "Removing gettext symlink (not buildable against the Montauk libc)" rm "${GCC_SRC}/gettext" fi # The gcc subdir resolves --with-native-system-header-dir=/sdk/include # inside the build sysroot at build time; give the sysroot an sdk -> usr # alias so that path exists. if [[ ! -e "${SYSROOT}/sdk" ]]; then ln -s usr "${SYSROOT}/sdk" fi # ── Native binutils ────────────────────────────────────────────────────────── if [[ -x "${NATIVE_BINUTILS}/sdk/bin/ld" ]]; then bold "Native binutils already staged — skipping." else bold "Building native binutils ${BINUTILS_VERSION} (host ${HOST})..." rm -rf "${BUILD_DIR}/binutils-native" mkdir -p "${BUILD_DIR}/binutils-native" ( cd "${BUILD_DIR}/binutils-native" "${SRC_DIR}/binutils-${BINUTILS_VERSION}/configure" \ --build=x86_64-pc-linux-gnu \ --host="${HOST}" \ --target="${HOST}" \ --prefix=/sdk \ --disable-nls \ --disable-werror \ --disable-gprofng \ --disable-gold \ --disable-plugins \ --disable-shared \ --enable-static # Only gas/ld/binutils: gprof needs fscanf %[] scansets the # Montauk libc lacks; gold and gprofng are disabled outright. make -j"${JOBS}" all-gas all-ld all-binutils make install-strip-gas install-strip-ld install-strip-binutils \ DESTDIR="${NATIVE_BINUTILS}" ) green "Native binutils staged into toolchain/native/sdk." fi # ── Native GCC ─────────────────────────────────────────────────────────────── if [[ -x "${NATIVE_GCC}/sdk/bin/gcc" ]]; then bold "Native GCC already staged — skipping." else bold "Building native GCC ${GCC_VERSION} (host ${HOST})..." rm -rf "${BUILD_DIR}/gcc-native" mkdir -p "${BUILD_DIR}/gcc-native" ( cd "${BUILD_DIR}/gcc-native" "${SRC_DIR}/gcc-${GCC_VERSION}/configure" \ --build=x86_64-pc-linux-gnu \ --host="${HOST}" \ --target="${HOST}" \ --prefix=/sdk \ --with-native-system-header-dir=/sdk/include \ --with-build-sysroot="${SYSROOT}" \ --enable-languages=c,c++ \ --disable-nls \ --disable-shared \ --disable-multilib \ --disable-gcov \ --disable-lto \ --disable-plugin \ --disable-bootstrap \ --disable-fixincludes \ --with-newlib \ --enable-initfini-array \ --disable-wchar_t \ --disable-libstdcxx-pch \ --with-gnu-as \ --with-gnu-ld # The gcc subdir configure cannot run host (montauk) binaries to # probe endianness; preset it. ac_cv_c_bigendian=no make -j"${JOBS}" all-gcc make install-gcc DESTDIR="${NATIVE_GCC}" ) # install-gcc does not strip, and cc1/cc1plus carry ~700 MB of debug # info between them (the ISO balloons to 1.7 GB if this is skipped). bold "Stripping native GCC binaries..." GCC_LIBEXEC="${NATIVE_GCC}/sdk/libexec/gcc/${HOST}/${GCC_VERSION}" for b in "${GCC_LIBEXEC}/cc1" "${GCC_LIBEXEC}/cc1plus" "${GCC_LIBEXEC}/collect2" \ "${NATIVE_GCC}/sdk/bin/gcc" "${NATIVE_GCC}/sdk/bin/g++" \ "${NATIVE_GCC}/sdk/bin/cpp"; do if [[ -f "${b}" ]]; then "${PREFIX}/bin/${HOST}-strip" "${b}" fi done green "Native GCC staged into toolchain/native-gcc/sdk." fi # ── Done ───────────────────────────────────────────────────────────────────── echo green "=== Montauk SDK ready ===" bold "Staged trees:" bold " ${NATIVE_BINUTILS}/sdk (as, ld, ar, nm, objdump, ...)" bold " ${NATIVE_GCC}/sdk (gcc, g++, cpp, cc1, cc1plus, collect2)" bold "The next 'make' ships them into the OS image at 0:/sdk (devkit target)."