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

PortSystem          1.0
PortGroup           compiler_blacklist_versions 1.0
PortGroup           select 1.0
PortGroup           compilers 1.0
PortGroup           muniversal 1.0
PortGroup           legacysupport 1.0

name                openmpi
version             4.0.1
set branch          [join [lrange [split ${version} .] 0 1] .]
categories          science parallel net
platforms           darwin
license             BSD
maintainers         nomaintainer
description         A High Performance Message Passing Library
long_description    Open MPI is a project combining technologies and resources \
                    from several other projects (FT-MPI, LA-MPI, LAM/MPI, and \
                    PACX-MPI) in order to build the best MPI library available. A \
                    completely new MPI-2 compliant implementation, Open MPI offers \
                    advantages for system and software vendors, application developers \
                    and computer science researchers.

homepage            https://www.open-mpi.org/
set subdir          ompi/v${branch}/downloads/
master_sites        https://www.open-mpi.org/software/${subdir}

checksums           rmd160  a9b7730d31e77e8d8d49204f9945d24f2dd54072 \
                    sha256  cce7b6d20522849301727f81282201d609553103ac0b09162cf28d102efb9709 \
                    size    9838152
use_bzip2           yes

livecheck.type      regex
livecheck.url       http://www.open-mpi.org/
livecheck.regex     Open MPI v(\[0-9\.\]+) released

if {[string first "-devel" $subport] > 0} {

    set base            201905080241
    set tag             5d4c9b4

    name                openmpi-devel
    version             ${branch}.999-${base}
    revision            0

    distname            openmpi-v${branch}.x-${base}-${tag}

    master_sites        http://www.open-mpi.org/nightly/v${branch}.x \
                        http://www.open-mpi.de/nightly/v${branch}.x

    checksums           rmd160  65d03a8e8cb897ffb288eca36f4e2419cc119c81 \
                        sha256  d90dce8cadf9344b989e8b44ceadd3e8f878effc99c8a800f4ab250a071233b1 \
                        size    9890558

    livecheck.version   ${base}
    livecheck.url       [lindex ${master_sites} 0]
    livecheck.regex     nightly/open-mpi/v${branch}.x/openmpi-v${branch}.x-(\[0-9\]+-\[0-9a-f\]+)
}

# As OpenMPI creates compiler wrappers, there are lots of
# variants for what compiler the user would like to wrap.

# Sub-ports names and corresponding configure.compiler value
array set clist {
    clang   {clang}
    clang50 {macports-clang-5.0}
    clang60 {macports-clang-6.0}
    clang70 {macports-clang-7.0}
    clang80 {macports-clang-8.0}
    gcc5    {macports-gcc-5}
    gcc6    {macports-gcc-6}
    gcc7    {macports-gcc-7}
    gcc8    {macports-gcc-8}
}
# gcc   4.x     not supported on mac OS 10.12 (Darwin16) or newer
# clang 3.{3,4} not supported on mac OS 10.12 (Darwin16) or newer
if { ${os.major} < 16 } {
    set clist(clang33) {macports-clang-3.3}
    set clist(clang34) {macports-clang-3.4}
    # Only provide gcc 4.9, as older versions do not build.
    set clist(gcc49)   {macports-gcc-4.9}
}
# clang 3.7,4.0 not supported on mac OS 10.14 (Darwin18) or newer
if { ${os.major} < 18 } {
    set clist(clang37) {macports-clang-3.7}
}
# gcc 9+ only available on macOS10.7 (Darwin11) and newer
if { ${os.major} > 10 } {
    set clist(gcc9)    {macports-gcc-9}
}

foreach key [array name clist] {
    subport ${name}-${key} {}
    subport ${name}-devel-${key} {}
}
subport ${name}-default {}
subport ${name}-devel {}
subport ${name}-devel-default {}

pre-extract { file mkdir ${workpath}/build }

# https://trac.macports.org/ticket/39089
compiler.blacklist  gcc-4.0
compiler.blacklist-append  llvm-gcc-4.2 macports-llvm-gcc-4.2

# For reasons that are not entirely clear, -I${worksrcpath} is added to the CPPFLAGS by the configure script.
# In ${worksrcpath}, there is a file called VERSION.
# C++ has a standard library header version (https://en.cppreference.com/w/cpp/header/version).
# Starting with Clang 8.0, version was included in other standard header files (https://reviews.llvm.org/D51955).
# With a case-insensitive file system, VERSION is used instead of version.
# This is an ugly workaround.
patchfiles-append   patch-configure.diff

configure.dir       ${workpath}/build
configure.cmd       ${worksrcpath}/configure
configure.args      --disable-mpi-fortran \
                    --enable-mpi-cxx \
                    "FFLAGS='' F77=''"

