#!/bin/sh
##########################################################################
# File: dktool/dk                                                        #
#                                                                        #
# Copyright 2023 Diskuv, Inc.                                            #
#                                                                        #
# Licensed under the Apache License, Version 2.0 (the "License");        #
# you may not use this file except in compliance with the License.       #
# You may obtain a copy of the License at                                #
#                                                                        #
#     http://www.apache.org/licenses/LICENSE-2.0                         #
#                                                                        #
# Unless required by applicable law or agreed to in writing, software    #
# distributed under the License is distributed on an "AS IS" BASIS,      #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        #
# implied. See the License for the specific language governing           #
# permissions and limitations under the License.                         #
#                                                                        #
##########################################################################

# Recommendation: Place this file in source control.
# Auto-generated by `./dk dksdk.project.new` of dktool.
#
# Invoking: ./dk
#   That works in Powershell on Windows, and in Unix. Copy-and-paste works!
#
# Purpose: Install CMake if not already. Then invoke CMake.

set -euf

dk_pwd=$PWD

# --- Imports of dkml-runtime-common's crossplatform-functions.sh ---

# Get standard locations of Unix system binaries like `/usr/bin/mv` (or `/bin/mv`).
#
# Will not return anything in `/usr/local/bin` or `/usr/sbin`. Use when you do not
# know whether the PATH has been set correctly, or when you do not know if the
# system binary exists.
#
# At some point in the future, this function will error out if the required system binaries
# do not exist. Most system binaries are common to all Unix/Linux/macOS installations but
# some (like `comm`) may need to be installed for proper functioning of DKML.
#
# Outputs:
# - env:DKMLSYS_MV - Location of `mv`
# - env:DKMLSYS_CHMOD - Location of `chmod`
# - env:DKMLSYS_UNAME - Location of `uname`
# - env:DKMLSYS_ENV - Location of `env`
# - env:DKMLSYS_AWK - Location of `awk`
# - env:DKMLSYS_SED - Location of `sed`
# - env:DKMLSYS_COMM - Location of `comm`
# - env:DKMLSYS_INSTALL - Location of `install`
# - env:DKMLSYS_RM - Location of `rm`
# - env:DKMLSYS_SORT - Location of `sort`
# - env:DKMLSYS_CAT - Location of `cat`
# - env:DKMLSYS_STAT - Location of `stat`
# - env:DKMLSYS_GREP - Location of `grep`
# - env:DKMLSYS_CURL - Location of `curl` (empty if not found)
# - env:DKMLSYS_WGET - Location of `wget` (empty if not found)
# - env:DKMLSYS_TR - Location of `tr`
autodetect_system_binaries() {
    if [ -z "${DKMLSYS_MV:-}" ]; then
        if [ -x /usr/bin/mv ]; then
            DKMLSYS_MV=/usr/bin/mv
        else
            DKMLSYS_MV=/bin/mv
        fi
    fi
    if [ -z "${DKMLSYS_CHMOD:-}" ]; then
        if [ -x /usr/bin/chmod ]; then
            DKMLSYS_CHMOD=/usr/bin/chmod
        else
            DKMLSYS_CHMOD=/bin/chmod
        fi
    fi
    if [ -z "${DKMLSYS_UNAME:-}" ]; then
        if [ -x /usr/bin/uname ]; then
            DKMLSYS_UNAME=/usr/bin/uname
        else
            DKMLSYS_UNAME=/bin/uname
        fi
    fi
    if [ -z "${DKMLSYS_ENV:-}" ]; then
        if [ -x /usr/bin/env ]; then
            DKMLSYS_ENV=/usr/bin/env
        else
            DKMLSYS_ENV=/bin/env
        fi
    fi
    if [ -z "${DKMLSYS_AWK:-}" ]; then
        if [ -x /usr/bin/awk ]; then
            DKMLSYS_AWK=/usr/bin/awk
        else
            DKMLSYS_AWK=/bin/awk
        fi
    fi
    if [ -z "${DKMLSYS_SED:-}" ]; then
        if [ -x /usr/bin/sed ]; then
            DKMLSYS_SED=/usr/bin/sed
        else
            DKMLSYS_SED=/bin/sed
        fi
    fi
    if [ -z "${DKMLSYS_COMM:-}" ]; then
        if [ -x /usr/bin/comm ]; then
            DKMLSYS_COMM=/usr/bin/comm
        else
            DKMLSYS_COMM=/bin/comm
        fi
    fi
    if [ -z "${DKMLSYS_INSTALL:-}" ]; then
        if [ -x /usr/bin/install ]; then
            DKMLSYS_INSTALL=/usr/bin/install
        else
            DKMLSYS_INSTALL=/bin/install
        fi
    fi
    if [ -z "${DKMLSYS_RM:-}" ]; then
        if [ -x /usr/bin/rm ]; then
            DKMLSYS_RM=/usr/bin/rm
        else
            DKMLSYS_RM=/bin/rm
        fi
    fi
    if [ -z "${DKMLSYS_SORT:-}" ]; then
        if [ -x /usr/bin/sort ]; then
            DKMLSYS_SORT=/usr/bin/sort
        else
            DKMLSYS_SORT=/bin/sort
        fi
    fi
    if [ -z "${DKMLSYS_CAT:-}" ]; then
        if [ -x /usr/bin/cat ]; then
            DKMLSYS_CAT=/usr/bin/cat
        else
            DKMLSYS_CAT=/bin/cat
        fi
    fi
    if [ -z "${DKMLSYS_STAT:-}" ]; then
        if [ -x /usr/bin/stat ]; then
            DKMLSYS_STAT=/usr/bin/stat
        else
            DKMLSYS_STAT=/bin/stat
        fi
    fi
    if [ -z "${DKMLSYS_GREP:-}" ]; then
        if [ -x /usr/bin/grep ]; then
            DKMLSYS_GREP=/usr/bin/grep
        else
            DKMLSYS_GREP=/bin/grep
        fi
    fi
    if [ -z "${DKMLSYS_CURL:-}" ]; then
        if [ -x /usr/bin/curl ]; then
            DKMLSYS_CURL=/usr/bin/curl
        elif [ -x /bin/curl ]; then
            DKMLSYS_CURL=/bin/curl
        else
            DKMLSYS_CURL=
        fi
    fi
    if [ -z "${DKMLSYS_WGET:-}" ]; then
        if [ -x /usr/bin/wget ]; then
            DKMLSYS_WGET=/usr/bin/wget
        elif [ -x /bin/wget ]; then
            DKMLSYS_WGET=/bin/wget
        else
            DKMLSYS_WGET=
        fi
    fi
    if [ -z "${DKMLSYS_TR:-}" ]; then
        if [ -x /usr/bin/tr ]; then
            DKMLSYS_TR=/usr/bin/tr
        else
            DKMLSYS_TR=/bin/tr
        fi
    fi
    export DKMLSYS_MV DKMLSYS_CHMOD DKMLSYS_UNAME DKMLSYS_ENV DKMLSYS_AWK DKMLSYS_SED DKMLSYS_COMM DKMLSYS_INSTALL
    export DKMLSYS_RM DKMLSYS_SORT DKMLSYS_CAT DKMLSYS_STAT DKMLSYS_GREP DKMLSYS_CURL DKMLSYS_WGET DKMLSYS_TR
}

