#!/bin/sh

set -e

JOBS="$1"
TARGET="$2" # Example: riscv64-linux-gnu
MCPU="$3" # Examples: `baseline`, `native`, `generic+v7a`, or `arm1176jzf_s`

ROOTDIR="$(pwd)"
ZIG_VERSION="0.8.0"

TARGET_OS_AND_ABI=${TARGET#*-} # Example: linux-gnu

# Here we map the OS from the target triple to the value that CMake expects.
TARGET_OS_CMAKE=${TARGET_OS_AND_ABI%-*} # Example: linux
case $TARGET_OS_CMAKE in
  macos) TARGET_OS_CMAKE="Darwin";;
  freebsd) TARGET_OS_CMAKE="FreeBSD";;
  windows) TARGET_OS_CMAKE="Windows";;
  linux) TARGET_OS_CMAKE="Linux";;
  native) TARGET_OS_CMAKE="";;
esac

# First build the libraries for Zig to link against, as well as native `llvm-tblgen`.
mkdir -p "$ROOTDIR/out/build-llvm-host"
cd "$ROOTDIR/out/build-llvm-host"
cmake "$ROOTDIR/llvm" \
  -DLLVM_ENABLE_PROJECTS="lld;clang" \
  -DLLVM_ENABLE_LIBXML2=OFF \
  -DCMAKE_INSTALL_PREFIX="$ROOTDIR/out/host" \
  -DCMAKE_PREFIX_PATH="$ROOTDIR/out/host" \
  -DLLVM_INCLUDE_TESTS=OFF \
  -DLLVM_INCLUDE_GO_TESTS=OFF \
  -DLLVM_INCLUDE_EXAMPLES=OFF \
  -DLLVM_INCLUDE_BENCHMARKS=OFF \
  -DLLVM_ENABLE_BINDINGS=OFF \
  -DLLVM_ENABLE_OCAMLDOC=OFF \
  -DLLVM_ENABLE_Z3_SOLVER=OFF \
  -DCLANG_BUILD_TOOLS=OFF \
  -DCMAKE_BUILD_TYPE=Release
make "$JOBS" install

# Now we build Zig, still with system C/C++ compiler, linking against LLVM,
# Clang, LLD we just built from source.
mkdir -p "$ROOTDIR/out/build-zig-host"
cd "$ROOTDIR/out/build-zig-host"
cmake "$ROOTDIR/zig" \
  -DCMAKE_INSTALL_PREFIX="$ROOTDIR/out/host" \
  -DCMAKE_PREFIX_PATH="$ROOTDIR/out/host" \
  -DCMAKE_BUILD_TYPE=Release \
  -DZIG_VERSION="$ZIG_VERSION"
make "$JOBS" install

# Now we have Zig as a cross compiler.
ZIG="$ROOTDIR/out/host/bin/zig"
export CC="$ZIG cc -fno-sanitize=all -target $TARGET -mcpu=$MCPU"
export CXX="$ZIG c++ -fno-sanitize=all -target $TARGET -mcpu=$MCPU"

# First cross compile zlib for the target, as we need the LLVM linked into
# the finaly zig binary to have zlib support enabled.
mkdir -p "$ROOTDIR/out/build-zlib-$TARGET-$MCPU"
cd "$ROOTDIR/out/build-zlib-$TARGET-$MCPU"
cmake "$ROOTDIR/zlib" \
  -DCMAKE_INSTALL_PREFIX="$ROOTDIR/out/$TARGET-$MCPU" \
  -DCMAKE_PREFIX_PATH="$ROOTDIR/out/$TARGET-$MCPU" \
  -DCMAKE_BUILD_TYPE=Release \
  -DCMAKE_CROSSCOMPILING=True \
  -DCMAKE_SYSTEM_NAME="$TARGET_OS_CMAKE" \
  -DCMAKE_AR="$ROOTDIR/out/host/bin/llvm-ar" \
  -DCMAKE_RANLIB="$ROOTDIR/out/host/bin/llvm-ranlib"
make "$JOBS" install

