#!/bin/sh
# Generate src/Makevars for the n4m R package. Two modes:
#
#   N4M_R_VENDOR=1  -> CRAN self-contained build: vendor the full libn4m C/C++
#                      core into src/vendor/ and compile it statically into
#                      n4m.so (no external libn4m at install/runtime). The
#                      library is zero-dependency by design (from-scratch
#                      reference linalg), so this needs only a C++17
#                      toolchain. This is the CRAN distribution path; submission
#                      itself is a manual web step (release-r.yml).
#
#   (default)       -> standalone dev/CI build: link a prebuilt libn4m located
#                      from PLS4ALL_LIB_DIR or the in-repo build. Fast inner loop
#                      + the R leg of the cross-binding parity gate.
#
#   N4M_R_LINK_PREBUILT=1 forces the standalone dev/CI build even when a
#                      src/vendor/ tree exists in the checkout from a previous
#                      CRAN package build.
set -e

PKG_ROOT=$(cd "$(dirname "$0")" && pwd)
REPO=$(cd "$PKG_ROOT/../../.." && pwd)

# ---------------------------------------------------------------------------
# CRAN self-contained (vendored static) build
#
# Triggered by N4M_R_VENDOR=1 (in-repo: vendor the sources from the checkout)
# OR when src/vendor/ is already populated (the CRAN source tarball ships the
# vendored sources, so the installing user — who has no repo — just compiles
# them). Either way the result is a self-contained n4m.so with no external
# libn4m at install or runtime.
# ---------------------------------------------------------------------------
VENDOR="$PKG_ROOT/src/vendor"
VENDORED_PRESENT=0
[ -d "$VENDOR/cpp/src/core" ] && VENDORED_PRESENT=1
FORCE_PREBUILT="${N4M_R_LINK_PREBUILT:-0}"

if [ "$FORCE_PREBUILT" != "1" ] && { [ "${N4M_R_VENDOR:-0}" = "1" ] || [ "$VENDORED_PRESENT" = "1" ]; }; then
    if [ "${N4M_R_VENDOR:-0}" = "1" ]; then
        # In-repo vendoring (forced): (re)copy the C/C++ core + headers +
        # the export header from the checkout into src/vendor/ (always fresh).
        # Export header: prefer the cmake-generated copy; else fall back to the
        # static template (cpp/include/n4m/n4m_export.h.in has no @-substitutions),
        # so vendoring needs NO cmake — just the source tree.
        EXPORT_HDR=""
        GEN="${PLS4ALL_GENERATED_DIR:-$REPO/build/dev-release/generated}"
        if [ -f "$GEN/n4m/n4m_export.h" ]; then
            EXPORT_HDR="$GEN/n4m/n4m_export.h"
        else
            for d in "$REPO"/build/*/generated; do
                [ -f "$d/n4m/n4m_export.h" ] && EXPORT_HDR="$d/n4m/n4m_export.h" && break
            done
        fi
        [ -z "$EXPORT_HDR" ] && [ -f "$REPO/cpp/include/n4m/n4m_export.h.in" ] \
            && EXPORT_HDR="$REPO/cpp/include/n4m/n4m_export.h.in"
        if [ -z "$EXPORT_HDR" ]; then
            echo "n4m configure(vendor): ERROR — no n4m_export.h (generated) or .in template found." >&2
            exit 1
        fi
        echo "n4m configure: CRAN self-contained build — vendoring sources from the checkout"
        rm -rf "$VENDOR"
        mkdir -p "$VENDOR/cpp/src" "$VENDOR/cpp/include" "$VENDOR/generated/n4m"
        cp -R "$REPO/cpp/src/core"    "$VENDOR/cpp/src/core"
        cp -R "$REPO/cpp/src/c_api"   "$VENDOR/cpp/src/c_api"
        cp -R "$REPO/cpp/include/n4m" "$VENDOR/cpp/include/n4m"
        cp "$EXPORT_HDR"              "$VENDOR/generated/n4m/n4m_export.h"
    else
        echo "n4m configure: CRAN self-contained build — using vendored sources from the tarball"
    fi

    cat > "$PKG_ROOT/src/Makevars" <<'MK'
# GENERATED by ./configure (N4M_R_VENDOR=1) — CRAN self-contained static build.
# Requires GNU make (SystemRequirements) for $(shell find ...) recursion.
PKG_CPPFLAGS = -Ivendor/cpp/include -Ivendor/cpp/src -Ivendor/generated \
               -DN4M_STATIC=1
CXX_STD = CXX17
# No FMA contraction: the same bits as every other n4m binding (see the root
# CMakeLists.txt). Unix R toolchains are GCC or Clang.
PKG_CFLAGS = -ffp-contract=off
PKG_CXXFLAGS = -ffp-contract=off

VEND_C   := $(shell find vendor -name '*.c')
# cuda_dispatch.cpp is the CUDA backend (needs cublas); excluded from the
# reference build, exactly as the CMake build gates it behind N4M_USE_CUDA.
VEND_CPP := $(shell find vendor -name '*.cpp' ! -name 'cuda_dispatch.cpp')
R_OBJ    := r_init.o r_gateway.o r_dispatch.o r_methods.o n4m_cxx.o

OBJECTS = $(R_OBJ) $(VEND_C:.c=.o) $(VEND_CPP:.cpp=.o)
MK
    echo "  vendored: $(find "$VENDOR" -name '*.cpp' -o -name '*.c' | wc -l) TUs"
    exit 0
fi

# ---------------------------------------------------------------------------
# Standalone prebuilt-link build (default)
# ---------------------------------------------------------------------------
INC="${PLS4ALL_INCLUDE_DIR:-$REPO/cpp/include}"
GEN="${PLS4ALL_GENERATED_DIR:-$REPO/build/dev-release/generated}"
LIB="${PLS4ALL_LIB_DIR:-$REPO/build/dev-release/cpp/src}"

if [ ! -e "$LIB/libn4m.so" ] && [ ! -e "$LIB/libn4m.dylib" ]; then
    for d in "$REPO"/build/*/cpp/src; do
        if [ -e "$d/libn4m.so" ] || [ -e "$d/libn4m.dylib" ]; then
            LIB="$d"
            GEN="$(cd "$d/../.." && pwd)/generated"
            break
        fi
    done
fi

if [ ! -e "$LIB/libn4m.so" ] && [ ! -e "$LIB/libn4m.dylib" ]; then
    echo "n4m configure: ERROR — no libn4m found (looked in '$LIB' and build/*/cpp/src)." >&2
    echo "  Build it (cmake --preset dev-release && cmake --build --preset dev-release)," >&2
    echo "  set PLS4ALL_LIB_DIR, or use N4M_R_VENDOR=1 for the CRAN self-contained build." >&2
    exit 1
fi

CPPFLAGS="-I$INC -I$GEN"
LIBS="-L$LIB -ln4m -Wl,-rpath,$LIB"

sed -e "s|@N4M_CPPFLAGS@|$CPPFLAGS|g" \
    -e "s|@N4M_LIBS@|$LIBS|g" \
    "$PKG_ROOT/src/Makevars.in" > "$PKG_ROOT/src/Makevars"

echo "n4m configure: linking prebuilt libn4m"
echo "  include   = $INC"
echo "  generated = $GEN"
echo "  lib       = $LIB"