# Is a Windows build machine if we are in a MSYS2 or Cygwin environment.
#
# Better alternatives
# -------------------
#
# 1. If you are checking to see if you should do a cygpath, then just guard it
#    like so:
#       if [ -x /usr/bin/cygpath ]; then
#           do_something $(/usr/bin/cygpath ...) ...
#       fi
#    This clearly guards what you are about to do (cygpath) with what you will
#    need (cygpath).
# 2. is_arg_windows_platform
is_unixy_windows_build_machine() {
    if is_msys2_msys_build_machine || is_cygwin_build_machine; then
        return 0
    fi
    return 1
}

# Is a MSYS2 environment with the MSYS or MINGW64 subsystem?
# * MSYS2 can also do MinGW 32-bit and 64-bit subsystems. Used by Diskuv OCaml
# * MINGW64 used by Git Bash (aka. GitHub Actions `shell: bash`)
# https://www.msys2.org/docs/environments/
is_msys2_msys_build_machine() {
    if [ -e /usr/bin/msys-2.0.dll ] && {
        [ "${MSYSTEM:-}" = "MSYS" ] || [ "${MSYSTEM:-}" = "MINGW64" ] || [ "${MSYSTEM:-}" = "UCRT64" ] || [ "${MSYSTEM:-}" = "CLANG64" ] || [ "${MSYSTEM:-}" = "MINGW32" ] || [ "${MSYSTEM:-}" = "CLANG32" ] || [ "${MSYSTEM:-}" = "CLANGARM64" ]
    }; then
        return 0
    fi
    return 1
}

