# -*- 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           cmake 1.1
PortGroup           github 1.0
PortGroup           legacysupport 1.1

# NOTE: Also rev-bump 'apache-arrow' when updating this port
github.setup        grpc grpc 1.48.4 v
# Change github.tarball_from to 'releases' or 'archive' next update
github.tarball_from tarball
revision            12
categories          devel
maintainers         nomaintainer
license             Apache-2
fetch.type          git

description         A high performance, open-source universal RPC framework.
long_description    gRPC is a modern, open source, high-performance \
                    remote procedure call (RPC) framework that can run \
                    anywhere. gRPC enables client and server \
                    applications to communicate transparently, and \
                    simplifies the building of connected systems.

homepage            https://grpc.io/

# ignore pre releases
github.livecheck.regex  {([0-9.]+)}

set name_io         ${name}io

patchfiles-append   patch-unbreak-port_platform.diff
patchfiles-append   patch-python-respect-cc-variable.diff
patchfiles-append   patch-avoid-overlinking-abseil.diff

patchfiles-append   patch-src-core-ext-xds-xds_api.cc.diff

# abseil and re2 require c++17 support
compiler.cxx_standard  2017

# https://github.com/grpc/grpc/commit/f15ba1ffc73c5d0b63754df72fc47c567b9c7252
if {[vercmp ${version} >= 1.51.0]} {
compiler.thread_local_storage yes
}

depends_build-append \
                    path:bin/pkg-config:pkgconfig

depends_lib-append \
                    port:abseil \
                    port:c-ares \
                    port:lbzip2 \
                    path:lib/pkgconfig/libuv.pc:libuv \
                    path:lib/libssl.dylib:openssl \
                    port:protobuf3-cpp \
                    port:re2 \
                    port:zlib

proc git_submodule_update_init {dir args} {
    foreach arg {*}${args} {
        system -W ${dir} "git submodule update --init ${arg}"
    }
}

# Ensure that these third_party repos exist to prevent downloads
# See: https://github.com/grpc/grpc/blob/658632fcd82aa673addc2b4b91860d4e2738f574/CMakeLists.txt#L330-L405
set grpc_submodules [list \
    benchmark \
    bloaty \
    envoy-api \
    googleapis \
    googletest \
    opencensus-proto \
    xds
]

post-fetch {
    git_submodule_update_init ${worksrcpath}/third_party ${grpc_submodules}
}

configure.args-append \
                    -DBUILD_SHARED_LIBS:BOOL=ON \
                    -DgRPC_BUILD_TESTS=OFF \
                    -DgRPC_ABSL_PROVIDER=package \
                    -DgRPC_CARES_PROVIDER=package \
                    -DgRPC_PROTOBUF_PROVIDER=package \
                    -DgRPC_RE2_PROVIDER=package \
                    -DgRPC_SSL_PROVIDER=package \
                    -DgRPC_ZLIB_PROVIDER=package

# https://github.com/grpc/grpc/pull/32159
configure.cppflags-append \
                    -D__STDC_FORMAT_MACROS

if {${build_arch} in [list i386 ppc] && [string match *gcc* ${configure.compiler}]} {
    # ___atomic_fetch_sub_8 etc.
    configure.ldflags-append -latomic
}

# the build must link against its own libraries
cmake.install_rpath
configure.pre_args-replace \
                    -DCMAKE_BUILD_WITH_INSTALL_RPATH:BOOL=ON \
                    -DCMAKE_BUILD_WITH_INSTALL_RPATH:BOOL=OFF

# Remove incorrect cmake dependency on SDK that cmake adds on some systems
# See https://github.com/grpc/grpc/issues/24902
set macos_sdk [file tail ${configure.sdkroot}]
set macos_sdk_dir [file dirname ${configure.sdkroot}]
set xcode_sdk_dir /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs

if {[info exists cmake.build_dir]
    && ${macos_sdk_dir} ne ${xcode_sdk_dir}
    && ![file isdirectory ${xcode_sdk_dir}/${macos_sdk}]} {
    post-configure {
        set cmakefiles_dirs {}
        fs-traverse f ${cmake.build_dir} {
            if { [file isdirectory ${f}]
                 && [string match "CMakeFiles" [file tail ${f}]] } {
                append cmakefiles_dirs " " ${f}
            }
        }
        foreach d ${cmakefiles_dirs} {
            foreach f [glob -nocomplain -type f ${d}/*.dir/*.make] {
                # delete incorrect Makefile targets to Xcode SDKs
                reinplace -q -E "/:\[\[:space:]]+\\/\[^\[:space:]]+\\/${macos_sdk}\\/\[^\[:space:]]+\\/CoreFoundation\\.framework/d" ${f}
                # correct incorrect build flags
                reinplace -q -E "s|(\[\[:space:]]+-F)${xcode_sdk_dir}(/${macos_sdk}/System/Library/Frameworks\[\[:space:]]+)|\\1${macos_sdk_dir}\\2|g" ${f}
            }
            foreach f [glob -nocomplain -type f ${d}/*.dir/link.txt] {
                # correct incorrect build flags
                reinplace -q -E "s|(\[\[:space:]]+)/\[^\[:space:]]+/${macos_sdk}/\[^\[:space:]]+/CoreFoundation\.framework\[\[:space:]]*| |g" ${f}
                # correct incorrect build flags
                reinplace -q -E "s|(\[\[:space:]]+-F)${xcode_sdk_dir}(/${macos_sdk}/System/Library/Frameworks\[\[:space:]]+)|\\1${macos_sdk_dir}\\2|g" ${f}
            }
        }
    }
}

build.target

variant test description {Build and run unit testing framework} {
    depends_test-append \
                    port:gperftools

    configure.args-replace \
                    -DgRPC_BUILD_TESTS=OFF \
                    -DgRPC_BUILD_TESTS=ON

    test.run         yes

    test {
        system -W ${workpath} \
            "${configure.cc} ${filespath}/test.cc -I${worksrcpath}/include -L${cmake.build_dir} -lgrpc -o test"
        set libgrpc [file tail [lindex [glob -type f ${cmake.build_dir}/libgrpc.*.dylib] 0]]
        system -W ${workpath} \
            "install_name_tool -change @rpath/${libgrpc} ${cmake.build_dir}/${libgrpc} ./test"
        system -W ${workpath} \
            "./test"
    }
}

# create Python subports
set python_versions {39 310}

# Python modules grpcio and grpcio-tools
foreach v ${python_versions} {
    subport py${v}-${name_io} {
        PortGroup   python 1.0

        categories-prepend  devel
        maintainers {emcrisostomo @emcrisostomo} openmaintainer

        description Python bindings for gRPC HTTP/2-based RPC framework
        long_description \
                    {*}${description}

        homepage    https://github.com/grpc/grpc

        python.default_version  ${v}
    }

    subport py${v}-${name_io}-tools {
        PortGroup   python 1.0
        PortGroup   compiler_wrapper 1.0

        categories-prepend  devel
        maintainers nomaintainer

        # https://github.com/macports/macports-ports/commit/9f4926a2ada59c0f2d54b5e923e4a7d99a7e67b6#commitcomment-53546190
        compwrap.add_compiler_flags no

        description Protobuf code generator for gRPC
        long_description \
                    {*}${description}

        homepage    https://github.com/grpc/grpc

        python.default_version  ${v}
    }
}

# common settings for all Python ports
if {[string match "py*" ${subport}]} {
    pre-patch {
        reinplace "s|/usr|${prefix}|g" ${worksrcpath}/setup.py
    }

    use_configure   yes

    # py-grpcio-tools needs to build with its (very old) bundled protobuf, not
    # with the headers installed by protobuf3-cpp.
    configure.cppflags-prepend \
                    -Ithird_party/protobuf/src

    configure.pre_args-delete \
                    --prefix=${prefix}
    configure.pre_args-replace \
                    {-DCMAKE_C_COMPILER="$CC"} \
                    -DCMAKE_C_COMPILER=${configure.cc}
    configure.pre_args-replace \
                    {-DCMAKE_CXX_COMPILER="$CXX"} \
                    -DCMAKE_CXX_COMPILER=${configure.cxx}
    configure.pre_args-replace \
                    "-DCMAKE_MAKE_PROGRAM=${python.bin} setup.py --no-user-cfg" \
                    -DCMAKE_MAKE_PROGRAM=[portbuild::build_getmaketype]

    configure.args-append \
                    -DPython_EXECUTABLE=${python.bin}

    foreach phase {build destroot} {
        ${phase}.env-append \
                    GRPC_PYTHON_BUILD_SYSTEM_ABSL=1 \
                    GRPC_PYTHON_BUILD_SYSTEM_CARES=1 \
                    GRPC_PYTHON_BUILD_SYSTEM_OPENSSL=1 \
                    GRPC_PYTHON_BUILD_SYSTEM_RE2=1 \
                    GRPC_PYTHON_BUILD_SYSTEM_ZLIB=1 \
                    GRPC_PYTHON_BUILD_WITH_CYTHON=1
    }

    python.pep517   no

    # Build instructions:
    # https://github.com/grpc/grpc/tree/master/src/python/grpcio#installing-from-source

    build.dir       ${worksrcpath}
    build.target    build
    build.post_args-delete \
                    VERBOSE=ON

    destroot.dir    ${build.dir}
    destroot.target install

    test.run        yes
}

# Python bindings for grpcio
if {[string match "py*${name_io}" ${subport}]} {
    depends_build-append \
                    port:py${python.version}-coverage \
                    port:py${python.version}-cython-compat \
                    port:py${python.version}-setuptools

    depends_lib-append \
                    port:py${python.version}-cython \
                    port:py${python.version}-protobuf3 \
                    port:py${python.version}-six

    depends_test-append \
                    port:py${python.version}-twisted

    # Not yet compatible with Cython 3
    set compat_path [string replace ${python.pkgd} 0 [string length ${python.prefix}]-1 ${prefix}/lib/py${python.version}-cython-compat]
    build.env-append    PYTHONPATH=${compat_path}
    destroot.env-append PYTHONPATH=${compat_path}
}

# Python bindings for grpcio-tools
if {[string match "py*-${name_io}-tools" ${subport}]} {
    set grpc_submodules \
                    protobuf

    depends_build-append \
                    port:py${python.version}-setuptools

    depends_lib-append \
                    port:py${python.version}-${name_io} \
                    port:py${python.version}-protobuf3

    # Build instructions:
    # https://github.com/grpc/grpc/tree/master/tools/distrib/python/grpcio_tools

    use_configure   no

    pre-build {
        system -W ${build.dir} "${python.bin} ../make_grpcio_tools.py"
    }

    build.dir       ${worksrcpath}/tools/distrib/python/grpcio_tools
    build.target    build
    build.post_args-delete \
                    VERBOSE=ON

    destroot.dir    ${build.dir}
    destroot.target install

    test.run        yes
    test.dir        ${build.dir}/grpc_tools
}
