# Maintainer: Alexey Pavlov <alexpux@gmail.com>
# Contributor: Zion Nimchuk <zionnimchuk@gmail.com>
# Contributor: Mateusz Mikuła <mati865@gmail.com
# Contributor: Philippe Renon <philippe_renon@yahoo.fr>

_bootstrapping=yes
if [[ $MINGW_PACKAGE_PREFIX == *-clang-aarch64 ]]; then
  _bootstrapping=no
fi

rust_dist_server=https://static.rust-lang.org/dist
#rust_dist_server=https://dev-static.rust-lang.org/dist/2024-09-03

embed_manifest_version=1.3.1
embed_manifest_url=https://gitlab.com/careyevans/embed-manifest/-/archive/v${embed_manifest_version}/embed-manifest-v${embed_manifest_version}.tar.gz

_realname=rust
pkgbase=mingw-w64-${_realname}
pkgname=("${MINGW_PACKAGE_PREFIX}-${_realname}"
         $([[ ${CARCH} == i686 ]] || echo "${MINGW_PACKAGE_PREFIX}-rust-wasm")
         "${MINGW_PACKAGE_PREFIX}-rust-src")
pkgver=1.81.0
pkgrel=1
pkgdesc="Systems programming language focused on safety, speed and concurrency (mingw-w64)"
arch=('any')
mingw_arch=('mingw32' 'mingw64' 'ucrt64' 'clang64' 'clangarm64' 'clang32')
url="https://www.rust-lang.org/"
msys2_repository_url="https://github.com/rust-lang/rust"
msys2_references=(
  'archlinux: rust'
  "cpe: cpe:/a:rust-lang:rust"
)
license=('spdx:Apache-2.0 AND MIT')
makedepends=("${MINGW_PACKAGE_PREFIX}-cc"
             "${MINGW_PACKAGE_PREFIX}-cmake"
             "${MINGW_PACKAGE_PREFIX}-curl"
             "${MINGW_PACKAGE_PREFIX}-libffi"
             "${MINGW_PACKAGE_PREFIX}-libssh2"
             "${MINGW_PACKAGE_PREFIX}-lldb"
             "${MINGW_PACKAGE_PREFIX}-llvm"
             "${MINGW_PACKAGE_PREFIX}-openssl"
             "${MINGW_PACKAGE_PREFIX}-python"
             "${MINGW_PACKAGE_PREFIX}-autotools"
             $([[ "$_bootstrapping" == "no" ]] && echo "${MINGW_PACKAGE_PREFIX}-rust")
             $([[ ${CARCH} == i686 ]] || echo "${MINGW_PACKAGE_PREFIX}-wasi-libc ${MINGW_PACKAGE_PREFIX}-wasm-component-ld")
             "${MINGW_PACKAGE_PREFIX}-zlib")
source=("${rust_dist_server}/${_realname}c-${pkgver}-src.tar.gz"{,.asc}
        "${embed_manifest_url}"
        "config.toml"
        "0001-rustc-llvm-fix-libs.patch"
        "0004-compiler-Use-wasm-ld-for-wasm-targets.patch"
        "0005-win32-config.patch"
        "0007-clang-subsystem.patch"
        "0008-disable-self-contained-for-gnu-targets.patch"
        "0011-disable-uac-for-installer.patch"
        "0012-vendor-embed-manifest.patch"
        # remove after 1.82.0 release
        "fix-bootstrap-on-windows.patch")
noextract=(${_realname}c-${pkgver}-src.tar.gz)
sha256sums=('872448febdff32e50c3c90a7e15f9bb2db131d13c588fe9071b0ed88837ccfa7'
            'SKIP'
            '24ef6d949c0b5b1940c1d6a7aad78d86012152fb8845a1644bc939350d7b75e2'
            '3254e26a03cbbe23ab77add05a3de8717b9711428330280dc3ee7a2c924d8c3c'
            '7cb1773c288ffb1c1e751edc49b1890c84bf9c362742bc5225d19d474edb73a0'
            '56882f1a0f1404c10c7726d6cc37444f2b343e72b969badfcb43760f80db0f32'
            '7d1c4e49524b835a8eadc961b39f5594b12a522a1e24368999be2c7e85399e4e'
            '87955818066f02e4a39c36a789caf45c524cf4a41f04ee1b0cc685bd5205e63e'
            '98bc3f2bd7371a5b8d14fd7b03bf05574e206d1d9e52bcfbe66d71398504da3c'
            '761d73328d9695a7a2bd2a10be8225f4a56801fee54cbb51c0841b7f16e2bde6'
            '23fc45f4e718770375be1c5196f035075de16d25e8f895100a3d1d2492995f86'
            '0a9800a4f5e833fc435e86457a1b7a41f32d4bd2c1185d1eada90b28bdf6230c')