is_cygwin_build_machine() {
    if [ -e /usr/bin/cygwin1.dll ]; then
        return 0
    fi
    return 1
}

# Tries to find the host ABI.
#
# Beware: This function uses `uname` probing which is inaccurate during
# cross-compilation.
#
# Outputs:
# - env:BUILDHOST_ARCH will contain the host ABI.
autodetect_buildhost_arch() {
    # Set DKMLSYS_*
    autodetect_system_binaries

    autodetect_buildhost_arch_SYSTEM=$("$DKMLSYS_UNAME" -s)
    autodetect_buildhost_arch_MACHINE=$("$DKMLSYS_UNAME" -m)
    # list from https://en.wikipedia.org/wiki/Uname and https://stackoverflow.com/questions/45125516/possible-values-for-uname-m
    case "${autodetect_buildhost_arch_SYSTEM}-${autodetect_buildhost_arch_MACHINE}" in
        Linux-armv7*)
            BUILDHOST_ARCH=linux_arm32v7;;
        Linux-armv6* | Linux-arm)
            BUILDHOST_ARCH=linux_arm32v6;;
        Linux-aarch64 | Linux-arm64 | Linux-armv8*)
            BUILDHOST_ARCH=linux_arm64;;
        Linux-i386 | Linux-i686)
            BUILDHOST_ARCH=linux_x86;;
        Linux-x86_64)
            BUILDHOST_ARCH=linux_x86_64;;
        Darwin-arm64)
            BUILDHOST_ARCH=darwin_arm64;;
        Darwin-x86_64)
            BUILDHOST_ARCH=darwin_x86_64;;
        *-i386 | *-i686)
            if is_unixy_windows_build_machine; then
                BUILDHOST_ARCH=windows_x86
            else
                printf "%s\n" "FATAL: Unsupported build machine type obtained from 'uname -s' and 'uname -m': $autodetect_buildhost_arch_SYSTEM and $autodetect_buildhost_arch_MACHINE" >&2
                exit 1
            fi
            ;;
        *-x86_64)
            if is_unixy_windows_build_machine; then
                BUILDHOST_ARCH=windows_x86_64
            else
                printf "%s\n" "FATAL: Unsupported build machine type obtained from 'uname -s' and 'uname -m': $autodetect_buildhost_arch_SYSTEM and $autodetect_buildhost_arch_MACHINE" >&2
                exit 1
            fi
            ;;
        *)
            # Since:
            # 1) MSYS2 does not run on ARM/ARM64 (https://www.msys2.org/docs/environments/)
            # 2) MSVC does not use ARM/ARM64 as host machine (https://docs.microsoft.com/en-us/cpp/build/building-on-the-command-line?view=msvc-160)
            # we do not support Windows ARM/ARM64 as a build machine
            printf "%s\n" "FATAL: Unsupported build machine type obtained from 'uname -s' and 'uname -m': $autodetect_buildhost_arch_SYSTEM and $autodetect_buildhost_arch_MACHINE" >&2
            exit 1
            ;;
    esac
}

# A function that will try to print an ISO8601 timestamp, but will fallback to
# the system default. Always uses UTC timezone.
try_iso8601_timestamp() {
    date -u -Iseconds 2>/dev/null || TZ=UTC date
}

