File ghc-hashable.spec of Package ghc-hashable
#
# spec file for package ghc-hashable
#
# Copyright (c) 2024 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
# upon. The license for this file, and modifications and additions to the
# file, is the same license as for the pristine package itself (unless the
# license for the pristine package is not an Open Source License, in which
# case the license is the MIT License). An "Open Source License" is a
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.
# Please submit bugfixes or comments via https://bugs.opensuse.org/
#
%global pkg_name hashable
%global pkgver %{pkg_name}-%{version}
%bcond_with tests
Name:           ghc-%{pkg_name}
Version:        1.5.0.0
Release:        0
Summary:        A class for types that can be converted to a hash value
License:        BSD-3-Clause
URL:            https://hackage.haskell.org/package/%{pkg_name}
Source0:        https://hackage.haskell.org/package/%{pkg_name}-%{version}/%{pkg_name}-%{version}.tar.gz
Source1:        https://hackage.haskell.org/package/%{pkg_name}-%{version}/revision/1.cabal#/%{pkg_name}.cabal
BuildRequires:  ghc-Cabal-devel
BuildRequires:  ghc-base-devel
BuildRequires:  ghc-base-prof
BuildRequires:  ghc-bytestring-devel
BuildRequires:  ghc-bytestring-prof
BuildRequires:  ghc-containers-devel
BuildRequires:  ghc-containers-prof
BuildRequires:  ghc-deepseq-devel
BuildRequires:  ghc-deepseq-prof
BuildRequires:  ghc-filepath-devel
BuildRequires:  ghc-filepath-prof
BuildRequires:  ghc-os-string-devel
BuildRequires:  ghc-os-string-prof
BuildRequires:  ghc-rpm-macros
BuildRequires:  ghc-text-devel
BuildRequires:  ghc-text-prof
ExcludeArch:    %{ix86}
%if %{with tests}
BuildRequires:  ghc-HUnit-devel
BuildRequires:  ghc-HUnit-prof
BuildRequires:  ghc-QuickCheck-devel
BuildRequires:  ghc-QuickCheck-prof
BuildRequires:  ghc-primitive-devel
BuildRequires:  ghc-primitive-prof
BuildRequires:  ghc-random-devel
BuildRequires:  ghc-random-prof
BuildRequires:  ghc-tasty-devel
BuildRequires:  ghc-tasty-hunit-devel
BuildRequires:  ghc-tasty-hunit-prof
BuildRequires:  ghc-tasty-prof
BuildRequires:  ghc-tasty-quickcheck-devel
BuildRequires:  ghc-tasty-quickcheck-prof
BuildRequires:  ghc-unix-devel
BuildRequires:  ghc-unix-prof
%endif
%description
This package defines a class, '\'Hashable\'', for types that can be converted to a
hash value. This class exists for the benefit of hashing-based data structures.
The package provides instances for basic types and a way to combine hash
values.
'Hashable' is intended exclusively for use in in-memory data structures.
'Hashable' does /not/ have a fixed standard. This allows it to improve over
time.
Because it does not have a fixed standard, different computers or computers on
different versions of the code will observe different hash values. As such,
'Hashable' is not recommended for use other than in-memory datastructures.
Specifically, 'hashable' is not intended for network use or in applications
which persist hashed values. For stable hashing use named hashes: sha256,
crc32, xxhash etc.
%package devel
Summary:        Haskell %{pkg_name} library development files
Requires:       %{name} = %{version}-%{release}
Requires:       ghc-compiler = %{ghc_version}
Requires(post): ghc-compiler = %{ghc_version}
Requires(postun): ghc-compiler = %{ghc_version}
%description devel
This package provides the Haskell %{pkg_name} library development files.
%package -n ghc-%{pkg_name}-doc
Summary:        Haskell %{pkg_name} library documentation
Requires:       ghc-filesystem
BuildArch:      noarch
%description -n ghc-%{pkg_name}-doc
This package provides the Haskell %{pkg_name} library documentation.
%package -n ghc-%{pkg_name}-prof
Summary:        Haskell %{pkg_name} profiling library
Requires:       ghc-%{pkg_name}-devel = %{version}-%{release}
Supplements:    (ghc-%{pkg_name}-devel and ghc-prof)
%description -n ghc-%{pkg_name}-prof
This package provides the Haskell %{pkg_name} profiling library.
%prep
%autosetup -n %{pkg_name}-%{version}
cp -p %{SOURCE1} %{pkg_name}.cabal
# Ensure Setup.hs is not compiled into a native Setup binary which would
# bypass our argument filtering. We rename the original Setup.hs/Setup.lhs
# and provide a small wrapper named "Setup" which delegates to runhaskell
# on the original source while sanitizing --ghc-options and removing
# -fobject-determinism tokens. Doing this in %prep guarantees the wrapper
# is present early and prevents rpmbuild from compiling Setup into an
# executable that would ignore our filtering.
if [ -f Setup.hs ]; then
  mv -f Setup.hs Setup.hs.orig || true
