# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4

PortSystem          1.0
PortGroup           gpg_verify 1.0
PortGroup           compiler_blacklist_versions 1.0
PortGroup           legacysupport 1.1

name                ghc
version             9.12.2
revision            0
categories          lang haskell
maintainers         {ieee.org:s.t.smith @essandess} openmaintainer
license             BSD
platforms           darwin

description         The Glorious Glasgow Haskell Compilation System
long_description    The Glasgow Haskell Compiler is a robust, \
                    fully-featured, optimising compiler and \
                    interactive environment for Haskell 98, GHC \
                    compiles Haskell to either native code or C.  It \
                    implements numerous experimental language \
                    extensions to Haskell 98, for example: \
                    concurrency, a foreign language interface, \
                    multi-parameter type classes, scoped type \
                    variables, existential and universal \
                    quantification, unboxed types, exceptions, weak \
                    pointers, and so on.  GHC comes with a \
                    generational garbage collector, and a space and \
                    time profiler.

homepage            https://haskell.org/${name}

# https://gitlab.haskell.org/ghc/ghc/-/wikis/building/hadrian
# https://www.haskell.org/ghc/blog/20220805-make-to-hadrian.html

use_xz              yes
master_sites        https://downloads.haskell.org/~${name}/${version}

platform arm {
    set ghc_build_arch  aarch64
}
platform i386 {
    set ghc_build_arch  x86_64
}
platform powerpc {
    set ghc_build_arch  ppc
}

if {${os.arch} ni [list arm i386]} {
    known_fail      yes
    pre-fetch {
        ui_error "GHC is only available on macOS \
            with [join ${supported_archs} " or "] architectures."
        error {unsupported platform}
    }
}

set ghc_version     ${version}
set ghc_distname    ${distname}-${ghc_build_arch}-apple-darwin

# set build_arch by hand on arm64/x86_64 systems to get x86_64/arm64 checksums
# sudo port -d checksum ghc-prebuilt os.arch=arm build_arch=arm64
# sudo port -d checksum ghc-prebuilt os.arch=i386 build_arch=x86_64
# run `port clean --all ghc-prebuilt` afterwards
if {${build_arch} eq {arm64}} {
    checksums       ${ghc_distname}${extract.suffix} \
                    rmd160  7ca5c3377749cda9ea431ce03ad794dfb25ed574 \
                    sha256  4b61b933028c63ace950236ea3382d02e51a3d9cbd1ca3f6cf4fe14c71ff436c \
                    size    306760740
} elseif {${build_arch} eq {x86_64}} {
    checksums       ${ghc_distname}${extract.suffix} \
                    rmd160  e840d1a1a97b096459ce5f50ee9687fadcf1f7cf \
                    sha256  e7a40e39059dd3619d7884b7382f357e79a0f4e430181b805bdd57b3be9a7300 \
                    size    310907744
}
set ghc_source_checksums [list \
                    ${distname}-src${extract.suffix} \
                    rmd160  11d8a5f76773d355c868c6292167d2ae38279e57 \
                    sha256  0e49cd5dde43f348c5716e5de9a5d7a0f8d68d945dc41cf75dfdefe65084f933 \
                    size    33394536 \
                    ]
set ghc_testsuite_checksums [list \
                    ${distname}-testsuite${extract.suffix} \
                    rmd160  bd9105298f8e13ba977af4dd45b558229ac331e6 \
                    sha256  cf142eadb4ff9b84ba49c01f52813acbeb742d57b21e64c46424563e0bf410aa \
                    size    7785840 \
                    ]

# Has issues if enabled
configure.ccache    no

# gpg --list-packets ${distfiles}/${distname}-src${extract.suffix}.sig
# https://pgp.mit.edu/pks/lookup?op=get&search=0x2DE04D4E97DB64AD
set gpg_keyid       2DE04D4E97DB64AD

# relative paths to ${prefix}
set ghc_libdir ${prefix}/lib/${name}-${version}

# LlvmMaxVersion=20 from ./configure.ac; must be less than actual llvm version
set ghc_llvm_version  19