# remove -arch from ldflags, ticket #22833
configure.ld_archflags
configure.ccache no

# We're making compiler wrappers here... don't default to -O2 for wrappers.
# Actual library code is compiled with -O2 via --enable-fast=O2 configure arg
configure.optflags-delete   -O2 -Os
configure.cppflags-delete   -I${prefix}/include
configure.ldflags-delete    -L${prefix}/lib

build.dir           ${configure.dir}
destroot.dir        ${build.dir}

if {${subport} != ${name}} {
    set cname                   [lindex [split ${subport} -] end]
    if {${cname} == "default"} {
        set cname                   mp
    }

    # Force buildbot to skip this since openmpi depends on hwloc and that would
    # be different for a user's machine
    archive_sites

    depends_build-append        port:pkgconfig
    depends_lib-append          port:hwloc
    depends_run                 port:mpi_select port:mpi-doc
    select.group                mpi
    select.file                 ${filespath}/${name}-${cname}
    livecheck.type              none

    if {[string first "-default" $subport] < 0} {
        configure.compiler      [lindex $clist($cname) 0]
        append long_description "\\n\\nTHIS SUBPORT WRAPS ${cname}'s C/C++"
    } else {
        append long_description \
"\\n\\nTHIS SUBPORT WRAPS MACPORTS' DEFAULT COMPILER FOR C/C++"
    }

    configure.args-append   \
        --bindir=${prefix}/libexec/${name}-${cname} \
        --libdir=${prefix}/lib/${name}-${cname} \
        --sysconfdir=${prefix}/etc/${name}-${cname} \
        --includedir=${prefix}/include/${name}-${cname} \
        --datadir=${prefix}/share/${name}-${cname} \
        --docdir=${prefix}/share/docdelete \
        --mandir=${prefix}/share/mandelete \
        --with-hwloc=${prefix}

    post-destroot {
        if {[string first "-devel" $subport] > 0} {
            # Supply our own -devel manpages (might be materially different / new)
            file mkdir ${destroot}${prefix}/share/doc
            file mkdir ${destroot}${prefix}/share/docdelete
            move ${destroot}${prefix}/share/mandelete \
                ${destroot}${prefix}/share/docdelete/man
            move ${destroot}${prefix}/share/docdelete \
                ${destroot}${prefix}/share/doc/${name}-${cname}
            system -W ${destroot}${prefix}/share/doc/${name}-${cname}/man \
                "/usr/bin/find . -type f -print0 | /usr/bin/xargs -0 -P ${build.jobs} /usr/bin/gzip -v"
        } else {
            # This version doesn't supply manpages
            if {[file isdirectory ${destroot}${prefix}/share/mandelete]} {
                delete ${destroot}${prefix}/share/mandelete
            }
            if {[file isdirectory ${destroot}${prefix}/share/docdelete]} {
                delete ${destroot}${prefix}/share/docdelete
            }
        }

        set vampirlog ${destroot}${prefix}/share/${name}-${cname}/vampirtrace/config.log
        if { [ file exists $vampirlog ] } {
            delete $vampirlog
        }

        foreach bin {mpirun mpiexec mpicc mpicxx mpif77 mpif90 mpifort} {
            system -W ${destroot}${prefix}/share/$name-$cname/openmpi \
                "ln -sf $bin-wrapper-data.txt $bin-$name-$cname-wrapper-data.txt"
            system -W ${destroot}${prefix}/bin \
                "ln -sf ${prefix}/libexec/$name-$cname/$bin $bin-$name-$cname"
        }
    }

    if { [string first gcc $cname] == 0 } {
        append long_description " AND FORTRAN COMPILERS"
        configure.args-delete   --disable-mpi-fortran
        configure.args-append   --enable-mpi-fortran
        select.file             ${filespath}/${name}-${cname}-fortran
        variant fortran description {
            Stub : fortran always enabled for gcc-based version
        } {}
        default_variants-append     +fortran

        # GCC C++ always uses libstdc++
        # see https://trac.macports.org/ticket/59185
        configure.cxx_stdlib libstdc++
    } else {
        append long_description " (AND THE FORTRAN COMPILER SELECTED BY THE VARIANT, IF ANY)"

        compilers.choose   fc
        compilers.setup    default_fortran

        if {[fortran_variant_isset]} {
            configure.args-delete   --disable-mpi-fortran
            configure.args-append   --enable-mpi-fortran
            select.file             ${filespath}/${name}-${cname}-fortran

            # at least currently, the Fortran variants gccX and g95 match the name of the ports
            depends_lib-append      port:[fortran_variant_name]
        }
    }
    set devnotes ""

    if {[string first "-devel" $subport] > 0} {
        set devnotes "

To see the -devel MAN pages, add:
  ${prefix}/share/doc/${name}-${cname}/man
to the start of your MANPATH environment variable."
    }

notes "
The mpicc wrapper (and friends) are installed as:

  ${prefix}/bin/mpicc-${name}-${cname} (likewise mpicxx, ...)

To make ${subport}'s wrappers the default (what you get when
you execute 'mpicc' etc.) please run:

  sudo port select --set mpi [file tail ${select.file}]${devnotes}