fi
if [ -f Setup.lhs ]; then
  mv -f Setup.lhs Setup.lhs.orig || true
fi
cat > Setup <<'EOF'
#!/bin/sh
# Minimal Setup wrapper created by package spec to sanitize GHC options.
newargs=""
for a in "$@"; do
  case "$a" in
    --ghc-options=*)
      val=${a#--ghc-options=}
      # remove occurrences of -fobject-determinism from the option value
      val=$(printf '%s' "$val" | sed -E 's/(^|[[:space:]])-fobject-determinism([[:space:]]|$)/ /g' | sed -E 's/^[[:space:]]+|[[:space:]]+$//g')
      if [ -n "$val" ]; then
        newargs="$newargs --ghc-options=$val"
      fi
      ;;
    *-fobject-determinism*)
      # drop any standalone occurrences
      ;;
    *)
      newargs="$newargs \"$a\""
      ;;
  esac
done
# Prefer to run the original Setup source using runhaskell
if [ -f Setup.hs.orig ]; then
  # shellcheck disable=SC2086
  eval exec runhaskell Setup.hs.orig $newargs
elif [ -f Setup.lhs.orig ]; then
  # shellcheck disable=SC2086
  eval exec runhaskell Setup.lhs.orig $newargs
else
  # Fallback: if a compiled Setup.real exists, use it
  if [ -x ./Setup.real ]; then
    # shellcheck disable=SC2086
    eval exec ./Setup.real $newargs
  else
    # fallback to system Setup if present
    # shellcheck disable=SC2086
    eval exec Setup $newargs
  fi
fi
EOF
chmod +x Setup
%build
%define cabal_configure_options -f-arch-native
# Some ghc installations (notably on aarch64) may not recognize
# the -fobject-determinism flag. The standard %ghc_lib_build macro
# injects that flag; to avoid build failure we wrap the Setup executable
# to filter out --ghc-options and any occurrence of -fobject-determinism
# from the arguments passed to it. This is a minimal, local workaround.
mkdir -p ghc-wrap
cat > ghc-wrap/ghc <<'EOF'
#!/bin/sh
# Robust wrapper to filter out -fobject-determinism which some GHCs do not accept
TARGET_DIR="$(pwd)/ghc-wrap"
# Build a PATH without our wrapper dir to discover the real ghc
PATH_NO_WRAP="$(echo "$PATH" | sed -e "s#${TARGET_DIR}:##g")"
me=$(basename "$0")
REAL_GHC=""
# Prefer to find a real binary with the same basename as the wrapper
IFS=:
for d in $PATH_NO_WRAP; do
  if [ -x "$d/$me" ] && [ "$d/$me" != "$TARGET_DIR/$me" ]; then
    REAL_GHC="$d/$me"
    break
  fi
done
unset IFS
# Fallback: try to find standard ghc or any ghc-* candidate
if [ -z "$REAL_GHC" ]; then
  for cand in $(which -a "$me" 2>/dev/null || true); do
    if [ -x "$cand" ] && [ "$cand" != "$TARGET_DIR/$me" ]; then
      REAL_GHC="$cand"
      break
    fi
  done
fi
if [ -z "$REAL_GHC" ]; then
  for cand in $(which -a ghc 2>/dev/null || command -v ghc 2>/dev/null || true); do
    if [ -x "$cand" ] && [ "$cand" != "$TARGET_DIR/ghc" ]; then
      REAL_GHC="$cand"
      break
    fi
  done
fi
# Final fallback: use command -v (may still point to wrapper, but best effort)
if [ -z "$REAL_GHC" ]; then
  REAL_GHC="$(command -v "$me" 2>/dev/null || command -v ghc 2>/dev/null || true)"
fi
# If no real ghc found, exec default ghc (will likely error)
if [ -z "$REAL_GHC" ]; then
  exec ghc "$@"