# A function that will print the command and possibly time it (if and only if it uses a full path to
# an executable, so that 'time' does not fail on internal shell functions).
# If --return-error-code is the first argument or LOG_TRACE_RETURN_ERROR_CODE=ON, then instead of exiting the
# function will return the error code.
log_trace() {
    log_trace_RETURN=${LOG_TRACE_RETURN_ERROR_CODE:-OFF}

    log_trace_1="$1"
    if [ "$log_trace_1" = "--return-error-code" ]; then
        shift
        log_trace_RETURN=ON
    fi

    if [ "${DKML_BUILD_TRACE:-OFF}" = ON ]; then
        printf "[%s] %s\n" "$(try_iso8601_timestamp)" "+ $*" >&2
        if [ -x "$1" ]; then
            time "$@"
        else
            "$@"
        fi
    else
        # use judgement so we essentially have log at an INFO level
        case "$1" in
        rm|cp)
            # debug level. only show when DKML_BUILD_TRACE=ON
            ;;
        git|make|ocaml_configure|ocaml_make|make_host|make_target)
            # info level. and can show entire command without polluting the screen
            printf "[%s] %s\n" "$(try_iso8601_timestamp)" "$*" >&2
            ;;
        *)  printf "[%s] %s\n" "$(try_iso8601_timestamp)" "$1" >&2
        esac
        "$@"
    fi
    log_trace_ec="$?"
    if [ "$log_trace_ec" -ne 0 ]; then
        if [ "$log_trace_RETURN" = ON ]; then
            return "$log_trace_ec"
        else
            printf "FATAL: Command failed with exit code %s: %s\n" "$log_trace_ec" "$*" >&2
            exit "$log_trace_ec"
        fi
    fi
}

# [sha256compute FILE] writes the SHA256 checksum (hex encoded) of file FILE to the standard output.
sha256compute() {
    sha256compute_FILE="$1"
    shift
    # For reasons unclear doing the following in MSYS2:
    #   sha256sum 'Z:\source\README.md'
    # will produce a backslash like:
    #   \5518c76ed7234a153941fb7bc94b6e91d9cb8f1c4e22daf169a59b5878c3fc8a *Z:\\source\\README.md
    # So always cygpath the filename if available
    if [ -x /usr/bin/cygpath ]; then
        sha256compute_FILE=$(/usr/bin/cygpath -a "$sha256compute_FILE")
    fi

    if [ -x /usr/bin/shasum ]; then
        /usr/bin/shasum -a 256 "$sha256compute_FILE" | awk '{print $1}'
    elif [ -x /usr/bin/sha256sum ]; then
        /usr/bin/sha256sum "$sha256compute_FILE" | awk '{print $1}'
    else
        printf "FATAL: %s\n" "No sha256 checksum utility found" >&2
        exit 107
    fi
}

# [sha256check FILE SUM] checks that the file FILE has a SHA256 checksum (hex encoded) of SUM.
# The function will return nonzero (and exit with failure if `set -e` is enabled) if the checksum does not match.
sha256check() {
    sha256check_FILE="$1"
    shift
    sha256check_SUM="$1"
    shift
    if [ -x /usr/bin/shasum ]; then
        printf "%s  %s" "$sha256check_SUM" "$sha256check_FILE" | /usr/bin/shasum -a 256 -c >&2
    elif [ -x /usr/bin/sha256sum ]; then
        printf "%s  %s" "$sha256check_SUM" "$sha256check_FILE" | /usr/bin/sha256sum -c >&2
    else
        printf "FATAL: %s\n" "No sha256 checksum utility found" >&2
        exit 107
    fi
}