"

    variant valgrind description {enable valgrind support} {
        depends_lib-append    path:${prefix}/lib/pkgconfig/valgrind.pc:valgrind
        configure.args-append --enable-debug --enable-memchecker --with-valgrind=${prefix}
    }

    if {[variant_isset universal]} {
        # use open-mpi's multilib support to build universal
        # see https://github.com/open-mpi/ompi/wiki/MultiLib
        # Fortran is the only non-trivial case

        merger-post-destroot {
            # Fortran headers do not understand preprocessors commands like __LP64__
            # Fortran mod files can not be merged for different architectures
            # create a architecture specific folder for the non-build_arch architecture
            foreach arch ${configure.universal_archs} {
                if {${arch} ne ${build_arch}} {
                    set mod_dir ${destroot}-${arch}${prefix}/lib/${name}-${cname}
                    xinstall -d -m 0755 ${mod_dir}/${arch}
                    foreach f [glob -nocomplain -directory ${mod_dir} *.mod] {
                        move ${f} ${mod_dir}/${arch}
                    }

                    set inc_dir ${destroot}-${arch}${prefix}/include/${name}-${cname}
                    xinstall -d -m 0755 ${inc_dir}/${arch}
                    foreach f [glob -nocomplain -directory ${inc_dir} mpif-config.h] {
                        move ${f} ${inc_dir}/${arch}
                    }

                    # include the new directories in the search paths for header and mod files
                    set data_dir ${destroot}-${arch}${prefix}/share/${name}-${cname}/openmpi
                    if {[file exists ${data_dir}/mpifort-wrapper-data.txt]} {
                        reinplace \
                            "s|-I\${libdir}|-I\${libdir}/${arch} -I\${libdir}|g" \
                            ${data_dir}/mpifort-wrapper-data.txt

                        reinplace \
                            "s|preprocessor_flags=|preprocessor_flags=-I\${includedir}/i386|g" \
                            ${data_dir}/mpifort-wrapper-data.txt
                    }
                }
            }
            foreach arch ${configure.universal_archs} {
                set data_dir ${destroot}-${arch}${prefix}/share/${name}-${cname}/openmpi
                if {[file exists ${data_dir}/mpifort-wrapper-data.txt]} {
                    # muniversal PortGroup will not merge this file properly
                    # merge file in destroot phase
                    move \
                        ${data_dir}/mpifort-wrapper-data.txt \
                        ${data_dir}/mpifort-wrapper-data-${arch}.txt
                }
            }
        }

        post-destroot {
            # merge mpifort data file
            # see https://github.com/open-mpi/ompi/wiki/compilerwrapper3264
            set data_dir ${destroot}${prefix}/share/${name}-${cname}/openmpi
            if {[file exists ${data_dir}/mpifort-wrapper-data-${build_arch}.txt]} {
                system -W ${data_dir} "cat mpifort-wrapper-data-${build_arch}.txt >> mpifort-wrapper-data.txt"
            }
            foreach arch ${configure.universal_archs} {
                if {[file exists ${data_dir}/mpifort-wrapper-data-${arch}.txt]} {
                    if {${arch} ne ${build_arch}} {
                        if {${arch} eq "ppc" || ${arch} eq "i386"} {
                            set bitval 32
                        } else {
                            set bitval 64
                        }
                        system -W ${data_dir} "echo \"\">> mpifort-wrapper-data.txt"
                        system -W ${data_dir} "echo \"compiler_args=${arch};-m${bitval}\" >> mpifort-wrapper-data.txt"
                        system -W ${data_dir} "cat mpifort-wrapper-data-${arch}.txt >> mpifort-wrapper-data.txt"
                    }
                }
            }
            foreach arch ${configure.universal_archs} {
                delete ${data_dir}/mpifort-wrapper-data-${arch}.txt
            }
        }
    }

} else {
    depends_lib-append      port:$name-default
    distfiles
    patchfiles
    supported_archs         noarch
    use_configure           no
    build {}
    destroot {
        set docdir          ${destroot}${prefix}/share/doc/${name}
        xinstall -d ${docdir}
        system "echo $name is a stub port > ${docdir}/README"
    }
}