validpgpkeys=('108F66205EAEB0AAA8DD5E1C85AB96E6FA1BE5FE'  # Rust Language (Tag and Release Signing Key) <rust-key@rust-lang.org>
              '474E22316ABF4785A88C6E8EA2C794A986419D8A'  # Tom Stellard <tstellar@redhat.com>
              'B6C8F98282B944E3B0D5C2530FC3042E345AD05D') # Hans Wennborg <hans@chromium.org>

# hack the bootstrap
_stage0date="2022-08-11"
_stage0version="1.63.0"
if [[ $_bootstrapping != "no" && $MINGW_PACKAGE_PREFIX == *-clang-aarch64 ]]; then
  source+=("https://github.com/mati865/rust-gnullvm-builds/releases/download/${_stage0version}-v2/cargo-${_stage0version}-dev-aarch64-pc-windows-gnullvm.tar.xz"
           "https://github.com/mati865/rust-gnullvm-builds/releases/download/${_stage0version}-v2/rust-std-${_stage0version}-dev-aarch64-pc-windows-gnullvm.tar.xz"
           "https://github.com/mati865/rust-gnullvm-builds/releases/download/${_stage0version}-v2/rustc-${_stage0version}-dev-aarch64-pc-windows-gnullvm.tar.xz")
  noextract+=("cargo-${_stage0version}-dev-aarch64-pc-windows-gnullvm.tar.xz"
              "rust-std-${_stage0version}-dev-aarch64-pc-windows-gnullvm.tar.xz"
              "rustc-${_stage0version}-dev-aarch64-pc-windows-gnullvm.tar.xz")
fi

# =========================================== #
#   Helper macros to help make tasks easier   #
apply_patch_with_msg() {
  for _patch in "$@"
  do
    msg2 "Applying ${_patch}"
    patch -Nbp1 -i "${srcdir}/${_patch}"
  done
}
# =========================================== #

prepare() {
  plain "Extracting ${_realname}c-${pkgver}-src.tar.gz"
  [[ -d ${srcdir}/${_realname}c-${pkgver}-src ]] && rm -rf ${srcdir}/${_realname}c-${pkgver}-src
  tar -xzf ${srcdir}/${_realname}c-${pkgver}-src.tar.gz -C ${srcdir} || true

  # move embed-manifest crate into rust source vendor directory
  mv ${srcdir}/embed-manifest-v${embed_manifest_version} ${srcdir}/${_realname}c-${pkgver}-src/vendor/embed-manifest

  # 0008-disable-self-contained-for-gnu-targets.patch allows self-contained for non-windows-gnu targets
  cd ${srcdir}/${_realname}c-${pkgver}-src
  apply_patch_with_msg \
    0001-rustc-llvm-fix-libs.patch \
    0005-win32-config.patch \
    0008-disable-self-contained-for-gnu-targets.patch

  if [[ $MINGW_PACKAGE_PREFIX == *-clang-i686 || $MINGW_PACKAGE_PREFIX == *-clang-x86_64 ]]; then
    apply_patch_with_msg \
      0007-clang-subsystem.patch
  fi
  if [[ $MINGW_PACKAGE_PREFIX == *-clang-* ]]; then
    apply_patch_with_msg \
      0011-disable-uac-for-installer.patch
  fi
  apply_patch_with_msg \
    0012-vendor-embed-manifest.patch

  if [[ ${CARCH} != i686 ]]; then
    apply_patch_with_msg \
      0004-compiler-Use-wasm-ld-for-wasm-targets.patch
  fi

  # https://github.com/rust-lang/rust/pull/128977
  apply_patch_with_msg \
    fix-bootstrap-on-windows.patch
}

