#!/bin/bash
# The libraries the3djin-rs links, built on macOS as a shipped macOS application needs them, into
# $PREFIX (default ~/opt) — what docs/BUILDING.md's "macOS" section explains:
#
#   $PREFIX/deps-13        FreeType and libpng, static, for macOS 13.3 (Homebrew's are for its own macOS)
#   $PREFIX/glibcm         glibc's libm functions (../glibcm/README.md)
#   $PREFIX/occt-7.9.3     OpenCascade 7.9.3: exception checks on, -ffp-contract=off, maths from glibcm,
#                          its Delaunay mesher ordering ties as libstdc++ does (occt-7.9.3-tie-order.patch)
#   $PREFIX/djinmesh       djinmesh against that OpenCascade, the same way
#
# Needs Xcode's command line tools, cmake, ninja and Homebrew's eigen@3. DJINMESH is the djinmesh
# checkout (default: beside this repository). Takes about twenty minutes on an M-series Mac.
set -eu
here=$(cd "$(dirname "$0")" && pwd)
PREFIX=${PREFIX:-$HOME/opt}
SRC=${SRC:-$HOME/src/the3djin-deps}
DJINMESH=${DJINMESH:-$here/../../../djinmesh}
export MACOSX_DEPLOYMENT_TARGET=13.3
JOBS=$(sysctl -n hw.ncpu)
mkdir -p "$SRC" "$PREFIX"

for tool in cmake ninja curl git; do command -v $tool >/dev/null || { echo "!! $tool is missing" >&2; exit 1; }; done
EIGEN=$(brew --prefix eigen@3 2>/dev/null)/share/eigen3/cmake
[ -d "$EIGEN" ] || { echo "!! brew install eigen@3 (djinmesh needs Eigen 3, not Homebrew's eigen 5)" >&2; exit 1; }
[ -f "$DJINMESH/include/djinmesh.h" ] || { echo "!! no djinmesh checkout at $DJINMESH (set DJINMESH)" >&2; exit 1; }

fetch() { # url sha256 file
  [ -f "$SRC/$3" ] || curl -sSfL "$1" -o "$SRC/$3"
  [ "$(shasum -a 256 "$SRC/$3" | cut -d' ' -f1)" = "$2" ] || { echo "!! $3: checksum mismatch" >&2; exit 1; }
}

echo "==> FreeType and libpng, static, for macOS $MACOSX_DEPLOYMENT_TARGET"
fetch https://downloads.sourceforge.net/project/freetype/freetype2/2.14.3/freetype-2.14.3.tar.xz \
  36bc4f1cc413335368ee656c42afca65c5a3987e8768cc28cf11ba775e785a5f freetype-2.14.3.tar.xz
fetch https://downloads.sourceforge.net/project/libpng/libpng16/1.6.59/libpng-1.6.59.tar.xz \
  d80dd2a38a37f803cb9b6ac7b14bd6e74ddc3b654780a8380bdf93523fdb4389 libpng-1.6.59.tar.xz
(cd "$SRC" && tar xf freetype-2.14.3.tar.xz && tar xf libpng-1.6.59.tar.xz)
deps=$PREFIX/deps-13
cmake -S "$SRC/libpng-1.6.59" -B "$SRC/libpng-build" -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="$deps" \
  -DPNG_SHARED=OFF -DPNG_STATIC=ON -DPNG_TESTS=OFF -DPNG_TOOLS=OFF -DPNG_FRAMEWORK=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON >/dev/null
ninja -C "$SRC/libpng-build" install >/dev/null
cmake -S "$SRC/freetype-2.14.3" -B "$SRC/freetype-build" -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="$deps" \
  -DBUILD_SHARED_LIBS=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DFT_DISABLE_HARFBUZZ=ON -DFT_DISABLE_BROTLI=ON \
  -DFT_DISABLE_BZIP2=ON -DFT_DISABLE_PNG=ON -DFT_REQUIRE_ZLIB=ON >/dev/null
ninja -C "$SRC/freetype-build" install >/dev/null

echo "==> glibcm"
"$here/../glibcm/build.sh" "$PREFIX/glibcm"
alias_dir=$PREFIX/glibcm/alias
glibcm_lib=$PREFIX/glibcm/lib

