# 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-03-17

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-docs")
         "${MINGW_PACKAGE_PREFIX}-rust-src")
pkgver=1.78.0
pkgrel=2
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}-ninja"
             "${MINGW_PACKAGE_PREFIX}-openssl"
             "${MINGW_PACKAGE_PREFIX}-python"
             "${MINGW_PACKAGE_PREFIX}-autotools"
             $([[ "$_bootstrapping" == "no" ]] && echo "${MINGW_PACKAGE_PREFIX}-rust")
             "${MINGW_PACKAGE_PREFIX}-zlib")
source=("${rust_dist_server}/${_realname}c-${pkgver}-src.tar.gz"{,.asc}
        "${embed_manifest_url}"
        "https://github.com/rust-lang/compiler-builtins/commit/d8ab794ed61e2c7c0750f57332a680d5aa8db48c.patch"
        "https://github.com/rust-lang/compiler-builtins/commit/3f47913bc6414bab4254d49f9f6e7238fecace69.patch"
        "0001-rustc-llvm-fix-libs.patch"
        "0005-win32-config.patch"
        "0007-clang-subsystem.patch"
        "0008-disable-self-contained.patch"
        "0011-disable-uac-for-installer.patch"
        "0012-vendor-embed-manifest.patch"
        "0013-backport-compiler-builtins.patch")
noextract=(${_realname}c-${pkgver}-src.tar.gz)
sha256sums=('ff544823a5cb27f2738128577f1e7e00ee8f4c83f2a348781ae4fc355e91d5a9'
            'SKIP'
            '24ef6d949c0b5b1940c1d6a7aad78d86012152fb8845a1644bc939350d7b75e2'
            '0426bc2a82f56ddabc0646100891bc61b9a57f4b7aec9f45aff40d7ba081db4f'
            'b888615732b1c9b0d4e8459cc9bd7ffb8afbf13bab840c2d345dc1492a63c9c3'
            '7cb1773c288ffb1c1e751edc49b1890c84bf9c362742bc5225d19d474edb73a0'
            '7d1c4e49524b835a8eadc961b39f5594b12a522a1e24368999be2c7e85399e4e'
            '46b63be79e4f2d5da2b183ed963429bce22966227bf24a73b158d23875841b11'
            '7a3b5722ff576b0661f36796f088dee4ce318b5dbc3fdcd65b48972de68a0edf'
            '761d73328d9695a7a2bd2a10be8225f4a56801fee54cbb51c0841b7f16e2bde6'
            '23fc45f4e718770375be1c5196f035075de16d25e8f895100a3d1d2492995f86'
            '465cb553e9dbaf176ad7b2e9bf7ebd8e481551cf2e8bbb8ba41c80acb28b3ed1')
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

  cd ${srcdir}/${_realname}c-${pkgver}-src
  apply_patch_with_msg \
    0001-rustc-llvm-fix-libs.patch \
    0005-win32-config.patch \
    0008-disable-self-contained.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

  # backport required for CLANG32 to build with compiler-rt 18.1.0
  (cd vendor/compiler_builtins && \
   apply_patch_with_msg \
     d8ab794ed61e2c7c0750f57332a680d5aa8db48c.patch \
     3f47913bc6414bab4254d49f9f6e7238fecace69.patch)
  # still needs to patch .cargo-checksums.json
  apply_patch_with_msg \
    0013-backport-compiler-builtins.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

  local -a _rust_conf=()
  if [ "${_bootstrapping}" = "no" ]; then
    _rust_conf+=("--local-rust-root=$(cygpath -m ${MINGW_PREFIX})")
  fi
  _rust_conf+=("--enable-vendor")

  if [[ ${CARCH} == i686 ]]; then
    _rust_conf+=("--disable-docs" "--disable-compiler-docs")
  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

  MSYS2_ARG_CONV_EXCL="--prefix;--sysconfdir;--localstatedir" \
  ../${_realname}c-${pkgver}-src/configure \
    --prefix=${MINGW_PREFIX} \
    --sysconfdir=${MINGW_PREFIX}/etc \
    --localstatedir=${MINGW_PREFIX}/var/lib \
    --build=$OSTYPE \
    --host=$OSTYPE \
    --target=$OSTYPE \
    --release-channel=stable \
    --release-description="Rev${pkgrel}, Built by MSYS2 project" \
    --enable-ninja \
    --enable-extended \
    --disable-llvm-static-stdcpp \
    --disable-codegen-tests \
    --set='dist.include-mingw-linker=false' \
    --llvm-root=${MINGW_PREFIX} \
    --python=${MINGW_PREFIX}/bin/python \
    "${_rust_conf[@]}"

  # 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 docs out of the way for splitting
    mv dest-rust/${MINGW_PREFIX}/share/doc dest-doc
  fi

  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")
  optdepends=("${MINGW_PACKAGE_PREFIX}-rust-src: Required for rust-analyzer component")

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

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

  # 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"

  install -d "${srcdir}/${MSYSTEM}/dest-src${MINGW_PREFIX}/lib/rustlib/src"
  mv src/* "${srcdir}/${MSYSTEM}/dest-src${MINGW_PREFIX}/lib/rustlib/src"
}

package_rust-docs() {
  pkgdesc='Documentation for the Rust programming language'
  conflicts=("${MINGW_PACKAGE_PREFIX}-${_realname}<1.52.0")

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

  install -d "$pkgdir"/${MINGW_PREFIX}/share/
  cp -a dest-doc "$pkgdir"/${MINGW_PREFIX}/share/doc
}

package_rust-src() {
  pkgdesc='Source code for the Rust standard library (mingw-w64)'

  cd "${srcdir}/${MSYSTEM}"
  cp -a dest-src/* ${pkgdir}
}

# 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;