fi
# Build new argument list with -fobject-determinism removed, handling key=value forms
newargs=""
for a in "$@"; do
  case "$a" in
    *-fobject-determinism*)
      case "$a" in
        *=*)
          key=${a%%=*}
          val=${a#*=}
          newval=$(printf '%s' "$val" | sed -E 's/(^|[[:space:]])-fobject-determinism([[:space:]]|$)/ /g' | sed -E 's/^[[:space:]]+|[[:space:]]+$//g')
          if [ -n "$newval" ]; then
            newargs="$newargs \"$key=$newval\""
          fi
          ;;
        *)
          newarg=$(printf '%s' "$a" | sed 's/-fobject-determinism//g; s/  / /g; s/^ //; s/ $//')
          if [ -n "$newarg" ]; then
            newargs="$newargs \"$newarg\""
          fi
          ;;
      esac
      ;;
    *)
      newargs="$newargs \"$a\""
      ;;
  esac
done
# Create symlinks for ghc* found in PATH_NO_WRAP so calls to ghc-<ver>
# are also intercepted by our wrapper.
for d in $(echo "$PATH_NO_WRAP" | tr ':' ' '); do
  for p in "$d"/ghc*; do
    if [ -x "$p" ]; then
      base=$(basename "$p")
      if [ ! -e "$TARGET_DIR/$base" ]; then
        (cd "$TARGET_DIR" && ln -s ghc "$base") || true
      fi
    fi
  done
done
# Also create symlinks for common system locations in case rpmbuild calls
# a fully-versioned ghc binary (e.g. ghc-9.10.2) not covered by PATH scanning.
for p in /usr/bin/ghc* /usr/local/bin/ghc* /usr/lib*/ghc*/bin/ghc*; do
  if [ -x "$p" ]; then
    base=$(basename "$p")
    if [ ! -e "$TARGET_DIR/$base" ]; then
      (cd "$TARGET_DIR" && ln -s ghc "$base") || true
    fi
  fi
done
# shellcheck disable=SC2086
eval exec "$REAL_GHC" $newargs
EOF
chmod +x ghc-wrap/ghc
# place wrapper at front of PATH for the duration of build
PATH="$(pwd)/ghc-wrap:$PATH"
export PATH
# compile Setup (best-effort, some environments already have Setup)
ghc --make -package Cabal -no-user-package-db -dynamic Setup || true
# Replace the compiled Setup executable with a small argument-filtering wrapper
# so that any --ghc-options or -fobject-determinism passed on the command line
# are removed before invoking the real Setup binary.
if [ -x ./Setup ]; then
  mv -f Setup Setup.real || true
  cat > Setup <<'EOF'
#!/bin/sh
# Wrapper to filter out --ghc-options and -fobject-determinism
newargs=""
for a in "$@"; do
  case "$a" in
    --ghc-options=*)
      val=${a#--ghc-options=}
      # remove occurrences of -fobject-determinism from the option value
      val=$(printf '%s' "$val" | sed -E "s/(^|[[:space:]])-fobject-determinism([[:space:]]|$)/ /g" | sed -E 's/^[[:space:]]+|[[:space:]]+$//g')
      if [ -n "$val" ]; then
        newargs="$newargs --ghc-options=$val"
      fi
      ;;
    *-fobject-determinism*)
      # drop any standalone occurrences
      ;;
    *)
      newargs="$newargs \"$a\""
      ;;
  esac
done
# shellcheck disable=SC2086
eval exec "./Setup.real" $newargs
EOF
  chmod +x Setup
fi
# run configure without the problematic --ghc-options global flag (explicitly override it to empty)
LANG=C.utf8 ./Setup configure --prefix=/usr --libdir=/usr/lib64 --docdir=/usr/share/licenses/ghc-hashable '--libsubdir=$compiler/lib/$pkgid' '--datasubdir=$pkgid' '--libexecsubdir=$pkgid' --ghc --dynlibdir=/usr/lib64/ghc-9.10.2/lib --ghc-options='' -f-arch-native --enable-library-profiling --enable-shared --htmldir=/usr/share/doc/packages/ghc-9.10.2/html/libraries/hashable-1.5.0.0 --global
# build using Setup
LANG=C.utf8 ./Setup build
%install
%ghc_lib_install
%check
%cabal_test
%post devel
%ghc_pkg_recache
%postun devel
%ghc_pkg_recache
%files -f %{name}.files
%license LICENSE
%files devel -f %{name}-devel.files
%doc CHANGES.md README.md
%files -n ghc-%{pkg_name}-doc -f ghc-%{pkg_name}-doc.files
%license LICENSE
%files -n ghc-%{pkg_name}-prof -f ghc-%{pkg_name}-prof.files
%changelog