# [downloadfile URL FILE SUM] downloads from URL into FILE and verifies the SHA256 checksum of SUM.
# If the FILE already exists with the correct checksum it is not redownloaded.
# The function will exit with failure if the checksum does not match.
downloadfile() {
    downloadfile_URL="$1"
    shift
    downloadfile_FILE="$1"
    shift
    downloadfile_SUM="$1"
    shift

    # Set DKMLSYS_*
    autodetect_system_binaries

    if [ -e "$downloadfile_FILE" ]; then
        if sha256check "$downloadfile_FILE" "$downloadfile_SUM"; then
            return 0
        else
            $DKMLSYS_RM -f "$downloadfile_FILE"
        fi
    fi
    if [ "${CI:-}" = true ]; then
        if [ -n "$DKMLSYS_CURL" ]; then
            log_trace "$DKMLSYS_CURL" -L -s "$downloadfile_URL" -o "$downloadfile_FILE".tmp
        elif [ -n "$DKMLSYS_WGET" ]; then
            log_trace "$DKMLSYS_WGET" -q -O "$downloadfile_FILE".tmp "$downloadfile_URL"
        else
            echo "No curl or wget available on the system paths" >&2
            exit 107
        fi
    else
        if [ -n "$DKMLSYS_CURL" ]; then
            log_trace "$DKMLSYS_CURL" -L "$downloadfile_URL" -o "$downloadfile_FILE".tmp
        elif [ -n "$DKMLSYS_WGET" ]; then
            log_trace "$DKMLSYS_WGET" -O "$downloadfile_FILE".tmp "$downloadfile_URL"
        else
            echo "No curl or wget available on the system paths" >&2
            exit 107
        fi
    fi
    if ! sha256check "$downloadfile_FILE".tmp "$downloadfile_SUM"; then
        printf "%s\n" "FATAL: Encountered a corrupted or compromised download from $downloadfile_URL" >&2
        exit 1
    fi
    $DKMLSYS_MV "$downloadfile_FILE".tmp "$downloadfile_FILE"
}

# --- Environment detection ---

# Set DKMLSYS_*
autodetect_system_binaries

# Find host ABI. Set in BUILDHOST_ARCH
autodetect_buildhost_arch

# Use the project tree as the current directory
PROJ_DIR=$(dirname "$0")
PROJ_DIR=$(cd "$PROJ_DIR" && pwd)
cd "$PROJ_DIR"

# --- Tool directory selection ---

tools_dir=
tools_name=dktool
#   1. Check if CI since many CI providers can only cache content in a subdirectory
#      of the project.
if [ -z "$tools_dir" ] && [ "${CI:-}" = true ]; then
  install -d "$PROJ_DIR/.tools"
  tools_dir="$PROJ_DIR/.tools"
fi
#   2. Check in locations rooted under /opt/diskuv
#      We look under a /opt/diskuv early because
#      - Especially important for WSL2 to use a pure Linux filesystem (ext4) for
#        best performance.
#      - Using a canonical location (especially /opt/diskuv/usr/share) makes
#        it easy to use CMake presets for non-Windows hosts.
if [ -z "$tools_dir" ] && [ -n "${XDG_DATA_HOME:-}" ] && [ -w "/opt/diskuv/$XDG_DATA_HOME" ]; then
  install -d "/opt/diskuv/$XDG_DATA_HOME/$tools_name"
  tools_dir="/opt/diskuv/$XDG_DATA_HOME/$tools_name"
fi
if [ -z "$tools_dir" ] && [ -n "${HOME:-}" ] && [ -w "/opt/diskuv/$HOME" ]; then
  install -d "/opt/diskuv/$HOME/.local/share/$tools_name"
  tools_dir="/opt/diskuv/$HOME/.local/share/$tools_name"
fi
if [ -z "$tools_dir" ] && [ -w "/opt/diskuv/usr/share" ]; then
  install -d "/opt/diskuv/usr/share/$tools_name"
  tools_dir="/opt/diskuv/usr/share/$tools_name"
fi
#   3. Check in the conventional locations rooted under /
if [ -z "$tools_dir" ] && [ -n "${XDG_DATA_HOME:-}" ] && [ -w "$XDG_DATA_HOME" ]; then
  install -d "$XDG_DATA_HOME/$tools_name"
  tools_dir="$XDG_DATA_HOME/$tools_name"
fi
if [ -z "$tools_dir" ] && [ -n "${HOME:-}" ] && [ -w "$HOME" ]; then
  install -d "$HOME/.local/share/$tools_name"
  tools_dir="$HOME/.local/share/$tools_name"
