2# Build libflame as a WebAssembly static library using Emscripten.
3#
4# Usage: ./build-wasm.sh (single-threaded)
5# PTHREAD=1 ./build-wasm.sh (compile with -pthread so the library
6# can link into shared-memory/threaded wasm modules; installs as
7# libflame-mt.a alongside the single-threaded libflame.a)
8# Requires: emsdk (expected at ~/emsdk, or already on PATH)
9set -euo pipefail
11PTHREAD=${PTHREAD:-0}
12EXTRA_CFLAGS=""
13if [ "$PTHREAD" = "1" ]; then
14 EXTRA_CFLAGS=" -pthread"
15fi
17cd "$(dirname "$0")"
18ROOT=$(pwd)
19PREFIX=$ROOT/install
21if ! command -v emcc >/dev/null 2>&1; then
22 source ~/emsdk/emsdk_env.sh
23fi
25# 1. Clone
26if [ ! -d libflame ]; then
27 git clone --depth 1 https://github.com/flame/libflame
28fi
29cd libflame
31# 2. Patch: libflame declares the Fortran-style BLAS as returning void, but the
32# f2c'd built-in BLAS defines those routines returning int. Harmless on
33# native targets, but a fatal signature mismatch under wasm-ld (calls
34# through mismatched signatures fail wasm validation).
35sed -i 's/^void F77_/int F77_/' src/base/flamec/blis/include/blis_prototypes_blas.h
37# 3. Configure. Notes:
38# - No --host triple: the bundled config.sub predates wasm; emcc via CC is enough.
39# - Fortran autodetection must be off (Emscripten has no Fortran compiler).
40# - builtin-blas uses the f2c C translations, so the library is self-contained.
41# - lapack2flame + legacy-lapack adds a full LAPACK API (f2c C sources, no Fortran).
42emconfigure ./configure \
43 --prefix="$PREFIX" \
44 --disable-autodetect-f77-ldflags \
45 --disable-autodetect-f77-name-mangling \
46 --enable-builtin-blas \
47 --enable-lapack2flame \
48 --enable-legacy-lapack \
49 --disable-dynamic-build \
50 --enable-static-build \
51 --enable-vector-intrinsics=none \
52 CC=emcc AR=emar RANLIB=emranlib
54# 4. configure doesn't know optimization flags for the "emcc" vendor; add -O2.
55sed -i "s/^COPTFLAGS := *\$/COPTFLAGS := -O2$EXTRA_CFLAGS/" config/*/config.mk
57# 5. Build.
58make -j"$(nproc)"
60# 6. Re-archive from the full object tree. The Makefile's incremental
61# archiving (ar_obj_list) only covers objects compiled in the current make
62# run, which can leave the archive stale or incomplete across rebuilds.
63LIBDIR=$(dirname "$(find lib -name libflame.a)")
64rm -f "$LIBDIR/libflame.a"
65find obj -name '*.o' | sort | xargs -n 500 emar crs "$LIBDIR/libflame.a"
67# 7. Install (single flattened FLAME.h + libflame.a).
68if [ "$PTHREAD" = "1" ]; then
69 mkdir -p "$PREFIX/lib"
70 cp "$LIBDIR/libflame.a" "$PREFIX/lib/libflame-mt.a"
71 echo "Done. Library: $PREFIX/lib/libflame-mt.a"
72else
73 make install
74 echo "Done. Library: $PREFIX/lib/libflame.a Header: $PREFIX/include/FLAME.h"
75fi