# Contributor: Oleg A. Khlybov <fougas@mail.ru>

# The supplementary `petsc-build` package contains the distilled PETSc build tree
# required at compile time by some packages (such as SLEPc).
# Regular users should use the `petsc` package.

# This package provides multiple library build flavors differentiated by
# the 3-character suffix XYZ as follows:
#
#  * X is the scalar type based on the Netlib's SDCZ notation:
#    - A for multiprecision or precision-neutral build
#    - S for single precision real
#    - D for double precision real
#    - C for single precision complex
#    - Z for double precision complex
#
#  * Y is the execution model:
#    - S for sequential code
#    - M for MPI parallel code
#    - T for multithreaded code, either bare threading or OpenMP, OpenACC etc.
#    - H for heterogeneous code with CUDA, OpenCL etc.
#
#  * Z is the build type:
#    - O for optimized build
#    - G for debugging build
#
# The suffix is used in the static and dynamic libraires as well as in PkgConfig .pc files.
# That is the ZMO suffix designates the optimized MPI parallel double precision complex library flavor.
# Consider the `pkg-config petsc-zmo --cflags` command to obtain the build-specific compilation flags.


_realname=petsc
pkgbase=mingw-w64-${_realname}
pkgname=("${MINGW_PACKAGE_PREFIX}-${_realname}" "${MINGW_PACKAGE_PREFIX}-${_realname}-build")
pkgver=3.22.0
pkgrel=2
pkgdesc='Sparse iterative (non)linear solver package (mingw-w64)'
arch=('any')
mingw_arch=('mingw64' 'ucrt64' 'clang64' 'clangarm64')
url="https://www.mcs.anl.gov/petsc/"
msys2_repository_url="https://gitlab.com/petsc/petsc"
msys2_references=(
  'aur: petsc'
)
license=('spdx:BSD-2-Clause')
depends=("${MINGW_PACKAGE_PREFIX}-gcc-libs"
         $([[ ${MINGW_PACKAGE_PREFIX} == *-clang-* ]] || echo "${MINGW_PACKAGE_PREFIX}-gcc-libgfortran")
         "${MINGW_PACKAGE_PREFIX}-hwloc"
         "${MINGW_PACKAGE_PREFIX}-metis"
         $([[ ${CARCH} == aarch64 ]] || echo "${MINGW_PACKAGE_PREFIX}-parmetis")
         "${MINGW_PACKAGE_PREFIX}-omp"
         "${MINGW_PACKAGE_PREFIX}-openblas")
makedepends=('python'
             "${MINGW_PACKAGE_PREFIX}-cc"
             $([[ ${CARCH} == aarch64 ]] || echo "${MINGW_PACKAGE_PREFIX}-msmpi")
             $([[ ${MINGW_PACKAGE_PREFIX} == *-clang-* ]] || echo "${MINGW_PACKAGE_PREFIX}-fc"))
optdepends=("${MINGW_PACKAGE_PREFIX}-tcl: build & run test suite")
source=("https://web.cels.anl.gov/projects/petsc/download/release-snapshots/${_realname}-lite-${pkgver}.tar.gz"
        'all.tcl'
        'tclbuildtest.tcl'
        'petsc.test'
        'petsc-mat.test'
        '0001-mpi-detection-override.patch'
        '0002-openblas-clang.patch'
        '0003-pid.patch'
        '0004-set_output_format.patch'
        '0005-with-pthread.patch')
noextract=("${_realname}-lite-${pkgver}.tar.gz")
sha256sums=('2c03f7c0f7ad2649240d4989355cf7fb7f211b75156cd7d424e1d9dd7dfb290b'
            'ec5072630e1c0309fe383669e9187790cd135a393c67bc4bc35cf60b0ba396ff'
            '15c7af25b91406d5fe5f26cfe00963b6cfde1c3dd466eb25f1b6fae299934966'
            '7d171b2680211b0a4d305dfb866faf5c995e47d0ecf619d33f1cce3190c32128'
            'b1c9c4c4155d10bcf12c5c512df34cd6a781c4c81f6edbc8e331f49c7e10a1f7'
            'bef5353d6d10de492c9832f24b41993c38d1b36a78eb55e7d49089ba72acc05a'
            'c954cc4240a6f3cebdc40cf4fca07561e58eb50717b9741c296b73657bac1c51'
            '08d37a205d7a2ae27ccef41ee931f92c96aa428b94ed633def2f56fdfa6fb11e'
            '254405c6c0eb5aa57b1cb74bbaf8876bcdb67d63136102e48a8036824bb9f129'
            'bd7d1fa888d24f5183de992fb9377a4532cd9f38c5608018f5cd82f61e3096e9')

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

prepare() {
  mkdir -p "${srcdir}"/build-${MSYSTEM} && cd "${srcdir}"/build-${MSYSTEM}
  tar xzf $srcdir/${_realname}-lite-${pkgver}.tar.gz

  cd ${_realname}-${pkgver}
  apply_patch_with_msg \
    0001-mpi-detection-override.patch \
    0002-openblas-clang.patch \
    0003-pid.patch \
    0004-set_output_format.patch \
    0005-with-pthread.patch
}