fi
#   4. Validate
if [ -z "$tools_dir" ]; then
  echo "FATAL: Could not find a location to install the tools necessary for this project." >&2
  echo "  ...: Make sure you have a home directory and that it is write-able, or define" >&2
  echo "  ...: the environment variable XDG_DATA_HOME in a shell profile script after" >&2
  echo "  ...: creating the \$XDG_DATA_HOME directory." >&2
  exit 2
fi

# --- Tool downloads and installs ---

# PREREQS
# -------

install_linux_prog() {
  install_linux_prog_NAME=$1
  shift
  install_linux_prog_PKG=$1
  shift
  if [ -x "/usr/bin/$install_linux_prog_NAME" ]; then
    export DK_PROG_INSTALLED_LOCATION="/usr/bin/$install_linux_prog_NAME"
  else
    if command -v yum > /dev/null 2> /dev/null; then
      if [ "$(id -u)" -eq 0 ]; then
        yum install -y "$install_linux_prog_PKG"
      else
        echo "Running: sudo yum install -y $install_linux_prog_PKG"
        sudo yum install -y "$install_linux_prog_PKG"
      fi
    else
      if [ "$(id -u)" -eq 0 ]; then
        apt-get -q install -y "$install_linux_prog_PKG"
      else
        echo "Running: sudo -q apt-get -qq install -y --no-install-suggests $install_linux_prog_PKG"
        sudo apt-get -qq install -y --no-install-suggests "$install_linux_prog_PKG"
      fi
    fi
    DK_PROG_INSTALLED_LOCATION=$(command -v "$install_linux_prog_NAME")
    export DK_PROG_INSTALLED_LOCATION
  fi
}

get_homebrew_binary() {
  get_homebrew_binary_NAME=$1
  shift
  if command -v brew > /dev/null 2> /dev/null; then
    get_homebrew_binary_PREFIX=$(brew --prefix)
    if [ -x "$get_homebrew_binary_PREFIX/bin/$get_homebrew_binary_NAME" ]; then
      export DK_PROG_INSTALLED_LOCATION="$get_homebrew_binary_PREFIX/bin/$get_homebrew_binary_NAME"
      return 0
    fi
  fi
  return 1
}

install_macos_prog() {
  install_macos_prog_NAME=$1
  shift
  install_macos_prog_PKG=$1
  shift
  if [ -x "/usr/bin/$install_macos_prog_NAME" ]; then
    export DK_PROG_INSTALLED_LOCATION="/usr/bin/$install_macos_prog_NAME"
  elif [ -x "/usr/local/bin/$install_macos_prog_NAME" ]; then
    export DK_PROG_INSTALLED_LOCATION="/usr/local/bin/$install_macos_prog_NAME"
  elif get_homebrew_binary "$install_macos_prog_NAME"; then
    # DK_PROG_INSTALLED_LOCATION already set by [get_homebrew_binary]
    true
  else
    if command -v brew > /dev/null 2> /dev/null; then
      brew install --quiet --formula "$install_macos_prog_PKG" >&2
      get_homebrew_binary "$install_macos_prog_NAME"
      # DK_PROG_INSTALLED_LOCATION already set by [get_homebrew_binary]
    elif command -v port > /dev/null 2> /dev/null; then
      if [ "$(id -u)" -eq 0 ]; then
        port install "$install_macos_prog_PKG"
      else
        echo "Running: sudo port install $install_macos_prog_PKG"
        sudo port install "$install_macos_prog_PKG"
      fi
      DK_PROG_INSTALLED_LOCATION=$(command -v "$install_macos_prog_NAME")
      export DK_PROG_INSTALLED_LOCATION
    else
      echo "FATAL: Neither Homebrew nor MacPorts are available on your macOS. You can follow https://docs.brew.sh/Installation to install Homebrew." >&2
      exit 2
    fi
  fi
}

case $BUILDHOST_ARCH in
  linux_*)
    install_linux_prog wget wget # For [downloadfile]
    install_linux_prog tar tar # For handling tar balls later in this script
    ;;
esac

# NINJA
# -----
#   We need a valid CMAKE_GENERATOR to do FetchContent_Populate() in script mode