echo "==> OpenCascade 7.9.3"
[ -d "$SRC/OCCT" ] || git clone -q --depth 1 --branch V7_9_3 https://github.com/Open-Cascade-SAS/OCCT.git "$SRC/OCCT"
git -C "$SRC/OCCT" apply --check "$here/occt-7.9.3-tie-order.patch" 2>/dev/null && git -C "$SRC/OCCT" apply "$here/occt-7.9.3-tie-order.patch"
flags="-ffp-contract=off -ffile-prefix-map=$SRC/OCCT=occt"
cmake -S "$SRC/OCCT" -B "$SRC/OCCT/build" -G Ninja -DCMAKE_BUILD_TYPE=Release -DINSTALL_DIR="$PREFIX/occt-7.9.3" \
  -DCMAKE_OSX_DEPLOYMENT_TARGET=$MACOSX_DEPLOYMENT_TARGET -DCMAKE_CXX_FLAGS="$flags" -DCMAKE_C_FLAGS="$flags" \
  -DCMAKE_SHARED_LINKER_FLAGS="-lz -Wl,-rpath,$glibcm_lib" \
  -DBUILD_RELEASE_DISABLE_EXCEPTIONS=OFF -DBUILD_MODULE_Draw=OFF -DUSE_TK=OFF -DUSE_FREETYPE=ON \
  -D3RDPARTY_FREETYPE_DIR="$deps" -D3RDPARTY_FREETYPE_INCLUDE_DIR_ft2build="$deps/include/freetype2" \
  -D3RDPARTY_FREETYPE_INCLUDE_DIR_freetype2="$deps/include/freetype2" -D3RDPARTY_FREETYPE_LIBRARY="$deps/lib/libfreetype.a" \
  -D3RDPARTY_FREETYPE_LIBRARY_DIR="$deps/lib" -DUSE_OPENGL=OFF -DUSE_GLES2=OFF -DUSE_VTK=OFF -DUSE_TBB=OFF \
  -DUSE_RAPIDJSON=OFF -DUSE_DRACO=OFF -DUSE_FREEIMAGE=OFF -DUSE_OPENVR=OFF >/dev/null
# OpenCascade puts -lm ahead of every flag it is given; with the alias first on the library path, that
# -lm is glibcm.
LIBRARY_PATH=$alias_dir ninja -C "$SRC/OCCT/build" -j"$JOBS" install >/dev/null

echo "==> djinmesh"
cmake -S "$DJINMESH" -B "$SRC/djinmesh-build" -G Ninja -DCMAKE_BUILD_TYPE=Release \
  -DCMAKE_OSX_DEPLOYMENT_TARGET=$MACOSX_DEPLOYMENT_TARGET -DCMAKE_CXX_FLAGS="-ffp-contract=off" -DCMAKE_C_FLAGS="-ffp-contract=off" \
  -DCMAKE_PREFIX_PATH="$PREFIX/occt-7.9.3;$deps;$(brew --prefix eigen@3)" \
  -DPNG_LIBRARY="$deps/lib/libpng16.a" -DPNG_PNG_INCLUDE_DIR="$deps/include" \
  -DCMAKE_SHARED_LINKER_FLAGS="-lm -Wl,-rpath,$glibcm_lib" -DCMAKE_INSTALL_RPATH="$PREFIX/occt-7.9.3/lib" \
  -DDJIN_WITH_OCC=ON -DDJIN_WITH_PNG=ON -DDJIN_WITH_PYTHON=OFF -DDJIN_WITH_METIS=OFF -DDJIN_WITH_CGNS=OFF \
  -DDJIN_WITH_MED=OFF -DDJIN_WITH_EXODUS=OFF -DDJIN_BUILD_TESTS=OFF >/dev/null
LIBRARY_PATH=$alias_dir ninja -C "$SRC/djinmesh-build" -j"$JOBS" djinmesh >/dev/null
mkdir -p "$PREFIX/djinmesh/include" "$PREFIX/djinmesh/lib"
cp "$DJINMESH/include/djinmesh.h" "$PREFIX/djinmesh/include/"
cp -a "$SRC/djinmesh-build"/libdjinmesh*.dylib "$PREFIX/djinmesh/lib/"

echo "==> checking that their maths is glibcm's"
maths='_(sin|cos|tan|asin|acos|atan|atan2|sinh|cosh|tanh|asinh|acosh|atanh|exp|exp2|expm1|log|log2|log10|log1p|pow|cbrt|hypot|lgamma|powf|acosf|sinf|cosf|__sincos_stret|__sincosf_stret|__exp10)'
elsewhere=$(for f in "$PREFIX"/occt-7.9.3/lib/libTK*.7.9.3.dylib "$PREFIX"/djinmesh/lib/libdjinmesh.*.*.*.dylib; do
  nm -m "$f" | grep -E "\(undefined\) external $maths " | grep -v "from libglibcm" | sed "s|^|$(basename "$f"): |"; done)
[ -z "$elsewhere" ] || { echo "!! these are not glibcm's:" >&2; echo "$elsewhere" | head >&2; exit 1; }
echo "==> done: $PREFIX/{deps-13,glibcm,occt-7.9.3,djinmesh}"
