#!/usr/bin/env bash # # Fetch and build upstream SHTNS, then record how to link against it. # # ./bootstrap.sh # CPU, with OpenMP; adds CUDA if nvcc is on PATH # ./bootstrap.sh --no-cuda # CPU only, even if nvcc is there # ./bootstrap.sh --rev master # a different revision than the pinned one # # Writes shtns.mk, which the Makefile includes: the library name, the link # flags configure decided on, and whether GPU transforms were compiled in. # Re-run it after changing --rev or the CUDA choice; it is idempotent otherwise. set -euo pipefail cd "$(dirname "$0")" # SHTNS 3.7.5, master as of 2026-05-07. Pinned so a change upstream shows up as # a deliberate bump here rather than as a benchmark that quietly moved. REV=4e69ceb3fc5f19475d55b03ff0fdec210dc3075e URL=https://bitbucket.org/nschaeff/shtns.git DIR=shtns WANT_CUDA=auto CUDA_ARCH= while [ $# -gt 0 ]; do case "$1" in --no-cuda) WANT_CUDA=no ;; --cuda) WANT_CUDA=yes ;; --cuda=*) WANT_CUDA=yes; CUDA_ARCH="${1#*=}" ;; --rev) shift; REV="$1" ;; --rev=*) REV="${1#*=}" ;; -h|--help) sed -n '2,12p' "$0" | sed 's/^# \{0,1\}//' exit 0 ;; *) echo "bootstrap: unknown option '$1'" >&2; exit 2 ;; esac shift done if [ "$WANT_CUDA" = auto ]; then if command -v nvcc >/dev/null 2>&1; then WANT_CUDA=yes; else WANT_CUDA=no; fi fi # ---------------------------------------------------------------------- clone if [ ! -d "$DIR/.git" ]; then echo "==> cloning $URL" git clone "$URL" "$DIR" fi echo "==> checking out $REV" # --unshallow so an existing shallow clone can still reach a --rev other than the # one it was cloned at; it errors on a full clone, hence the fallback. git -C "$DIR" fetch --tags --unshallow origin 2>/dev/null || git -C "$DIR" fetch --tags origin git -C "$DIR" checkout --detach "$REV" # ------------------------------------------------------------------ configure CONF=(--enable-openmp) if [ "$WANT_CUDA" = yes ]; then if [ -n "$CUDA_ARCH" ]; then CONF+=("--enable-cuda=$CUDA_ARCH") else CONF+=(--enable-cuda) fi # configure looks for these where CUDA_PATH points; say so if it is unset and # nvcc is somewhere obvious, since the error it produces otherwise is opaque. if [ -z "${CUDA_PATH:-}" ]; then nvcc_dir=$(dirname "$(command -v nvcc)") export CUDA_PATH="${nvcc_dir%/bin}" echo "==> CUDA_PATH was unset; using $CUDA_PATH" fi fi echo "==> configure ${CONF[*]}" ( cd "$DIR" && ./configure "${CONF[@]}" ) echo "==> make" ( cd "$DIR" && make -j"$(getconf _NPROCESSORS_ONLN)" ) # --------------------------------------------------------------- record how to # link. configure has already worked all of this out; read it back rather than # guessing, so a machine that needed MKL or a different FFTW still links. libname=$(sed -n 's/^libname *= *//p' "$DIR/Makefile" | head -1) libs=$(sed -n 's/^LIBS=//p' "$DIR/Makefile" | head -1) if [ ! -f "$DIR/$libname" ]; then echo "bootstrap: expected $DIR/$libname but it is not there" >&2 exit 1 fi # Whether the GPU entry points are actually in the archive — asked of the # library rather than of configure's intentions, since --enable-cuda can succeed # at configure time and still leave them out. gpu=0 if nm -g "$DIR/$libname" 2>/dev/null | grep -q ' T cu_spat_to_SH_float'; then gpu=1 elif sed -n 's/^objs *= *//p' "$DIR/Makefile" | grep -q 'sht_gpu\.o'; then gpu=1 # no nm on this host; trust what configure put in the object list fi fft=none [ "$gpu" = 1 ] && fft=vkfft if [ "$gpu" = 1 ] && ! grep -q '^#define VKFFT_BACKEND' "$DIR/sht_config.h"; then # SHTNS falls back to cuFFT when vkfft/vkFFT.h is absent, and its configure # does not add -lcufft (the check is commented out), so we have to. fft=cufft libs="$libs -lcufft" fi cat > shtns.mk < built $DIR/$libname (GPU transforms: $([ "$gpu" = 1 ] && echo yes || echo no))" if [ "$gpu" = 1 ]; then echo " GPU Fourier stage: $fft" if [ "$fft" = cufft ]; then echo " NOTE: SHTNS' cuFFT path handles only the theta-contiguous layout, so" echo " --layout phi will not work. vkfft/vkFFT.h is normally in the SHTNS" echo " tree; if it is missing, that is why." fi fi echo " link flags: $libs" echo echo "Now: make"