NINJA_EXE=
case $BUILDHOST_ARCH in
  darwin_*)
    install_macos_prog ninja ninja
    NINJA_EXE=$DK_PROG_INSTALLED_LOCATION;;
  linux_*)
    install_linux_prog ninja ninja-build
    NINJA_EXE=$DK_PROG_INSTALLED_LOCATION;;
esac

# CMAKE
# -----

case $BUILDHOST_ARCH in
  linux_*)
    #   This is for CMake to do FetchContent()
    install_linux_prog git git ;;
esac
case $BUILDHOST_ARCH in
  linux_x86)
    #   This is for Python wheel extraction
    install_linux_prog unzip unzip ;;
esac

cmake_base=
cmake_majmin_ver=3.25
cmake_majminpat_ver=3.25.2
cmake_bindir=
cmake_destdir=$tools_dir/cmake-$cmake_majminpat_ver
install -d "$tools_dir/dl"
download_cmake() {
  case $BUILDHOST_ARCH in
    darwin_*)
      install_macos_prog cmake cmake
      cmake_bindir=$(dirname "$DK_PROG_INSTALLED_LOCATION")
      ;;
    linux_x86_64)
      cmake_base="cmake-$cmake_majminpat_ver-linux-x86_64"
      printf "%s\n\n" "-- Downloading cmake-$cmake_majminpat_ver for Linux x86_64" >&2
      downloadfile \
        "https://github.com/Kitware/CMake/releases/download/v$cmake_majminpat_ver/$cmake_base.tar.gz" \
        "$tools_dir/dl/cmake.tar.gz" \
        783da74f132fd1fea91b8236d267efa4df5b91c5eec1dea0a87f0cf233748d99
      cmake_bindir="$cmake_destdir/bin" ;;
    linux_x86)
      # CMake does not provide 32-bit binaries. But pypi does at https://pypi.org/project/cmake/
      printf "%s\n\n" "-- Downloading cmake-$cmake_majminpat_ver for Linux x86" >&2
      downloadfile \
        https://files.pythonhosted.org/packages/11/6e/aeeddf2f5b16542b6a30ceab4896421e8705d8e9a9296dba79395db11b00/cmake-3.25.2-py2.py3-none-manylinux_2_17_i686.manylinux2014_i686.whl \
        "$tools_dir/dl/cmake.whl" \
        715ef82e81b48db3e4c7744614c15ff361d53f6987fd70b1b66b0880595f2e2c
      cmake_bindir="$cmake_destdir/bin" ;;
    linux_arm64)
      cmake_base="cmake-$cmake_majminpat_ver-linux-aarch64"
      printf "%s\n\n" "-- Downloading cmake-$cmake_majminpat_ver for Linux ARM64" >&2
      downloadfile \
        "https://github.com/Kitware/CMake/releases/download/v$cmake_majminpat_ver/$cmake_base.tar.gz" \
        "$tools_dir/dl/cmake.tar.gz" \
        9216ecf0449ade700e66e0def11eeaebf9fa7d4428c02f49cb59f11418d3f8a5
      cmake_bindir="$cmake_destdir/bin" ;;
  esac
}
export_cmake_vars() {
  case $BUILDHOST_ARCH in
    darwin_*)
      if command -v brew > /dev/null 2> /dev/null; then
        cmake_bindir=$(brew --prefix cmake)/bin
      else
        cmake_bindir=$(command -v cmake)
        cmake_bindir=$(dirname "$cmake_bindir")
      fi
      ;;
    linux_x86_64)
      cmake_bindir="$cmake_destdir/bin" ;;
    linux_x86)
      cmake_bindir="$cmake_destdir/bin" ;;
  esac
}
have_correct_cmake=0
if [ -x "$tools_dir/cmake-$cmake_majminpat_ver/bin/cmake" ]; then
  # shellcheck disable=SC2016
  have_correct_cmake_VER=$("$tools_dir/cmake-$cmake_majminpat_ver/bin/cmake" --version | $DKMLSYS_AWK 'NR==1{print $NF}')
  if [ "$have_correct_cmake_VER" = "$cmake_majminpat_ver" ]; then
    have_correct_cmake=1
  fi
fi
if [ $have_correct_cmake -eq 0 ]; then
  download_cmake