if {${name} eq ${subport}} {
    PortGroup       haskell_cabal 1.0

    haskell_cabal.use_prebuilt  yes

    haskell_cabal.env \
                    "CABAL_CONFIG=${haskell_cabal.cabal_root}/config" \
                    "GHC=${haskell_cabal.cabal_root}/bin/ghc" \
                    "LD=${prefix}/bin/ld" \
                    "LLC=${prefix}/bin/llc-mp-${ghc_llvm_version}" \
                    "OPT=${prefix}/bin/opt-mp-${ghc_llvm_version}" \
                    "PATH=${workpath}/bin:${haskell_cabal.cabal_root}/bin:$env(PATH)"

    # https://gitlab.haskell.org/ghc/ghc/-/issues/23477
    post-extract {
        copy        ${worksrcpath}/docs/index.html.in \
                    ${worksrcpath}/docs/index.html
        reinplace   "s|@LIBRARY_ghc_VERSION@|${version}|g" \
                    ${worksrcpath}/docs/index.html
    }

    # /usr/bin/clang++ -std=gnu++11: No such file or directory
    compiler.cxx_standard \
                    2011
    configure.cxxflags-append \
                    -std=gnu++11

    # https://trac.macports.org/ticket/65899
    # https://trac.macports.org/wiki/UsingTheRightCompiler#testing
    foreach phase {build destroot test} {
        ${phase}.env-append \
                    CC=${configure.cc} \
                    "CFLAGS=${configure.cflags}" \
                    CPP=${configure.cpp} \
                    "CPPFLAGS=${configure.cppflags}" \
                    CXX=${configure.cxx} \
                    "CXXFLAGS=${configure.cxxflags}" \
                    "LDFLAGS=${configure.ldflags}" \
                    "LD=${prefix}/bin/ld" \
                    "LLC=${prefix}/bin/llc-mp-${ghc_llvm_version}" \
                    "OPT=${prefix}/bin/opt-mp-${ghc_llvm_version}"
    }

    use_configure   yes

    configure.cmd   ./configure
    configure.pre_args \
                    --prefix=${prefix}
    configure.args

    build.cmd       hadrian
    build.target    binary-dist-dir
    build.pre_args
    build.post_args -VVVVV [haskell_cabal.build_getjobsarg]

    destroot.cmd    hadrian
    destroot.target install
    destroot.pre_args \
                    --prefix=${destroot}${prefix}
    destroot.post_args \
                    -VVVVV

    test.cmd        hadrian
    test.target     test
    test.pre_args
    test.post_args  [haskell_cabal.build_getjobsarg]

    distfiles       [lindex ${ghc_source_checksums} 0] \
                    [lindex ${ghc_testsuite_checksums} 0]
    checksums       {*}${ghc_source_checksums} \
                    {*}${ghc_testsuite_checksums}
    extract.only    [lindex ${ghc_source_checksums} 0] \
                    [lindex ${ghc_testsuite_checksums} 0]

    variant prebuilt \
        description {This variant is deprecated.} {
        ui_error "Please install the port ${name}-prebuilt."
        return -code error "deprecated variant."
    }

    gpg_verify.use_gpg_verification \
                    yes

    if {[option gpg_verify.use_gpg_verification]} {
        distfiles-append \
                    ${distname}-testsuite${extract.suffix}.sig
        checksums-append \
                    ${distname}-testsuite${extract.suffix}.sig \
                    size    586

        post-checksum {
            gpg_verify.verify_gpg_signature \
                    ${filespath}/keyid-${gpg_keyid}.txt \
                    ${distpath}/${distname}-testsuite${extract.suffix}.sig \
                    ${distpath}/${distname}-testsuite${extract.suffix}
        }
    }

    # Build requires C11
    compiler.c_standard 2011
    # On OSX 10.{8,9} with clang 503, 600
    #   :info:build dtrace: failed to open td=gnu11/usr/bin/clang -std=gnu11 -E ...
    compiler.blacklist-append {clang < 700}

    # use these to specify python versions, python3 required
    # use ${prefix}/var/macports/sources/rsync.macports.org/macports/release/tarballs/ports/_resources/port1.0/group/python-1.0.tcl
    set python3_version 313
    set python3_branch  [string index ${python3_version} 0].[string range ${python3_version} 1 end]
    set python3_prefix  ${frameworks_dir}/Python.framework/Versions/${python3_branch}
    set python3_bin     ${python3_prefix}/bin/python${python3_branch}

    depends_build-append \
                    port:alex \
                    port:autoconf \
                    port:automake \
                    port:bash \
                    port:bzip2 \
                    port:file \
                    port:gzip \
                    port:hadrian \
                    port:happy \
                    port:HsColour \
                    port:python${python3_version} \
                    port:py${python3_version}-sphinx \
                    port:texlive-fonts-extra \
                    port:texlive-fonts-recommended \
                    port:texlive-latex-extra \
                    port:texlive-xetex \
                    port:xz

    depends_lib-append  \
                    port:cctools \
                    port:gmp \
                    port:ld64 \
                    port:libiconv \
                    port:llvm-${ghc_llvm_version} \
                    port:ncurses
    
    # build depends upon these x86_64 binaries
    depends_skip_archcheck-append \
                    alex \
                    hadrian \
                    happy \
                    HsColour

    post-extract {
        xinstall -d ${workpath}/bin
        ln -s       ${python3_bin} \
                    ${workpath}/bin/python3
        ln -s       ${prefix}/bin/sphinx-build-${python3_branch} \
                    ${workpath}/bin/sphinx-build
        # avoid this cabal/sed error in macOS 10 and earlier:
        # checking for version of sphinx-build... sed: illegal option -- r
        ln -s       ${prefix}/bin/gsed \
                    ${workpath}/bin/sed
    }

    post-patch {
        if { ![file exists ${worksrcpath}/boot] } {
            xinstall \
                    ${worksrcpath}/boot.source \
                    ${worksrcpath}/boot
        }

        # fix DejaVu texlive fonts names, e.g. "\setmonofont{DejaVu Sans Mono}"
        foreach f [list \
            ${worksrcpath}/libraries/Cabal/doc/conf.py \
            ${worksrcpath}/docs/users_guide/conf.py \
            ] {
            reinplace -E "s|(\{DejaVu\[\[:alnum:]_]*)\[\[:space:]]+|\\1|g" \
                    ${f}
            reinplace -E "s|(\{DejaVu\[\[:alnum:]_]*)\[\[:space:]]+|\\1|g" \
                    ${f}
            reinplace -E "s|\{(DejaVu\[\[:alnum:]_]*)\}|\{\\1.ttf\}|g" \
                    ${f}
        }
        
        # update rtd-theme to make it compatible with sphinx 7
        #delete ${worksrcpath}/docs/users_guide/rtd-theme
        #copy ${filespath}/rtd-theme-70526f5bd8886126f49833ef20604a2c6477780a \
             ${worksrcpath}/docs/users_guide/rtd-theme
    }

    pre-configure {
        system -W ${worksrcpath} \
            "env ${haskell_cabal.env} ./boot"
    }

    use_autoconf    yes

    # https://gitlab.haskell.org/ghc/ghc/-/issues/22118
    configure.pre_args-append \
                    --with-gmp-includes=${prefix}/include \
                    --with-gmp-libraries=${prefix}/lib \
                    --with-iconv-includes=${prefix}/include \
                    --with-iconv-libraries=${prefix}/lib

    post-build {
        system -W ${build.dir} \
            "env ${haskell_cabal.env} ${build.cmd} docs [haskell_cabal.build_getjobsarg]"
    }

    pre-destroot {
        # mk/install_script.sh isn't automatically created by hadrian
        set bindist_mkdir [glob ${worksrcpath}/_build/bindist/${distname}-*/mk]
        if {![file exists ${bindist_mkdir}/install_script.sh]} {
            xinstall -W ${worksrcpath} mk/install_script.sh ${bindist_mkdir}
        }
    }

    haskell_cabal.bindirs-append \
                    ${destroot}${prefix}/lib/${subport}-${version}/bin \
                    ${destroot}${prefix}/lib/${subport}-${version}/lib/bin
    
    # documentation
    post-destroot {
        xinstall -W ${filespath} -m 0644 ./ghci.conf ${destroot}${prefix}/etc

        delete      ${destroot}${prefix}/share/share/doc/${distname}/archives

        xinstall -d ${destroot}${prefix}/share/man/man1
        xinstall -m 0644 \
                    ${worksrcpath}/_build/manpage/${name}.1 \
                    ${destroot}${prefix}/share/man/man1
    }

    post-destroot {
        # delete any destroot path appearing in text files
        fs-traverse f ${destroot}${prefix} {
            if {[file isfile ${f}] && [file type ${f}] eq {file}} {
                if {[string match "text/*" [lindex [exec file --mime-type ${f}] end]]} {
                    reinplace -q "s|${destroot}||g" ${f}
                }
            }
        }
    }

    test.run        yes

    post-activate {
        system "${prefix}/bin/ghc-pkg recache"
    }

    notes "The GHC User Manual is available at:

    file://${prefix}/share/doc/${distname}/html/index.html
    ${prefix}/share/doc/${distname}/users_guide.pdf

Copy/edit ${prefix}/etc/ghci.conf to your directory ~/.ghc
for a user-specific startup configuration."

    livecheck.url       ${homepage}/download.html
    livecheck.type      regex
    livecheck.regex     {<a href="download_ghc[_0-9]+.html">([0-9.]+)</a>}
}