# Optimized build flavors
builds='dso dto zso zto sso sto cso cto'
if [[ ${CARCH} != aarch64 ]]; then
  builds+=' dmo zmo smo cmo'
fi

# Additional debugging build flavors, disabled by default due to huge library sizes
# builds="$builds dsg dtg dmg zsg ztg zmg ssg stg smg csg ctg cmg"

_petsc() {
  desc=
  opts="--with-single-library=1 --disable-shared --with-cxx=0 --with-windows-graphics=0 --with-x=0 --with-hwloc=1 --with-openblas=1 --with-openblas-dir=$MINGW_PREFIX"
  pc="hwloc openblas"
  iflags=
  cflags="$CFLAGS"
  cxxflags="$CXXFLAGS"
  fflags="$CFLAGS -I$MINGW_PREFIX/include"
  cppflags="$CPPFLAGS"
  ldflags="$LDFLAGS"
  pc_libs="$LIBS"
  libs="$LIBS"
  ld="$CXX"
  if [[ ${MINGW_PACKAGE_PREFIX} != *-clang-* ]]; then
    fflags+=" -fallow-invalid-boz -fallow-argument-mismatch"
    libs+=" -lgfortran -lquadmath"
    pc_libs="$libs"
  else
  # elif [[ ${MSYSTEM} == CLANG32 ]]; then
    opts+=" --with-fc=0"
  # else
  #   opts+=" --with-fc=${MINGW_PREFIX}/bin/flang"
  #   libs+=" -lFortranRuntime -lFortranDecimal"
  # fi
  # if [[ ${MINGW_PACKAGE_PREFIX} == *-clang-* ]]; then
    cflags+=" -Wno-incompatible-function-pointer-types"
  fi
  case $1 in
    ?m?)
      opts+=" --with-mpi=1 --with-mpi-compilers=0 --with-pthread=0 --with-openmp=0 --with-metis=1 --with-parmetis=1"
      pc+=" parmetis msmpi"
      libs+=" -lmsmpi"
      # pc_libs is not augmented because MPI is provided by the PkgConfig
      desc="MPI parallel"
    ;;
    ?t?)
      opts+=" --with-mpi=0 --with-pthread=0 --with-openmp=1"
      iflags="$iflags -I\${includedir}/mpiuni"
      ldflags+=" -fopenmp"
      desc="OpenMP multithreaded"
    ;;
    ?s?)
      opts+=" --with-mpi=0 --with-pthread=0 --with-openmp=0"
      iflags+=" -I\${includedir}/mpiuni"
      desc="Sequential"
    ;;
  esac
  case $1 in
    z*|d*)
      opts+=" --with-precision=double"
      desc+=" double precision"
    ;;
    c*|s*)
      opts+=" --with-precision=single"
      desc+=" single precision"
    ;;
  esac
  case $1 in
    d*|s*)
      opts+=" --with-scalar-type=real"
    ;;
    z*|c*)
      opts+=" --with-scalar-type=complex"
      desc+=" complex"
    ;;
  esac
  case $1 in
    *o)
      opts+=" --with-debugging=0"
    ;;
    *g)
      opts+=" --with-debugging=1"
      debug="-g -Og"
      cflags+=" $debug"
      cxxflags+=" $debug"
      fflags+=" $debug"
    ;;
  esac
}

build() {
  cd  "${srcdir}/build-${MSYSTEM}/${_realname}-${pkgver}"
  if [[ ${MINGW_PACKAGE_PREFIX} != *-clang-* ]]; then
    export FC=gfortran
  # else
  #   export FC=${MINGW_PREFIX}/bin/flang.exe
  fi
  for build in ${builds}; do
    _petsc ${build}
    export PETSC_DIR=`pwd`
    /usr/bin/python configure --PETSC_ARCH=${build} ${opts} CC="$CC" CXX="$CXX" FC="$FC" CFLAGS="$cflags" FFLAGS="$fflags" CXXFLAGS="$cxxflags" CPPFLAGS="$cppflags" LDFLAGS="$ldflags" LIBS="$libs" MAKEFLAGS="$MAKEFLAGS"
    make PETSC_ARCH=${build} all
    (
      cd ${build}/lib
      case ${build} in
        *o) strip -S *.a ;;
      esac
      ${ld} -shared -Wl,--enable-auto-import -Wl,--export-all-symbols -o lib${_realname}-${build}.dll -Wl,--out-implib,lib${_realname}.dll.a -Wl,--whole-archive lib${_realname}.a -Wl,--no-whole-archive ${ldflags} ${libs} $(pkg-config ${pc} --libs)
    )
  done
}

eval "package_${MINGW_PACKAGE_PREFIX}-${_realname}() { _package; }"
eval "package_${MINGW_PACKAGE_PREFIX}-${_realname}-build() { _package_build; }"

