diff --git a/Makefile b/Makefile index e1ceb59ca3..b96a03aec4 100644 --- a/Makefile +++ b/Makefile @@ -20,11 +20,13 @@ LIBTIRPC_STAMP := $(APPS_BUILD)/.stamp_libtirpc GNULIB_STAMP := $(APPS_BUILD)/.stamp_gnulib ZLIB_STAMP := $(APPS_BUILD)/.stamp_zlib OPENSSL_STAMP := $(APPS_BUILD)/.stamp_openssl +LIBCXX_STAMP := $(APPS_BUILD)/.stamp_libcxx MERGE_BASE_STAMP := $(APPS_BUILD)/.stamp_merge_base_sysroot MERGE_TIRPC_STAMP := $(APPS_BUILD)/.stamp_merge_tirpc MERGE_GNULIB_STAMP := $(APPS_BUILD)/.stamp_merge_gnulib MERGE_ZLIB_STAMP := $(APPS_BUILD)/.stamp_merge_zlib MERGE_OPENSSL_STAMP := $(APPS_BUILD)/.stamp_merge_openssl +MERGE_LIBCXX_STAMP := $(APPS_BUILD)/.stamp_merge_libcxx MERGE_ALL_STAMP := $(APPS_BUILD)/.stamp_merge_sysroot TOOL_ENV := $(APPS_BUILD)/.toolchain.env @@ -41,7 +43,7 @@ TESTABLE_APPS := bash coreutils curl git grep lmbench sed tinycc APP ?= $(TESTABLE_APPS) # -------- Phonies ------------------------------------------------------------- -.PHONY: all preflight dirs print-config check-build libtirpc gnulib zlib openssl merge-base-sysroot merge-sysroot lmbench bash nginx coreutils cpython git curl grep sed postgres clean clean-all rebuild-libs rebuild-sysroot install-bash install-nginx install-git install-curl install-grep install-sed install-lmbench install-coreutils install +.PHONY: all preflight dirs print-config check-build libtirpc gnulib zlib openssl libcxx merge-base-sysroot merge-sysroot lmbench bash nginx coreutils cpython git curl grep sed gcc binutils postgres clean clean-all rebuild-libs rebuild-sysroot install-bash install-nginx install-git install-curl install-grep install-sed install-lmbench install-coreutils install-gcc install-binutils install all: preflight libtirpc gnulib merge-sysroot lmbench bash @@ -144,6 +146,14 @@ $(OPENSSL_STAMP): $(APPS_ROOT)/openssl/compile_openssl.sh | $(TOOL_ENV) openssl: $(OPENSSL_STAMP) +# ---------------- libc++ (via compile_libcxx.sh) ------------------------------ +$(LIBCXX_STAMP): $(APPS_ROOT)/llvm-project/compile_libcxx.sh | $(TOOL_ENV) + . '$(TOOL_ENV)' + JOBS='$(JOBS)' '$(APPS_ROOT)/llvm-project/compile_libcxx.sh' + touch '$@' + +libcxx: $(LIBCXX_STAMP) + # ---------------- Merge sysroot + overlay ------------------------------------- $(MERGE_BASE_STAMP): | $(TOOL_ENV) @echo "[merge] refreshing base merged sysroot" @@ -194,7 +204,16 @@ $(MERGE_OPENSSL_STAMP): $(MERGE_BASE_STAMP) $(OPENSSL_STAMP) touch '$@' -$(MERGE_ALL_STAMP): $(MERGE_TIRPC_STAMP) $(MERGE_GNULIB_STAMP) $(MERGE_ZLIB_STAMP) $(MERGE_OPENSSL_STAMP) +$(MERGE_LIBCXX_STAMP): $(MERGE_BASE_STAMP) $(LIBCXX_STAMP) + # libc++ headers (into include/wasm32-wasi/c++/ so clang's -isystem finds them) + mkdir -p '$(MERGED_SYSROOT)/include/wasm32-wasi/c++' + rsync -a '$(APPS_OVERLAY)/usr/include/c++/' '$(MERGED_SYSROOT)/include/wasm32-wasi/c++/' || true + rsync -a '$(APPS_OVERLAY)/usr/lib/wasm32-wasi/' '$(MERGED_SYSROOT)/lib/wasm32-wasi/' || true + rsync -a '$(APPS_OVERLAY)/lib/wasm32-wasi/' '$(MERGED_SYSROOT)/lib/wasm32-wasi/' || true + touch '$@' + + +$(MERGE_ALL_STAMP): $(MERGE_TIRPC_STAMP) $(MERGE_GNULIB_STAMP) $(MERGE_ZLIB_STAMP) $(MERGE_OPENSSL_STAMP) $(MERGE_LIBCXX_STAMP) touch '$@' merge-sysroot: $(MERGE_ALL_STAMP) @@ -259,12 +278,27 @@ sed: $(MERGE_BASE_STAMP) . '$(TOOL_ENV)' JOBS='$(JOBS)' '$(APPS_ROOT)/sed/compile_sed.sh' +# ---------------- gcc (WASM build) -------------------------------------------- +# Uses gcc/compile_gcc.sh to cross-compile GCC cc1 as a wasm32-wasi binary. +# Requires libc++ in the merged sysroot (for compiling GCC's C++ source). +# Stages artifacts under build/gcc/usr/local/bin. +gcc: $(MERGE_LIBCXX_STAMP) + . '$(TOOL_ENV)' + JOBS='$(JOBS)' '$(APPS_ROOT)/gcc/compile_gcc.sh' + +# ---------------- binutils (WASM build) ---------------------------------------- +# Uses binutils/compile_binutils.sh to cross-compile ld and as as wasm32-wasi +# binaries. Pure C — no libc++ needed. Stages to build/binutils/usr/local/bin. +binutils: $(MERGE_ZLIB_STAMP) + . '$(TOOL_ENV)' + JOBS='$(JOBS)' '$(APPS_ROOT)/binutils/compile_binutils.sh' + rebuild-libs: - rm -f '$(LIBTIRPC_STAMP)' '$(GNULIB_STAMP)' '$(ZLIB_STAMP)' '$(OPENSSL_STAMP)' \ - '$(MERGE_TIRPC_STAMP)' '$(MERGE_GNULIB_STAMP)' '$(MERGE_ZLIB_STAMP)' '$(MERGE_OPENSSL_STAMP)' '$(MERGE_ALL_STAMP)' + rm -f '$(LIBTIRPC_STAMP)' '$(GNULIB_STAMP)' '$(ZLIB_STAMP)' '$(OPENSSL_STAMP)' '$(LIBCXX_STAMP)' \ + '$(MERGE_TIRPC_STAMP)' '$(MERGE_GNULIB_STAMP)' '$(MERGE_ZLIB_STAMP)' '$(MERGE_OPENSSL_STAMP)' '$(MERGE_LIBCXX_STAMP)' '$(MERGE_ALL_STAMP)' rebuild-sysroot: - rm -f '$(MERGE_BASE_STAMP)' '$(MERGE_TIRPC_STAMP)' '$(MERGE_GNULIB_STAMP)' '$(MERGE_ZLIB_STAMP)' '$(MERGE_OPENSSL_STAMP)' '$(MERGE_ALL_STAMP)' + rm -f '$(MERGE_BASE_STAMP)' '$(MERGE_TIRPC_STAMP)' '$(MERGE_GNULIB_STAMP)' '$(MERGE_ZLIB_STAMP)' '$(MERGE_OPENSSL_STAMP)' '$(MERGE_LIBCXX_STAMP)' '$(MERGE_ALL_STAMP)' # ---------------- cpython (WASM build) ---------------------------------------- # Placeholder target to preserve the per-app staging/layering pattern. @@ -300,7 +334,13 @@ install-lmbench: install-coreutils: '$(APPS_ROOT)/scripts/post_install.sh' '$(LINDFS_ROOT)' '$(APPS_BUILD)' coreutils -install: install-bash install-nginx install-git install-curl install-grep install-sed install-lmbench install-coreutils +install-gcc: + '$(APPS_ROOT)/scripts/post_install.sh' '$(LINDFS_ROOT)' '$(APPS_BUILD)' gcc + +install-binutils: + '$(APPS_ROOT)/scripts/post_install.sh' '$(LINDFS_ROOT)' '$(APPS_BUILD)' binutils + +install: install-bash install-nginx install-git install-curl install-grep install-sed install-lmbench install-coreutils install-gcc install-binutils clean: $(MAKE) -C '$(APPS_ROOT)/lmbench/src' clean || true @@ -309,6 +349,9 @@ clean: -rm -rf '$(APPS_BIN_DIR)/nginx' -$(MAKE) -C '$(APPS_ROOT)/nginx' clean || true -rm -rf '$(APPS_OVERLAY)' '$(MERGED_SYSROOT)' '$(APPS_BIN_DIR)' '$(APPS_LIB_DIR)' '$(TOOL_ENV)' - -rm -f '$(LIBTIRPC_STAMP)' '$(GNULIB_STAMP)' '$(ZLIB_STAMP)' '$(OPENSSL_STAMP)' - -rm -f '$(MERGE_BASE_STAMP)' '$(MERGE_TIRPC_STAMP)' '$(MERGE_GNULIB_STAMP)' '$(MERGE_ZLIB_STAMP)' '$(MERGE_OPENSSL_STAMP)' '$(MERGE_ALL_STAMP)' + '$(APPS_ROOT)/gcc/clean.sh' + '$(APPS_ROOT)/binutils/clean.sh' + '$(APPS_ROOT)/llvm-project/clean.sh' + -rm -f '$(LIBTIRPC_STAMP)' '$(GNULIB_STAMP)' '$(ZLIB_STAMP)' '$(OPENSSL_STAMP)' '$(LIBCXX_STAMP)' + -rm -f '$(MERGE_BASE_STAMP)' '$(MERGE_TIRPC_STAMP)' '$(MERGE_GNULIB_STAMP)' '$(MERGE_ZLIB_STAMP)' '$(MERGE_OPENSSL_STAMP)' '$(MERGE_LIBCXX_STAMP)' '$(MERGE_ALL_STAMP)' $(MAKE) -C '$(APPS_ROOT)/libtirpc' distclean || true diff --git a/binutils/clean.sh b/binutils/clean.sh new file mode 100755 index 0000000000..af4e361610 --- /dev/null +++ b/binutils/clean.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +APPS_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +APPS_BUILD="$APPS_ROOT/build" + +rm -rf "$APPS_BUILD/binutils-build" +rm -rf "$APPS_BUILD/binutils" +rm -f "$SCRIPT_DIR/ld.wasm" "$SCRIPT_DIR/ld.opt.wasm" "$SCRIPT_DIR/ld.opt.cwasm" +rm -f "$SCRIPT_DIR/as.wasm" "$SCRIPT_DIR/as.opt.wasm" "$SCRIPT_DIR/as.opt.cwasm" diff --git a/binutils/compile_binutils.sh b/binutils/compile_binutils.sh new file mode 100755 index 0000000000..984d9d1477 --- /dev/null +++ b/binutils/compile_binutils.sh @@ -0,0 +1,224 @@ +#!/usr/bin/env bash +set -euo pipefail + +############################################################################### +# Binutils WASI build helper for lind-wasm-apps +# +# Cross-compiles GNU Binutils 2.46.0 (ld, as) to wasm32-wasi so that the +# linker and assembler can run inside the Lind sandbox alongside cc1 from GCC. +# The resulting tools target x86_64-linux-gnu (matching GCC's --target). +# +# High-level strategy: +# 1. Out-of-tree build +# 2. Configure with --host=wasm32-unknown-wasi, --target=x86_64-linux-gnu +# Generator tools are built natively via CC_FOR_BUILD; ld/as are cross- +# compiled to wasm32 via CC. +# 3. Build with 'make all-ld all-gas' (linker + assembler only) +# 4. Stage ld and as, post-process with wasm-opt + lind-boot +# +# Prerequisites: +# - Run 'make preflight merge-sysroot' first +# - Native gcc must be on PATH (for CC_FOR_BUILD) +############################################################################### + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +APPS_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +BINUTILS_SRC="$APPS_ROOT/binutils" + +APPS_BUILD="$APPS_ROOT/build" +MERGED_SYSROOT="$APPS_BUILD/sysroot_merged" +STAGE_DIR="$APPS_BUILD/binutils/usr/local/bin" +TOOL_ENV="$APPS_BUILD/.toolchain.env" + +if [[ -z "${LIND_WASM_ROOT:-}" ]]; then + LIND_WASM_ROOT="$(cd "$APPS_ROOT/.." && pwd)" +fi + +WASM_OPT="${WASM_OPT:-$LIND_WASM_ROOT/tools/binaryen/bin/wasm-opt}" +LIND_BOOT="${LIND_BOOT:-$LIND_WASM_ROOT/build/lind-boot}" + +JOBS="${JOBS:-$(nproc 2>/dev/null || getconf _NPROCESSORS_ONLN || echo 4)}" + +# ---------------------------------------------------------------------- +# 1) Load toolchain from Makefile preflight +# ---------------------------------------------------------------------- +if [[ -r "$TOOL_ENV" ]]; then + # shellcheck disable=SC1090 + . "$TOOL_ENV" +else + echo "[binutils] ERROR: missing toolchain env '$TOOL_ENV' (run 'make preflight' first)" >&2 + exit 1 +fi + +: "${CLANG:?missing CLANG in $TOOL_ENV}" +: "${AR:?missing AR in $TOOL_ENV}" +: "${RANLIB:?missing RANLIB in $TOOL_ENV}" +: "${NM:?missing NM in $TOOL_ENV}" + +# Sanity checks +if [[ ! -d "$BINUTILS_SRC" ]]; then + echo "[binutils] ERROR: source dir not found at '$BINUTILS_SRC'" >&2 + exit 1 +fi +if [[ ! -d "$MERGED_SYSROOT" ]]; then + echo "[binutils] ERROR: merged sysroot '$MERGED_SYSROOT' not found. Run 'make merge-sysroot' first." >&2 + exit 1 +fi +if ! command -v gcc &>/dev/null; then + echo "[binutils] ERROR: native gcc required for CC_FOR_BUILD but not found on PATH" >&2 + exit 1 +fi + +mkdir -p "$STAGE_DIR" + +# ---------------------------------------------------------------------- +# 2) WASM toolchain flags +# ---------------------------------------------------------------------- +CC_WASM="$CLANG --target=wasm32-unknown-wasi --sysroot=$MERGED_SYSROOT \ + -pthread -matomics -mbulk-memory \ + -I$MERGED_SYSROOT/include -I$MERGED_SYSROOT/include/wasm32-wasi" + +CFLAGS_WASM="-Os" + +LDFLAGS_WASM="-Wl,--import-memory,--export-memory,--max-memory=67108864 \ + -Wl,--export=__stack_pointer,--export=__stack_low \ + -L$MERGED_SYSROOT/lib/wasm32-wasi \ + -L$MERGED_SYSROOT/usr/lib/wasm32-wasi" + +echo "[binutils] using CLANG = $CLANG" +echo "[binutils] using AR = $AR" +echo "[binutils] LIND_WASM_ROOT = $LIND_WASM_ROOT" +echo "[binutils] merged sysroot = $MERGED_SYSROOT" +echo "[binutils] stage dir = $STAGE_DIR" +echo "[binutils] CC_WASM = $CC_WASM" +echo + +# ---------------------------------------------------------------------- +# 3) Out-of-tree build directory +# ---------------------------------------------------------------------- +BINUTILS_BUILD="$APPS_BUILD/binutils-build" +mkdir -p "$BINUTILS_BUILD" + +echo "[binutils] build dir = $BINUTILS_BUILD" + +# ---------------------------------------------------------------------- +# 4) Configure +# ---------------------------------------------------------------------- +BUILD_TRIPLET="$(gcc -dumpmachine 2>/dev/null || echo x86_64-linux-gnu)" + +echo "[binutils] configuring…" +echo "[binutils] --build=$BUILD_TRIPLET" +echo "[binutils] --host=wasm32-unknown-wasi" +echo "[binutils] --target=x86_64-linux-gnu" + +pushd "$BINUTILS_BUILD" >/dev/null + +"$BINUTILS_SRC/configure" \ + --build="$BUILD_TRIPLET" \ + --host=wasm32-unknown-wasi \ + --target=x86_64-linux-gnu \ + --disable-shared \ + --enable-static \ + --disable-nls \ + --disable-plugins \ + --disable-gdb \ + --disable-gdbserver \ + --disable-gprofng \ + --disable-sim \ + --disable-gold \ + --enable-ld=yes \ + --disable-werror \ + --disable-largefile \ + --without-zstd \ + --with-system-zlib \ + CC_FOR_BUILD=gcc \ + AR_FOR_BUILD=ar \ + CFLAGS_FOR_BUILD="-O2 -g" \ + LDFLAGS_FOR_BUILD="" \ + CC="$CC_WASM" \ + AR="$AR" \ + NM="$NM" \ + RANLIB="$RANLIB" \ + CFLAGS="$CFLAGS_WASM" \ + LDFLAGS="$LDFLAGS_WASM" + +if [[ ! -f Makefile ]]; then + echo "[binutils] ERROR: configure failed to produce Makefile." >&2 + exit 1 +fi + +# ---------------------------------------------------------------------- +# 5) Build ld and as +# ---------------------------------------------------------------------- +echo "[binutils] building (make all-ld all-gas)…" +make all-ld all-gas -j"$JOBS" V=1 MAKEINFO=true + +popd >/dev/null + +# ---------------------------------------------------------------------- +# 6) Post-process helper +# ---------------------------------------------------------------------- +post_process_binary() { + local NAME="$1" + local SRC_BIN="$2" + + if [[ ! -f "$SRC_BIN" ]]; then + echo "[binutils] ERROR: $NAME binary not produced at '$SRC_BIN'" >&2 + return 1 + fi + + local WASM_FILE="$SCRIPT_DIR/${NAME}.wasm" + local OPT_WASM="$SCRIPT_DIR/${NAME}.opt.wasm" + cp "$SRC_BIN" "$WASM_FILE" + echo "[binutils] $NAME binary size: $(du -h "$WASM_FILE" | cut -f1)" + + # --- wasm-opt --- + if [[ -x "$WASM_OPT" ]]; then + echo "[binutils] running wasm-opt on $NAME (epoch-injection + asyncify + O2)…" + "$WASM_OPT" --epoch-injection --asyncify \ + --debuginfo -O2 \ + "$WASM_FILE" -o "$OPT_WASM" + else + echo "[binutils] ERROR: wasm-opt not found at '$WASM_OPT'; exiting." >&2 + exit 1 + fi + + if [[ ! -f "$OPT_WASM" ]]; then + echo "[binutils] ERROR: failed to generate '$OPT_WASM'; exiting." >&2 + exit 1 + fi + + # --- lind-boot --precompile --- + if [[ ! -x "$LIND_BOOT" ]]; then + echo "[binutils] ERROR: lind-boot not found at '$LIND_BOOT'" >&2 + exit 1 + fi + + echo "[binutils] generating cwasm for $NAME via lind-boot --precompile…" + "$LIND_BOOT" --precompile "$OPT_WASM" + + local OPT_CWASM="$SCRIPT_DIR/${NAME}.opt.cwasm" + if [[ ! -f "$OPT_CWASM" ]]; then + echo "[binutils] ERROR: precompile produced no .cwasm for $NAME" >&2 + exit 1 + fi + + cp "$OPT_CWASM" "$STAGE_DIR/$NAME" + echo "[binutils] $NAME staged as $STAGE_DIR/$NAME (precompiled)" +} + +# ---------------------------------------------------------------------- +# 7) Stage ld and as +# ---------------------------------------------------------------------- +LD_BIN="$BINUTILS_BUILD/ld/ld-new" +AS_BIN="$BINUTILS_BUILD/gas/as-new" + +post_process_binary "ld" "$LD_BIN" +post_process_binary "as" "$AS_BIN" + +popd >/dev/null 2>&1 || true + +echo +echo "[binutils] build complete. Outputs under:" +echo " $STAGE_DIR" +ls -lh "$STAGE_DIR" || true diff --git a/gcc/clean.sh b/gcc/clean.sh new file mode 100755 index 0000000000..b9ad097204 --- /dev/null +++ b/gcc/clean.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +APPS_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +APPS_BUILD="$APPS_ROOT/build" + +rm -rf "$APPS_BUILD/gcc-build" +rm -rf "$APPS_BUILD/gcc" +rm -f "$SCRIPT_DIR/cc1.wasm" "$SCRIPT_DIR/cc1.opt.wasm" "$SCRIPT_DIR/cc1.opt.cwasm" diff --git a/gcc/compile_gcc.sh b/gcc/compile_gcc.sh new file mode 100755 index 0000000000..873e1739db --- /dev/null +++ b/gcc/compile_gcc.sh @@ -0,0 +1,411 @@ +#!/usr/bin/env bash +set -euo pipefail + +############################################################################### +# GCC WASI build helper for lind-wasm-apps +# +# Cross-compiles GCC 15.2.0 (C language only) to wasm32-wasi so that cc1 can +# run inside the Lind sandbox. The resulting compiler targets x86_64-linux-gnu +# (GCC has no wasm32 backend). +# +# High-level strategy: +# 1. Download GCC prerequisites (GMP, MPFR, MPC) into the source tree +# 2. Out-of-tree build (GCC requires this) +# 3. Configure with --host=wasm32-unknown-wasi, --target=x86_64-linux-gnu +# Generator tools are built natively via CC_FOR_BUILD; cc1 is cross- +# compiled to wasm32 via CC/CXX. +# 4. Build with 'make all-gcc' (compiler only, no target libraries) +# 5. Stage cc1, post-process with wasm-opt + lind-boot +# +# Prerequisites: +# - Run 'make preflight' and ensure libc++ is in the merged sysroot +# (run 'make libcxx merge-sysroot' or let the Makefile handle it) +# - Native gcc/g++ must be on PATH (for CC_FOR_BUILD / CXX_FOR_BUILD) +############################################################################### + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +APPS_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +GCC_SRC="$APPS_ROOT/gcc" + +APPS_BUILD="$APPS_ROOT/build" +MERGED_SYSROOT="$APPS_BUILD/sysroot_merged" +STAGE_DIR="$APPS_BUILD/gcc/usr/local/bin" +TOOL_ENV="$APPS_BUILD/.toolchain.env" + +if [[ -z "${LIND_WASM_ROOT:-}" ]]; then + LIND_WASM_ROOT="$(cd "$APPS_ROOT/.." && pwd)" +fi + +WASM_OPT="${WASM_OPT:-$LIND_WASM_ROOT/tools/binaryen/bin/wasm-opt}" +LIND_BOOT="${LIND_BOOT:-$LIND_WASM_ROOT/build/lind-boot}" + +JOBS="${JOBS:-$(nproc 2>/dev/null || getconf _NPROCESSORS_ONLN || echo 4)}" + +# ---------------------------------------------------------------------- +# 1) Load toolchain from Makefile preflight +# ---------------------------------------------------------------------- +if [[ -r "$TOOL_ENV" ]]; then + # shellcheck disable=SC1090 + . "$TOOL_ENV" +else + echo "[gcc] ERROR: missing toolchain env '$TOOL_ENV' (run 'make preflight' first)" >&2 + exit 1 +fi + +: "${CLANG:?missing CLANG in $TOOL_ENV}" +: "${AR:?missing AR in $TOOL_ENV}" +: "${RANLIB:?missing RANLIB in $TOOL_ENV}" +: "${NM:?missing NM in $TOOL_ENV}" + +LLVM_BIN_DIR="$(dirname "$CLANG")" +CLANGXX="$LLVM_BIN_DIR/clang++" +if [[ ! -x "$CLANGXX" ]]; then + echo "[gcc] WARN: clang++ not found; creating symlink to clang" + ln -sf "$CLANG" "$CLANGXX" +fi + +# Sanity checks +if [[ ! -d "$GCC_SRC" ]]; then + echo "[gcc] ERROR: GCC source dir not found at '$GCC_SRC'" >&2 + exit 1 +fi +if [[ ! -d "$MERGED_SYSROOT" ]]; then + echo "[gcc] ERROR: merged sysroot '$MERGED_SYSROOT' not found. Run 'make merge-sysroot' first." >&2 + exit 1 +fi +# libc++ must be in the sysroot for C++ compilation +if [[ ! -f "$MERGED_SYSROOT/lib/wasm32-wasi/libc++.a" ]]; then + echo "[gcc] ERROR: libc++.a not found in merged sysroot. Run 'make libcxx merge-sysroot' first." >&2 + exit 1 +fi +# Need native gcc/g++ for building generator tools +if ! command -v gcc &>/dev/null || ! command -v g++ &>/dev/null; then + echo "[gcc] ERROR: native gcc/g++ required for CC_FOR_BUILD but not found on PATH" >&2 + exit 1 +fi + +mkdir -p "$STAGE_DIR" + +# ---------------------------------------------------------------------- +# 2) WASM toolchain flags +# ---------------------------------------------------------------------- +LIBCXX_INCLUDE="$MERGED_SYSROOT/include/wasm32-wasi/c++/v1" + +# GCC's build system passes CFLAGS/CXXFLAGS to BOTH the cross-compiler (CC) +# and the native build compiler (CC_FOR_BUILD). ALL wasm-specific flags — +# target, sysroot, include paths, -matomics, -mbulk-memory, libc++ — MUST +# live in CC/CXX so that native g++ never sees them. +CC_WASM="$CLANG --target=wasm32-unknown-wasi --sysroot=$MERGED_SYSROOT \ + -pthread -matomics -mbulk-memory \ + -I$MERGED_SYSROOT/include -I$MERGED_SYSROOT/include/wasm32-wasi" + +CXX_WASM="$CLANGXX --target=wasm32-unknown-wasi --sysroot=$MERGED_SYSROOT \ + -pthread -matomics -mbulk-memory \ + -stdlib=libc++ -isystem $LIBCXX_INCLUDE -fno-exceptions \ + -I$MERGED_SYSROOT/include -I$MERGED_SYSROOT/include/wasm32-wasi" + +# CFLAGS/CXXFLAGS must contain ONLY portable flags that native g++ also +# understands — no paths, no wasm flags. +# Use -Os to minimize binary size — cc1 at -O2 is ~183MB which causes +# wasm-opt --asyncify to OOM in Docker (no swap available). +CFLAGS_WASM="-Os" +CXXFLAGS_WASM="-Os" + +LDFLAGS_WASM="-Wl,--import-memory,--export-memory,--max-memory=67108864 \ + -Wl,--export=__stack_pointer,--export=__stack_low,--export=__tls_base \ + -L$MERGED_SYSROOT/lib/wasm32-wasi \ + -L$MERGED_SYSROOT/usr/lib/wasm32-wasi \ + -lc++ -lc++abi" + +echo "[gcc] using CLANG = $CLANG" +echo "[gcc] using CLANGXX = $CLANGXX" +echo "[gcc] using AR = $AR" +echo "[gcc] LIND_WASM_ROOT = $LIND_WASM_ROOT" +echo "[gcc] merged sysroot = $MERGED_SYSROOT" +echo "[gcc] libc++ headers = $LIBCXX_INCLUDE" +echo "[gcc] stage dir = $STAGE_DIR" +echo "[gcc] CC_WASM = $CC_WASM" +echo + +# ---------------------------------------------------------------------- +# 3) Download GCC prerequisites (GMP, MPFR, MPC) if not already present +# ---------------------------------------------------------------------- +pushd "$GCC_SRC" >/dev/null + +if [[ ! -d gmp ]] || [[ ! -d mpfr ]] || [[ ! -d mpc ]]; then + echo "[gcc] downloading prerequisites (GMP, MPFR, MPC)…" + ./contrib/download_prerequisites --no-isl --no-verify +fi + +# GMP/MPFR/MPC ship their own config.sub which is too old to know about +# wasm32-wasi. Overwrite with GCC's version which does. +echo "[gcc] patching config.sub in prerequisites…" +for dir in gmp mpfr mpc; do + if [[ -f "$dir/config.sub" ]]; then + cp -f config.sub "$dir/config.sub" + echo "[gcc] updated $dir/config.sub" + fi + if [[ -f "$dir/configfsf.sub" ]]; then + cp -f config.sub "$dir/configfsf.sub" + echo "[gcc] updated $dir/configfsf.sub" + fi +done + +# Patch MPFR's configure to disable float128. +# MPFR detects __float128 (clang accepts it), then adds -D_Float128=__float128 +# which conflicts with the WASI sysroot's "typedef __float128 _Float128;" +# in bits/floatn.h. MPFR's configure runs during 'make all-gcc', so we +# patch the source-level configure script directly. +MPFR_CONFIGURE="$GCC_SRC/mpfr/configure" +if [[ -f "$MPFR_CONFIGURE" ]]; then + if ! grep -q 'PATCHED_FOR_WASI' "$MPFR_CONFIGURE"; then + echo "[gcc] [patch] disabling float128 in MPFR configure…" + # Insert enable_float128=no right after the shebang line + sed -i '1 a\enable_float128=no # PATCHED_FOR_WASI' "$MPFR_CONFIGURE" + echo "[gcc] [patch] verify:" + head -3 "$MPFR_CONFIGURE" + else + echo "[gcc] MPFR configure already patched for WASI." + fi +else + echo "[gcc] WARN: MPFR configure not found at $MPFR_CONFIGURE" +fi + +# Also guard the sysroot's bits/floatn.h so the typedef doesn't conflict +# when _Float128 is pre-defined as a macro (by MPFR or anything else). +FLOATN_H="$MERGED_SYSROOT/include/wasm32-wasi/bits/floatn.h" +if [[ -f "$FLOATN_H" ]] && ! grep -q 'PATCHED_FOR_WASI' "$FLOATN_H"; then + echo "[gcc] [patch] guarding _Float128 typedef in sysroot floatn.h…" + sed -i 's|^typedef __float128 _Float128;|/* PATCHED_FOR_WASI */\n#ifndef _Float128\ntypedef __float128 _Float128;\n#endif|' "$FLOATN_H" +fi + +popd >/dev/null + +# ---------------------------------------------------------------------- +# 4) Out-of-tree build directory +# ---------------------------------------------------------------------- +GCC_BUILD="$APPS_BUILD/gcc-build" +mkdir -p "$GCC_BUILD" + +echo "[gcc] build dir = $GCC_BUILD" + +# ---------------------------------------------------------------------- +# 4b) Create config.site to override broken sub-configure detections +# ---------------------------------------------------------------------- +# This lives here (not in a separate MPFR step) because GCC builds MPFR +# in-tree as part of its own configure/make. CONFIG_SITE is inherited by +# all sub-configures, so setting it once in the top-level build directory +# is the correct way to inject overrides into MPFR's autoconf. +# +# MPFR's configure detects __float128 support, then adds -D_Float128=__float128. +# But the WASI sysroot already has "typedef __float128 _Float128;" in +# bits/floatn.h, so the macro turns it into "typedef __float128 __float128;" +# which is invalid. Disable float128 in MPFR via configure cache. +GCC_CONFIG_SITE="$GCC_BUILD/config.site" +cat > "$GCC_CONFIG_SITE" << 'EOF' +# Overrides for wasm32-wasi cross-compilation +mpfr_cv_want_float128=no +EOF +export CONFIG_SITE="$GCC_CONFIG_SITE" +echo "[gcc] created config.site: $GCC_CONFIG_SITE" + +# ---------------------------------------------------------------------- +# 5) Configure GCC +# ---------------------------------------------------------------------- +BUILD_TRIPLET="$(gcc -dumpmachine 2>/dev/null || echo x86_64-linux-gnu)" + +echo "[gcc] configuring…" +echo "[gcc] --build=$BUILD_TRIPLET" +echo "[gcc] --host=wasm32-unknown-wasi" +echo "[gcc] --target=x86_64-linux-gnu" + +pushd "$GCC_BUILD" >/dev/null + +"$GCC_SRC/configure" \ + --build="$BUILD_TRIPLET" \ + --host=wasm32-unknown-wasi \ + --target=x86_64-linux-gnu \ + --disable-bootstrap \ + --enable-languages=c \ + --disable-shared \ + --enable-static \ + --disable-threads \ + --disable-multilib \ + --disable-plugin \ + --disable-nls \ + --disable-libgcc \ + --disable-libssp \ + --disable-libgomp \ + --disable-libatomic \ + --disable-libquadmath \ + --disable-libvtv \ + --disable-libitm \ + --disable-libsanitizer \ + --disable-libstdc++-v3 \ + --disable-libffi \ + --disable-decimal-float \ + --disable-lto \ + --disable-gcov \ + --enable-checking=release \ + --without-headers \ + --without-isl \ + --with-gnu-as \ + --with-gnu-ld \ + CC_FOR_BUILD=gcc \ + CXX_FOR_BUILD=g++ \ + AR_FOR_BUILD=ar \ + CFLAGS_FOR_BUILD="-O2 -g" \ + CXXFLAGS_FOR_BUILD="-O2 -g" \ + LDFLAGS_FOR_BUILD="" \ + CC="$CC_WASM" \ + CXX="$CXX_WASM" \ + AR="$AR" \ + NM="$NM" \ + RANLIB="$RANLIB" \ + CFLAGS="$CFLAGS_WASM" \ + CXXFLAGS="$CXXFLAGS_WASM" \ + LDFLAGS="$LDFLAGS_WASM" + +if [[ ! -f Makefile ]]; then + echo "[gcc] ERROR: configure failed to produce Makefile." >&2 + exit 1 +fi + +# ---------------------------------------------------------------------- +# 6) Build (compiler only — no target libraries) +# ---------------------------------------------------------------------- +echo "[gcc] building (make all-gcc)…" +make all-gcc -j"$JOBS" V=1 + +popd >/dev/null + +# ---------------------------------------------------------------------- +# 7) Stage cc1 binary +# ---------------------------------------------------------------------- +CC1_BIN="$GCC_BUILD/gcc/cc1" +if [[ ! -f "$CC1_BIN" ]]; then + echo "[gcc] ERROR: cc1 binary not produced at '$CC1_BIN'" >&2 + exit 1 +fi + +CC1_WASM="$SCRIPT_DIR/cc1.wasm" +CC1_OPT_WASM="$SCRIPT_DIR/cc1.opt.wasm" +cp "$CC1_BIN" "$CC1_WASM" + +echo "[gcc] cc1 binary size: $(du -h "$CC1_WASM" | cut -f1)" + +# ---------------------------------------------------------------------- +# 8) wasm-opt +# ---------------------------------------------------------------------- +if [[ -x "$WASM_OPT" ]]; then + # Build an asyncify ignore list for functions that are too large to + # instrument. Asyncify inflates auto-generated pattern matchers and + # template instantiations by 1000x+, causing cranelift's u32 DFG index + # to overflow during AOT precompilation. These are all pure computation + # (no I/O or yield points) so skipping is safe. + # + # This is a permanent part of the build, not a temporary workaround — + # these auto-generated functions will always be too large for asyncify + # and will never contain yield points (they are pure tree/RTL rewrites). + # + # gimple_simplify_* — match.pd GIMPLE simplifiers + # generic_simplify_* — match.pd GENERIC simplifiers + # gimple_bitwise_*, gimple_bit_*, gimple_power_* — match.pd exports + # tree_power_*, tree_bitwise_* — match.pd GENERIC exports + # types_match — match.pd helper + # def_fn_type — builtin type init (runs once) + # wi::* — wide-int template instantiations + # fold_* — tree constant folding + # recog*, extract_* — insn-recog.c / insn-extract.c + # output_NNN — insn-output.c emitters + # gen_* — insn-emit.c generated code + # simplify_* — RTL simplification + # combine_* — instruction combiner + # ix86_*, x86_* — x86 backend (huge switch tables) + # get_attr_*, internal_dfa* — insn-attrtab.c scheduling tables + # Binaryen's asyncify-removelist supports * wildcards, so we use a + # small static pattern list instead of enumerating all 17K+ names. + ASYNCIFY_IGNORE="$SCRIPT_DIR/asyncify_ignore.txt" + cat > "$ASYNCIFY_IGNORE" << 'PATTERNS' +gimple_simplify_* +generic_simplify_* +gimple_bitwise_* +gimple_bit_* +gimple_power_* +gimple_maybe_* +gimple_unsigned_integer_sat_* +gimple_signed_integer_sat_* +gimple_nop_convert* +gimple_with_* +tree_power_* +tree_bitwise_* +tree_bit_* +tree_maybe_* +tree_nop_convert* +tree_with_* +tree_unsigned_integer_sat_* +tree_signed_integer_sat_* +types_match +def_fn_type +wi::* +fold_* +recog* +simplify_* +combine_* +ix86_* +x86_* +output_* +gen_* +extract_* +get_attr_* +internal_dfa* +peephole2_* +PATTERNS + IGNORE_COUNT=$(wc -l < "$ASYNCIFY_IGNORE") + echo "[gcc] asyncify removelist: $IGNORE_COUNT wildcard patterns" + + # IMPORTANT: asyncify must run on cc1.wasm (which has the name section + # from wasm-ld) so that the removelist can match function names. + # Note: double @@ — first @ is pass-arg separator, second @ means + # "read from response file" (Binaryen convention). + echo "[gcc] running wasm-opt (epoch-injection + asyncify + strip + Os)…" + "$WASM_OPT" --epoch-injection --asyncify \ + --pass-arg=asyncify-removelist@@"$ASYNCIFY_IGNORE" \ + --strip-debug -Os \ + "$CC1_WASM" -o "$CC1_OPT_WASM" +else + echo "[gcc] ERROR: wasm-opt not found at '$WASM_OPT'; exiting." >&2 + exit 1 +fi + +if [[ ! -f "$CC1_OPT_WASM" ]]; then + echo "[gcc] ERROR: Failed to generate '$CC1_OPT_WASM'; exiting." >&2 + exit 1 +fi + +# ---------------------------------------------------------------------- +# 9) cwasm generation via lind-boot --precompile +# ---------------------------------------------------------------------- +if [[ ! -x "$LIND_BOOT" ]]; then + echo "[gcc] ERROR: lind-boot not found at '$LIND_BOOT'" + exit 1 +fi + +echo "[gcc] generating cwasm via lind-boot --precompile…" +"$LIND_BOOT" --precompile "$CC1_OPT_WASM" + +CC1_OPT_CWASM="$SCRIPT_DIR/cc1.opt.cwasm" +if [[ ! -f "$CC1_OPT_CWASM" ]]; then + echo "[gcc] ERROR: precompile produced no .cwasm" + exit 1 +fi + +cp "$CC1_OPT_CWASM" "$STAGE_DIR/cc1" +echo "[gcc] cc1 staged as $STAGE_DIR/cc1 (precompiled)" + +popd >/dev/null 2>&1 || true + +echo +echo "[gcc] build complete. Outputs under:" +echo " $STAGE_DIR" +ls -lh "$STAGE_DIR" || true diff --git a/llvm-project/Toolchain-WASI.cmake.in b/llvm-project/Toolchain-WASI.cmake.in new file mode 100644 index 0000000000..538efe9c87 --- /dev/null +++ b/llvm-project/Toolchain-WASI.cmake.in @@ -0,0 +1,25 @@ +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR wasm32) + +set(CMAKE_C_COMPILER "@CLANG@") +set(CMAKE_CXX_COMPILER "@CLANGXX@") +set(CMAKE_AR "@AR@") +set(CMAKE_NM "@NM@") +set(CMAKE_RANLIB "@RANLIB@") +set(CMAKE_SYSROOT "@BASE_SYSROOT@") + +set(CMAKE_C_COMPILER_TARGET wasm32-unknown-wasi) +set(CMAKE_CXX_COMPILER_TARGET wasm32-unknown-wasi) + +set(CMAKE_C_FLAGS_INIT "-pthread -matomics -mbulk-memory -static -nostdlib -nodefaultlibs -fno-exceptions -fno-unwind-tables") +set(CMAKE_CXX_FLAGS_INIT "-frtti -pthread -matomics -mbulk-memory -static -nostdlib -nodefaultlibs -fno-exceptions -stdlib=libc++ -fno-unwind-tables") +set(CMAKE_EXE_LINKER_FLAGS_INIT "-static -nostdlib -nodefaultlibs") + +set(CMAKE_SKIP_RPATH ON) + +set(LLVM_HOST_TRIPLE "wasm32-wasip1") +set(LLVM_DEFAULT_TARGET_TRIPLE "wasm32-wasip1") + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/llvm-project/clean.sh b/llvm-project/clean.sh new file mode 100755 index 0000000000..5c53bce77c --- /dev/null +++ b/llvm-project/clean.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +APPS_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +APPS_BUILD="$APPS_ROOT/build" + +rm -rf "$APPS_BUILD/libcxx-build" +rm -rf "$APPS_BUILD/libcxx-install" diff --git a/llvm-project/compile_libcxx.sh b/llvm-project/compile_libcxx.sh new file mode 100755 index 0000000000..46968352f4 --- /dev/null +++ b/llvm-project/compile_libcxx.sh @@ -0,0 +1,188 @@ +#!/usr/bin/env bash +set -euo pipefail + +############################################################################### +# libc++ / libc++abi WASI build helper for lind-wasm-apps +# +# Cross-compiles LLVM libc++ and libc++abi to wasm32-wasi using the toolchain +# detected by the top-level Makefile preflight target. Installs headers and +# static libraries to the sysroot overlay so merge-sysroot can pick them up. +# +# Based on the approach in Lind-Project/lind-wasm PR #976. +# +# Prerequisites: +# - Run 'make preflight' first +# - cmake >= 3.20 must be on PATH +############################################################################### + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +APPS_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +LLVM_SRC="$SCRIPT_DIR" + +APPS_BUILD="$APPS_ROOT/build" +APPS_OVERLAY="$APPS_BUILD/sysroot_overlay" +TOOL_ENV="$APPS_BUILD/.toolchain.env" + +if [[ -z "${LIND_WASM_ROOT:-}" ]]; then + LIND_WASM_ROOT="$(cd "$APPS_ROOT/.." && pwd)" +fi + +BASE_SYSROOT="${BASE_SYSROOT:-$LIND_WASM_ROOT/src/glibc/sysroot}" + +JOBS="${JOBS:-$(nproc 2>/dev/null || getconf _NPROCESSORS_ONLN || echo 4)}" + +# ---------------------------------------------------------------------- +# 1) Load toolchain from Makefile preflight +# ---------------------------------------------------------------------- +if [[ -r "$TOOL_ENV" ]]; then + # shellcheck disable=SC1090 + . "$TOOL_ENV" +else + echo "[libcxx] ERROR: missing toolchain env '$TOOL_ENV' (run 'make preflight' first)" >&2 + exit 1 +fi + +: "${CLANG:?missing CLANG in $TOOL_ENV}" +: "${AR:?missing AR in $TOOL_ENV}" +: "${RANLIB:?missing RANLIB in $TOOL_ENV}" +: "${NM:?missing NM in $TOOL_ENV}" + +LLVM_BIN_DIR="$(dirname "$CLANG")" +# clang++ is typically a symlink next to clang +CLANGXX="$LLVM_BIN_DIR/clang++" +if [[ ! -x "$CLANGXX" ]]; then + echo "[libcxx] WARN: clang++ not found at '$CLANGXX'; creating symlink to clang" + ln -sf "$CLANG" "$CLANGXX" +fi + +# Sanity checks +if [[ ! -d "$LLVM_SRC/libcxx" ]]; then + echo "[libcxx] ERROR: libc++ source not found at '$LLVM_SRC/libcxx'" >&2 + exit 1 +fi +if [[ ! -d "$LLVM_SRC/libcxxabi" ]]; then + echo "[libcxx] ERROR: libc++abi source not found at '$LLVM_SRC/libcxxabi'" >&2 + exit 1 +fi +if [[ ! -r "$BASE_SYSROOT/include/wasm32-wasi/stdio.h" ]]; then + echo "[libcxx] ERROR: base sysroot headers missing at '$BASE_SYSROOT'" >&2 + exit 1 +fi + +CMAKE="${CMAKE:-cmake}" +if ! command -v "$CMAKE" &>/dev/null; then + echo "[libcxx] ERROR: cmake not found on PATH" >&2 + exit 1 +fi + +BUILD_DIR="$APPS_BUILD/libcxx-build" +INSTALL_DIR="$APPS_BUILD/libcxx-install" + +echo "[libcxx] using CLANG = $CLANG" +echo "[libcxx] using CLANGXX = $CLANGXX" +echo "[libcxx] using AR = $AR" +echo "[libcxx] using NM = $NM" +echo "[libcxx] LIND_WASM_ROOT = $LIND_WASM_ROOT" +echo "[libcxx] base sysroot = $BASE_SYSROOT" +echo "[libcxx] build dir = $BUILD_DIR" +echo "[libcxx] install dir = $INSTALL_DIR" +echo + +# ---------------------------------------------------------------------- +# 2) Patch libc++ time_utils.h (reinterpret_cast fix for WASI timespec) +# See: Lind-Project/lind-wasm PR #976 +# ---------------------------------------------------------------------- +TIME_UTILS="$LLVM_SRC/libcxx/src/filesystem/time_utils.h" +if [[ -f "$TIME_UTILS" ]]; then + if grep -q 'reinterpret_cast' "$TIME_UTILS"; then + echo "[libcxx] [patch] time_utils.h already patched; skipping." + else + python3 - <<'PY' "$TIME_UTILS" +import pathlib, sys +p = pathlib.Path(sys.argv[1]) +s = p.read_text(errors="ignore") + +old = "return set_times_checked(&dest.tv_sec, &dest.tv_nsec, tp);" +new = "return set_times_checked(reinterpret_cast(&dest.tv_sec),\n reinterpret_cast(&dest.tv_nsec),\n tp);" + +if old in s: + p.write_text(s.replace(old, new)) + print(f"[libcxx] [patch] added reinterpret_cast fix to {p}") +else: + print(f"[libcxx] WARN: time_utils.h patch pattern not found in {p}", file=sys.stderr) +PY + fi +fi + +# ---------------------------------------------------------------------- +# 3) Generate CMake toolchain file for wasm32-wasi cross-compilation +# ---------------------------------------------------------------------- +mkdir -p "$BUILD_DIR" + +TOOLCHAIN_FILE="$BUILD_DIR/Toolchain-WASI.cmake" +sed -e "s|@CLANG@|$CLANG|g" \ + -e "s|@CLANGXX@|$CLANGXX|g" \ + -e "s|@AR@|$AR|g" \ + -e "s|@NM@|$NM|g" \ + -e "s|@RANLIB@|$RANLIB|g" \ + -e "s|@BASE_SYSROOT@|$BASE_SYSROOT|g" \ + "$SCRIPT_DIR/Toolchain-WASI.cmake.in" > "$TOOLCHAIN_FILE" + +echo "[libcxx] generated toolchain file: $TOOLCHAIN_FILE" + +# ---------------------------------------------------------------------- +# 4) Configure with CMake +# ---------------------------------------------------------------------- +echo "[libcxx] configuring…" + +"$CMAKE" -B "$BUILD_DIR" -S "$LLVM_SRC/runtimes" \ + -DCMAKE_TOOLCHAIN_FILE="$TOOLCHAIN_FILE" \ + -DLLVM_PATH="$LLVM_SRC/llvm" \ + -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi" \ + -DLIBCXX_ENABLE_SHARED=OFF \ + -DLIBCXX_ENABLE_STATIC=ON \ + -DLIBCXX_ENABLE_EXCEPTIONS=OFF \ + -DLIBCXX_ENABLE_RTTI=ON \ + -DLIBCXX_USE_COMPILER_RT=ON \ + -DLIBCXX_ENABLE_UNWIND_TABLES=OFF \ + -DLIBCXX_ENABLE_TIME_ZONE_DATABASE=OFF \ + -DLIBCXX_HAS_MUSL_LIBC=OFF \ + -DLIBCXXABI_ENABLE_SHARED=OFF \ + -DLIBCXXABI_ENABLE_STATIC=ON \ + -DLIBCXXABI_ENABLE_EXCEPTIONS=OFF \ + -DLIBCXXABI_ENABLE_RTTI=ON \ + -DLIBCXXABI_USE_LLVM_UNWINDER=OFF \ + -DLIBCXXABI_ENABLE_STATIC_UNWINDER=OFF \ + -DLIBCXXABI_ENABLE_UNWIND_TABLES=OFF \ + -DLIBCXXABI_USE_COMPILER_RT=ON \ + -DLIBCXXABI_LIBCXX_PATH="$LLVM_SRC/libcxx" \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX="$INSTALL_DIR" \ + -DCMAKE_CXX_COMPILER_WORKS=1 \ + -DCMAKE_C_COMPILER_WORKS=1 + +# ---------------------------------------------------------------------- +# 5) Build and install +# ---------------------------------------------------------------------- +echo "[libcxx] building…" +"$CMAKE" --build "$BUILD_DIR" --target install -j"$JOBS" + +# ---------------------------------------------------------------------- +# 6) Copy headers and libs to sysroot overlay +# ---------------------------------------------------------------------- +echo "[libcxx] installing to sysroot overlay…" + +# Headers: overlay/usr/include/c++/v1/ (merge step puts them at include/wasm32-wasi/c++/v1/) +mkdir -p "$APPS_OVERLAY/usr/include/c++" +cp -r "$INSTALL_DIR/include/c++/"* "$APPS_OVERLAY/usr/include/c++/" + +# Static libraries +mkdir -p "$APPS_OVERLAY/usr/lib/wasm32-wasi" +cp "$INSTALL_DIR/lib/libc++.a" "$APPS_OVERLAY/usr/lib/wasm32-wasi/" +cp "$INSTALL_DIR/lib/libc++abi.a" "$APPS_OVERLAY/usr/lib/wasm32-wasi/" + +echo +echo "[libcxx] build complete. Outputs:" +echo " headers: $APPS_OVERLAY/usr/include/c++/" +echo " libs: $APPS_OVERLAY/usr/lib/wasm32-wasi/" +ls -lh "$APPS_OVERLAY/usr/lib/wasm32-wasi/libc++"* || true