subport ghc-prebuilt {
    revision        0
    supported_archs arm64 x86_64

    distfiles       ${ghc_distname}${extract.suffix}

    gpg_verify.use_gpg_verification \
                    yes

    if {[option gpg_verify.use_gpg_verification]} {
        distfiles-append \
                    ${ghc_distname}${extract.suffix}.sig
        checksums-append \
                    ${ghc_distname}${extract.suffix}.sig \
                    size    586

        post-checksum {
            gpg_verify.verify_gpg_signature \
                    ${filespath}/keyid-${gpg_keyid}.txt \
                    ${distpath}/${ghc_distname}${extract.suffix}.sig \
                    ${distpath}/${ghc_distname}${extract.suffix}
        }
    }

    depends_build-append \
                    port:file

    depends_lib-append \
                    port:cctools \
                    port:ld64 \
                    port:llvm-${ghc_llvm_version}

    extract.only    ${ghc_distname}${extract.suffix}
    extract.rename  yes

    # Build requires C11
    compiler.c_standard 2011
    # On OSX 10.{8,9} with clang 503, 600
    #   :info:build dtrace: failed to open td=gnu11/usr/bin/clang -std=gnu11 -E ...
    compiler.blacklist-append {clang < 700}

    distname        ${name}-${ghc_version}

    configure.env-append \
                    "LD=${prefix}/bin/ld" \
                    "LLC=${prefix}/bin/llc-mp-${ghc_llvm_version}" \
                    "OPT=${prefix}/bin/opt-mp-${ghc_llvm_version}"

    build           {}

    post-destroot {
        # rename installed files to *-prebuilt
        set exedir ${prefix}/lib/${distname}
        set docdir ${prefix}/share/doc/${distname}
        set mandir ${prefix}/share/man/man1
        foreach f [glob ${destroot}${prefix}/bin/*] {
            if {[file isfile ${f}] && [file type ${f}] eq {file}
                && [string match "text/*" [lindex [exec file --mime-type ${f}] end]]} {
                reinplace -E -q \
                    "s|^(exeprog=\".+)(\")\$|\\1-prebuilt\\2|" \
                    ${f}
                foreach d [list ${exedir} ${docdir}] {
                    reinplace -E -q "s|(${d})|\\1-prebuilt|g" ${f}
                }
                move ${f} ${f}-prebuilt
            } elseif {[file type ${f}] eq {link}} {
                set flink [file readlink ${f}]
                ln -s ${flink}-prebuilt ${f}-prebuilt
                delete ${f}
            }
        }
        foreach d [list ${destroot}${exedir} ${destroot}${docdir}] {
            move    ${d} ${d}-prebuilt
        }
        move ${destroot}${mandir}/${name}.1 ${destroot}${mandir}/${name}-prebuilt.1

        delete -force \
                    ${destroot}${docdir}/archives
    }
}

subport hadrian {
    # find ${worksrcpath} -type f -exec egrep -E -o '"pkg-name":"shake","pkg-version":"[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+"' {} ';'
    # revbump if the version is unchanged
    version         0.19.8
    revision        1

    distname        ${name}-${ghc_version}
    distfiles       [lindex ${ghc_source_checksums} 0]
    checksums       {*}${ghc_source_checksums}
    extract.only    [lindex ${ghc_source_checksums} 0]
if {[exists extract.rename]} {
    extract.rename  yes
}
    set worksrcpath ${workpath}/${worksrcdir}/${subport}

    variant stack \
        description {Use stack to build.} {}

    if { [variant_isset "stack"] } {
        PortGroup   haskell_stack 1.0

        post-extract {
            # Fix for cabal data-files hardcoded path in binary
            # See:
            # https://github.com/commercialhaskell/stack/issues/848
            # https://github.com/commercialhaskell/stack/issues/4857
            # https://github.com/haskell/cabal/issues/462
            # https://github.com/haskell/cabal/issues/3586
            xinstall -m 0644 -W ${worksrcpath} \
                ${filespath}/Paths_${subport}.hs ./src/Paths_${subport}.hs

            reinplace "s|@PREFIX@|${prefix}|g" \
                ${worksrcpath}/src/Paths_${subport}.hs
            reinplace "s|@NAME@|${subport}|g" \
                ${worksrcpath}/src/Paths_${subport}.hs
            reinplace -E "s|(Version\[\[:space:\]\]+)\\\[\[\[:digit:\]\]+(,\[\[:digit:\]\]+){1,4}\\\]|\\1\[[join [split ${version} .] ,]\]|" \
                ${worksrcpath}/src/Paths_${subport}.hs
        }
    } else {
        PortGroup   haskell_cabal 1.0

        variant haskell_cabal_use_prebuilt \
            description {Use prebuilt cabal and ghc. This is a necessary\
                default variant because hadrian is used to bootstrap ghc\
                and ghc is used to bootstrap cabal.} {
            haskell_cabal.use_prebuilt  yes
        }
        default_variants-append \
                    +haskell_cabal_use_prebuilt

        build.target-append \
                    --project-file=cabal.project \
                    --allow-newer
        build.post_args-append \
                    --bindir=${prefix}/bin \
                    --datadir=${prefix}/share/${subport}
    }
}