fi
#   Handle tarball
if [ -e "$tools_dir/dl/cmake.tar.gz" ] && [ -n "$cmake_base" ]; then
  rm -rf "$tools_dir/cmake-$cmake_majminpat_ver"
  install -d "$cmake_destdir"
  tar xCfz "$cmake_destdir" "$tools_dir/dl/cmake.tar.gz"
  rm -f "$tools_dir/dl/cmake.tar.gz"
  set +f
  if [ -e "$cmake_destdir/$cmake_base/CMake.app" ]; then
      mv "$cmake_destdir/$cmake_base/CMake.app/Contents"/* "$cmake_destdir/"
  else
      mv "$cmake_destdir/$cmake_base"/* "$cmake_destdir/"
  fi
  set -f
fi
#   Handle Python wheel
if [ -e "$tools_dir/dl/cmake.whl" ]; then
  rm -rf "$tools_dir/cmake-$cmake_majminpat_ver"
  cd "$tools_dir/dl"
  rm -rf cmake/data
  #     Don't want cmake/data/{aclocal,bash-completion,emacs,vim}
  unzip -q cmake.whl 'cmake/data/bin/**'
  unzip -q cmake.whl 'cmake/data/doc/**'
  #     Don't want cmake/data/share/cmake-$cmake_majmin_ver/Help
  unzip -q cmake.whl "cmake/data/share/cmake-$cmake_majmin_ver/"'include/**'
  unzip -q cmake.whl "cmake/data/share/cmake-$cmake_majmin_ver/"'Modules/**'
  unzip -q cmake.whl "cmake/data/share/cmake-$cmake_majmin_ver/"'Templates/**'
  rm -f cmake.whl
  cd -
  set +f
  install -d "$cmake_destdir/share" "$cmake_destdir/doc" "$cmake_destdir/bin"
  mv "$tools_dir/dl/cmake/data/bin"/* "$cmake_destdir/bin/"
  rm -rf "$cmake_destdir/share/cmake-$cmake_majmin_ver" "$cmake_destdir/doc/cmake-$cmake_majmin_ver" "$cmake_destdir/doc/cmake"
  mv "$tools_dir/dl/cmake/data/share/cmake-$cmake_majmin_ver" "$cmake_destdir/share/"
  if [ -e "$tools_dir/dl/cmake/data/doc/cmake" ]; then # Windows wheel
    mv "$tools_dir/dl/cmake/data/doc/cmake" "$cmake_destdir/doc/"
  fi
  if [ -e "$tools_dir/dl/cmake/data/doc/cmake-$cmake_majmin_ver" ]; then # Linux wheel
    mv "$tools_dir/dl/cmake/data/doc/cmake-$cmake_majmin_ver" "$cmake_destdir/doc/"
  fi
  set -f
  #   other dirs: aclocal bash-completion emacs vim
  rm -rf "$tools_dir/dl/cmake/data/share"
  #   be pedantic. if we don't know about a directory, it may be important. so error
  #   if some directory is non-empty
  rmdir "$tools_dir/dl/cmake/data/bin" "$tools_dir/dl/cmake/data/doc"
  rmdir "$tools_dir/dl/cmake/data"
fi

# Put tools in PATH
export_cmake_vars
if [ -n "$cmake_bindir" ] && [ -d "$cmake_bindir" ]; then
  tools_bin_dir=$(cd "$cmake_bindir" && pwd)
  export PATH="$tools_bin_dir:$PATH"
else
  echo "This platform is not supported. No cmake 3.25+ download logic has been added" >&2
  exit 1
fi

# Validate
"$cmake_bindir/cmake" --version > /dev/null

# --- Run finder script ---

cd "$PROJ_DIR"
"$cmake_bindir/cmake" \
  -D CMAKE_GENERATOR=Ninja -D CMAKE_MAKE_PROGRAM="$NINJA_EXE" \
  -D "DKTOOL_PWD:FILEPATH=$dk_pwd" \
  -D "DKTOOL_WORKDIR:FILEPATH=$tools_dir/work" -D "DKTOOL_CMDLINE:STRING=$*" \
  -P cmake/FindDkToolScripts.cmake