build() {
  mkdir -p "${srcdir}/${MSYSTEM}" && cd "${srcdir}/${MSYSTEM}"

  # The ultimate hack to let the bootstrap compiler use libgcc* libs
  if [[ $_bootstrapping != "no" ]] && [[ $MINGW_PACKAGE_PREFIX == *-clang-i686 || $MINGW_PACKAGE_PREFIX == *-clang-x86_64 ]]; then
    export GCC_LIBS_HACK="$(cygpath -am build/missing-libs-hack)"
    mkdir -p "${GCC_LIBS_HACK}"
    cp "$(cygpath -u $(clang -print-libgcc-file-name))" "${GCC_LIBS_HACK}/libgcc.a"
    cp "${MINGW_PREFIX}/lib/libunwind.a" "${GCC_LIBS_HACK}/libgcc_eh.a"
    cp "${MINGW_PREFIX}/lib/libunwind.dll.a" "${GCC_LIBS_HACK}/libgcc_s.a"
    export RUSTFLAGS_BOOTSTRAP="-C link-arg=-L$(cygpath -am build/missing-libs-hack)"
  fi

  # hack to inject the bootstrap compiler
  if [[ $_bootstrapping != "no" && $MINGW_PACKAGE_PREFIX == *-clang-aarch64 ]]; then
    mkdir -p "build/cache/${_stage0date}/"
    cp -f "${srcdir}/cargo-${_stage0version}-dev-aarch64-pc-windows-gnullvm.tar.xz" \
      "${srcdir}/rust-std-${_stage0version}-dev-aarch64-pc-windows-gnullvm.tar.xz" \
      "${srcdir}/rustc-${_stage0version}-dev-aarch64-pc-windows-gnullvm.tar.xz" \
      "build/cache/${_stage0date}/"
  fi

  if [[ $MINGW_PACKAGE_PREFIX == *-clang-aarch64 ]]; then
    # We have to do the following because rust doesn't count x86_64-w64-mingw32 as a target triple
    OSTYPE="$CARCH-pc-windows-gnullvm"

    # Otherwise it uses gcc during bootstrap, even when we build for clang
    export CARGO_TARGET_${CARCH^^}_PC_WINDOWS_GNULLVM_LINKER="${CC}"
  else
    # We have to do the following because rust doesn't count x86_64-w64-mingw32 as a target triple
    OSTYPE="$CARCH-pc-windows-gnu"

    # Otherwise it uses gcc during bootstrap, even when we build for clang
    export CARGO_TARGET_${CARCH^^}_PC_WINDOWS_GNU_LINKER="${CC}"
  fi

  # avoid OOMing in some cases
  if [[ ${CARCH} == i686 ]]; then
    LDFLAGS+=" -Wl,--large-address-aware"
  elif [[ $MINGW_PACKAGE_PREFIX != *-clang-aarch64 ]]; then
    local _unsupported_options="-march=nocona -msahf"
    # Remove unsupported options for target wasm32-*
    export CFLAGS="${CFLAGS#$_unsupported_options}"

    # Add options back for target $OSTYPE
    export CFLAGS_${OSTYPE//-/_}="$_unsupported_options"
  fi

  # The rust build uses git if it's available but can't handle cygwin git paths
  # so we try to make git not detect any repo with this
  export GIT_DIR=/dev/null

  # For a faster build:
  # - add --disable-docs and --disable-compiler-docs
  # - compile only rustc by removing --enable-extended
  # - run makepkg-mingw with --nocheck
  # - remove --stage 2

  export RUST_BACKTRACE=1

  # substitute the values in config.toml
  local _prefix="$(cygpath -m ${MINGW_PREFIX})"
  cp "${srcdir}/config.toml" "${srcdir}/${_realname}c-${pkgver}-src"
  sed -i -e "s|%PREFIX%|${_prefix}|g" \
         -e "s|%INSTALL_PREFIX%|${MINGW_PREFIX}|g" \
         -e "s|%OSTYPE%|${OSTYPE}|g" \
         -e "s|%PKGREL%|${pkgrel}|g" \
         "${srcdir}/${_realname}c-${pkgver}-src/config.toml"
  if [ "${_bootstrapping}" = "no" ]; then
    sed -i "/^\[build\]/a rustc = \"${_prefix}/bin/rustc.exe\"\ncargo = \"${_prefix}/bin/cargo.exe\"" "${srcdir}/${_realname}c-${pkgver}-src/config.toml"
  fi
  # generate debuginfo only for non-i686 targets
  if check_option "debug" "y" && [ "${CARCH}" != i686 ]; then
    sed -i '/^\[rust\]/a debug = true\ndebuginfo-level-std = 2' "${srcdir}/${_realname}c-${pkgver}-src/config.toml"
  fi

  # Add target wasm32-*
  if [[ ${CARCH} != i686 ]]; then
    sed -i '/target = \[/a\  "wasm32-unknown-unknown", "wasm32-wasip1", "wasm32-wasip1-threads", "wasm32-wasip2",' "${srcdir}/${_realname}c-${pkgver}-src/config.toml"
  fi

  # Building out of tree is not officially supported so we have to workaround some things like vendored deps
  cp -r ../${_realname}c-${pkgver}-src/.cargo .
  sed -i "s|directory = \"vendor\"|directory = \"../${_realname}c-${pkgver}-src/vendor\"|" .cargo/config.toml

  local -a _rust_build=()
  _rust_build+=("--stage" "2")
  #_rust_build+=("--verbose")

  # create the install at a temporary directory
  DEP_NGHTTP_ROOT=${MINGW_PREFIX} \
  DEP_OPENSSL_ROOT=${MINGW_PREFIX} \
  DEP_Z_ROOT=${MINGW_PREFIX} \
  DESTDIR="$PWD"/dest-rust ${MINGW_PREFIX}/bin/python ../${_realname}c-${pkgver}-src/x.py install "${_rust_build[@]}"

  if [[ ${CARCH} != i686 ]]; then
    # move wasm32-* targets out of the way for splitting
    mkdir -p dest-wasm/${MINGW_PREFIX}/lib/rustlib
    mv dest-rust/${MINGW_PREFIX}/lib/rustlib/wasm32-* dest-wasm/${MINGW_PREFIX}/lib/rustlib
  fi

  # move src out of the way for splitting
  mv dest-rust/${MINGW_PREFIX}/lib/rustlib/src dest-src

  rm -f dest-rust/${MINGW_PREFIX}/lib/rustlib/$OSTYPE/lib/self-contained/*
}

check() {
  cd "${srcdir}/${MSYSTEM}"
  DEP_NGHTTP_ROOT=${MINGW_PREFIX} \
  DEP_OPENSSL_ROOT=${MINGW_PREFIX} \
  DEP_Z_ROOT=${MINGW_PREFIX} \
  ${MINGW_PREFIX}/bin/python ../${_realname}c-${pkgver}-src/x.py test --stage 2 --exclude src/test/debuginfo
}

package_rust() {
  depends=("${MINGW_PACKAGE_PREFIX}-cc"
           "${MINGW_PACKAGE_PREFIX}-curl"
           "${MINGW_PACKAGE_PREFIX}-libxml2"
           "${MINGW_PACKAGE_PREFIX}-libssh2")
  conflicts=("${MINGW_PACKAGE_PREFIX}-rust-docs")
  replaces=("${MINGW_PACKAGE_PREFIX}-rust-docs")

  cd "${srcdir}/${MSYSTEM}"

  cp -a dest-rust/* "$pkgdir"

  # delete unnecessary files, e.g. components and manifest files only used for the uninstall script
  cd "$pkgdir"/${MINGW_PREFIX}/lib/rustlib
  rm components install.log manifest-* rust-installer-version uninstall.sh

  install -d "$pkgdir/${MINGW_PREFIX}/share/bash-completion/completions"
  mv "${pkgdir}${MINGW_PREFIX}/etc/bash_completion.d/cargo" \
     "${pkgdir}${MINGW_PREFIX}/share/bash-completion/completions/cargo"
}

package_rust-wasm() {
  pkgdesc="WebAssembly targets for Rust"
  depends=("${MINGW_PACKAGE_PREFIX}-lld"
           "${MINGW_PACKAGE_PREFIX}-rust"
           "${MINGW_PACKAGE_PREFIX}-wasm-component-ld")
  # object files provided for wasm32-* targets can't be stripped with MSYS2 toolchain
  options=('!strip')

  cd "${srcdir}/${MSYSTEM}"

  cp -a dest-wasm/* "$pkgdir"
  install -Dm644 "${srcdir}"/${_realname}c-${pkgver}-src/LICENSE-APACHE "${pkgdir}${MINGW_PREFIX}/share/licenses/${_realname}-wasm/LICENSE-APACHE"
  install -Dm644 "${srcdir}"/${_realname}c-${pkgver}-src/LICENSE-MIT "${pkgdir}${MINGW_PREFIX}/share/licenses/${_realname}-wasm/LICENSE-MIT"
}

package_rust-src() {
  pkgdesc='Source code for the Rust standard library (mingw-w64)'
  depends=("${MINGW_PACKAGE_PREFIX}-rust")

  cd "${srcdir}/${MSYSTEM}"
  install -Dm644 "${srcdir}"/${_realname}c-${pkgver}-src/LICENSE-APACHE "${pkgdir}${MINGW_PREFIX}/share/licenses/${_realname}-src/LICENSE-APACHE"
  install -Dm644 "${srcdir}"/${_realname}c-${pkgver}-src/LICENSE-MIT "${pkgdir}${MINGW_PREFIX}/share/licenses/${_realname}-src/LICENSE-MIT"

  install -d "${pkgdir}${MINGW_PREFIX}/lib/rustlib/"
  cp -a dest-src "${pkgdir}${MINGW_PREFIX}/lib/rustlib/src"
}

# template start; name=mingw-w64-splitpkg-wrappers; version=1.0;
# vim: set ft=bash :

# generate wrappers
for _name in "${pkgname[@]}"; do
  _short="package_${_name#${MINGW_PACKAGE_PREFIX}-}"
  _func="$(declare -f "${_short}")"
  eval "${_func/#${_short}/package_${_name}}"
done
# template end;