# Rebuild LLVM with Zig.
mkdir -p "$ROOTDIR/out/build-llvm-$TARGET-$MCPU"
cd "$ROOTDIR/out/build-llvm-$TARGET-$MCPU"
cmake "$ROOTDIR/llvm" \
  -DLLVM_ENABLE_PROJECTS="lld;clang" \
  -DLLVM_ENABLE_LIBXML2=OFF \
  -DLLVM_ENABLE_TERMINFO=OFF \
  -DLLVM_ENABLE_ZLIB=FORCE_ON \
  -DLLVM_ENABLE_BACKTRACES=OFF \
  -DLLVM_ENABLE_PLUGINS=OFF \
  -DCMAKE_INSTALL_PREFIX="$ROOTDIR/out/$TARGET-$MCPU" \
  -DCMAKE_PREFIX_PATH="$ROOTDIR/out/$TARGET-$MCPU" \
  -DCMAKE_BUILD_TYPE=Release \
  -DCMAKE_CROSSCOMPILING=True \
  -DCMAKE_SYSTEM_NAME="$TARGET_OS_CMAKE" \
  -DCMAKE_AR="$ROOTDIR/out/host/bin/llvm-ar" \
  -DCMAKE_RANLIB="$ROOTDIR/out/host/bin/llvm-ranlib" \
  -DLLVM_TABLEGEN="$ROOTDIR/out/host/bin/llvm-tblgen" \
  -DCLANG_TABLEGEN="$ROOTDIR/out/build-llvm-host/bin/clang-tblgen" \
  -DLLVM_BUILD_TOOLS=OFF \
  -DLLVM_INCLUDE_UTILS=OFF \
  -DLLVM_INCLUDE_TESTS=OFF \
  -DLLVM_INCLUDE_GO_TESTS=OFF \
  -DLLVM_INCLUDE_EXAMPLES=OFF \
  -DLLVM_INCLUDE_BENCHMARKS=OFF \
  -DLLVM_ENABLE_BINDINGS=OFF \
  -DLLVM_ENABLE_OCAMLDOC=OFF \
  -DLLVM_ENABLE_Z3_SOLVER=OFF \
  -DCLANG_BUILD_TOOLS=OFF \
  -DCLANG_ENABLE_ARCMT=ON \
  -DLLVM_BUILD_STATIC=ON \
  -DLIBCLANG_BUILD_STATIC=ON \
  -DLLVM_DEFAULT_TARGET_TRIPLE="$TARGET"
cd "$ROOTDIR/out/build-llvm-$TARGET-$MCPU/tools/lld"
make "$JOBS" install
cd "$ROOTDIR/out/build-llvm-$TARGET-$MCPU/tools/clang/lib"
make "$JOBS" install
cd "$ROOTDIR/out/build-llvm-$TARGET-$MCPU/lib"
make "$JOBS" install
cd "$ROOTDIR/out/build-llvm-$TARGET-$MCPU"
make "$JOBS" install-llvm-headers install-clang-headers install-LLVMSupport install-LLVMDemangle

# Finally, we can cross compile Zig itself, with Zig.
mkdir -p "$ROOTDIR/out/build-zig-$TARGET-$MCPU"
cd "$ROOTDIR/out/build-zig-$TARGET-$MCPU"
cmake "$ROOTDIR/zig" \
  -DCMAKE_INSTALL_PREFIX="$ROOTDIR/out/zig-$TARGET-$MCPU" \
  -DCMAKE_PREFIX_PATH="$ROOTDIR/out/$TARGET-$MCPU" \
  -DCMAKE_CROSSCOMPILING=True \
  -DCMAKE_SYSTEM_NAME="$TARGET_OS_CMAKE" \
  -DCMAKE_AR="$ROOTDIR/out/host/bin/llvm-ar" \
  -DCMAKE_RANLIB="$ROOTDIR/out/host/bin/llvm-ranlib" \
  -DCMAKE_BUILD_TYPE=Release \
  -DZIG_TARGET_TRIPLE="$TARGET" \
  -DZIG_TARGET_MCPU="$MCPU" \
  -DZIG_EXECUTABLE="$ZIG" \
  -DZIG_VERSION="$ZIG_VERSION" \
  -DZIG_USE_LLVM_CONFIG=OFF \
  -DZIG_STATIC_ZLIB=ON
unset CC
unset CXX
make "$JOBS" install