_package() {
  cd ${srcdir}/build-${MSYSTEM}/${_realname}-${pkgver}
  mkdir -p ${pkgdir}${MINGW_PREFIX}/{bin,lib/pkgconfig,lib/${_realname},include/${_realname},share/test/${_realname}/{ksp,mat}}
  (
    cd include
    cp *.h ${pkgdir}${MINGW_PREFIX}/include/${_realname}
    cd ${_realname}
    cp -R finclude mpiuni private ${pkgdir}${MINGW_PREFIX}/include/${_realname}
    cd ${pkgdir}${MINGW_PREFIX}/include/${_realname}
    find . \( ! -name '*.h' -a -type f \) -delete
  )
  (
    cd ${srcdir}
    cp {all,tclbuildtest}.tcl {petsc,petsc-mat}.test ${pkgdir}${MINGW_PREFIX}/share/test/${_realname}
  )
  (
    cd src/ksp/ksp/tutorials
    cp ex1.c ex2.c ex1f.F90 ex2f.F90 ${pkgdir}${MINGW_PREFIX}/share/test/${_realname}/ksp
  )
  (
    cd src/mat/tutorials
    cp ex15.c ex15f.F90 ${pkgdir}${MINGW_PREFIX}/share/test/${_realname}/mat
  )
  for build in ${builds}; do
    _petsc ${build}
    (
      cd ${build}/lib
      mkdir -p ${pkgdir}${MINGW_PREFIX}/lib/${_realname}/${build}
      cp *.a ${pkgdir}${MINGW_PREFIX}/lib/${_realname}/${build}
      cp *.dll ${pkgdir}${MINGW_PREFIX}/bin
    )
    (
      cd ${build}/include
      mkdir -p ${pkgdir}${MINGW_PREFIX}/include/${_realname}/${build}
      cp *.h ${pkgdir}${MINGW_PREFIX}/include/${_realname}/${build}
      if [[ ${MINGW_PACKAGE_PREFIX} != *-clang-* ]]; then
        cp *.mod ${pkgdir}${MINGW_PREFIX}/include/${_realname}/${build}
      fi
    )
    echo "
      prefix=${MINGW_PREFIX}
      libdir=\${prefix}/lib/${_realname}
      includedir=\${prefix}/include/${_realname}
      Name: ${_realname}
      URL: ${url}
      Version: ${pkgver}
      Description: ${desc} PETSc build
      Requires.private: ${pc}
      Cflags: -I\${includedir}/${build} -I\${includedir} ${iflags}
      Libs.private: -L\${libdir}/${build} -l${_realname} ${ldflags} ${pc_libs}
      Libs: -L\${libdir}/${build} -l${_realname}
    " | sed '/^\s*$/d;s/^\s*//' > ${pkgdir}${MINGW_PREFIX}/lib/pkgconfig/${_realname}-${build}.pc
  done
}

_package_build() {
  mkdir -p ${pkgdir}${MINGW_PREFIX}/src
  cd ${srcdir}/build-${MSYSTEM}
  cp -R ${_realname}-${pkgver} ${pkgdir}${MINGW_PREFIX}/src
  cd ${pkgdir}${MINGW_PREFIX}/src
  mv ${_realname}-${pkgver} ${_realname}
  find . -regextype posix-extended \( -regex '.*\.(o|dll|log|DIR)$' -or -regex '.*/__pycache__' \) -exec rm -rf {} +
  for build in ${builds}; do
    find . -regextype posix-extended -regex ".*$build/(bin|obj|tests)" -exec rm -rf {} +
    si=${MINGW_PREFIX}/src/${_realname}/include
    sb=${MINGW_PREFIX}/src/${_realname}/${build}/include
    pi=${MINGW_PREFIX}/include/petsc
    pb=${MINGW_PREFIX}/include/petsc/${build}
    sed -r -i \
      -e "s%(PETSC_(C|F)C_INCLUDES)[[:space:]]+.*$%\\1 = -I${sb} -I${si}%" \
      -e "s%(PETSC_(C|F)C_INCLUDES_INSTALL)[[:space:]]+.*$%\\1 = -I${pb} -I${pi}%" \
      -e "s%(wPETSC_DIR)[[:space:]]+.*$%\\1 = ${MINGW_PREFIX}/src/${_realname}%" \
      -e "s%(PREFIXDIR)[[:space:]]+.*$%\\1 = ${MINGW_PREFIX}/src/${_realname}/${build}%" \
      -e "/^PETSC_WITH_EXTERNAL_LIB/s%${srcdir}/build-${MSYSTEM}/${_realname}-${pkgver}%${MINGW_PREFIX}/src/${_realname}%g" \
      ${_realname}/${build}/lib/petsc/conf/petscvariables
  done
  echo "
    petsc_pkgver=${pkgver}
    petsc_builds=\"${builds}\"
  " | sed '/^\s*$/d;s/^\s*//' > ${_realname}/petsc
}
