# -*- 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           python                         1.0
PortGroup           java                           1.0
PortGroup           github                         1.0
PortGroup           compilers                      1.0
PortGroup           compiler_blacklist_versions    1.0
PortGroup           xcode_workaround               1.0

name                py-tensorflow1
version             1.15.5
revision            0
github.setup        tensorflow tensorflow ${version} v
platforms           darwin
supported_archs     x86_64

license             Apache-2
maintainers         {emcrisostomo @emcrisostomo} {jonesc @cjones051073} openmaintainer

description         TensorFlow helps the tensors flow
long_description    ${description}

homepage            https://www.tensorflow.org/

github.livecheck.regex  {(1\.[0-9.]+)}

checksums           rmd160  1807544e59cb25028af0bfec45ddffd1f861cc4e \
                    sha256  2430b0a48e049078e249190d31d354ecdf565b9e1fb39bde3b50a4c06ac2f3fa \
                    size    46213601

set min_darwin 14
if { ${os.major} < ${min_darwin} } {
    known_fail yes
    # https://trac.macports.org/ticket/58518
    pre-fetch {
        ui_error "${name} ${version} requires Darwin ${min_darwin} or newer."
        return -code error "incompatible macOS version"
    }
}

compiler.blacklist-append {clang < 840}
compiler.cxx_standard 2014

patch.pre_args      -p1

# Required java version
java.version        11+
# LTS JDK port to install if required java not found
java.fallback       openjdk11
# JDK only needed at build time, but java PG sets lib dependency so
# declare no conflict to allow redistribution of binaries.
license_noconflict  ${java.fallback}

# The oldest Xcode version to use default Xcode compiler
# Note setting here should be in sync with that in bazel
set tf_min_xcode    9.0

patchfiles-append Fix-build-failures-for-python-3.8.patch
if {${os.major} < 16} {
    # Work around for issues with clock_gettime(CLOCK_REALTIME, &ts);
    # https://stackoverflow.com/questions/5167269/clock-gettime-alternative-in-mac-os-x
    # Note bazel does not play nice with legacysupport, so this IS needed instead..
    patchfiles-append CLOCK_REALTIME-Older-OSX.patch
}

# https://github.com/tensorflow/tensorflow/pull/40654
# https://github.com/tensorflow/tensorflow/issues/40688
patchfiles-append patch-numpy-1.19-fix.diff

variant mkl description {Enable Intel Math Kernel Library support} { }
# Enable MKL by default on 10.12 and newer.
if {${os.major} >= 16} {
    default_variants-append +mkl
}

variant native description {Build from source for best native platform support} {
    # Prevent precompiled binaries to let compilation optimise the library for the user processor
    archive_sites
}

# Support python versions
python.versions        36 37 38
python.default_version 38

if {${name} ne ${subport}} {

    # TF versions 1 and 2 cannot be installed at once
    conflicts py${python.version}-tensorflow

    depends_build-append \
        port:py${python.version}-future \
        port:py${python.version}-pip \
        port:py${python.version}-mock \
        port:bazel-0.25 \
        port:cctools

    depends_lib-append \
        port:py${python.version}-absl \
        port:py${python.version}-astor \
        port:py${python.version}-gast \
        port:py${python.version}-google-pasta \
        port:py${python.version}-grpcio \
        port:py${python.version}-keras \
        port:py${python.version}-numpy \
        port:py${python.version}-protobuf3 \
        port:py${python.version}-six \
        port:py${python.version}-tensorboard1 \
        port:py${python.version}-tensorflow_estimator1 \
        port:py${python.version}-termcolor \
        port:py${python.version}-wheel \
        port:py${python.version}-wrapt

    use_configure yes
    # Options passed to configure script via env vars
    configure.env-append PYTHON_LIB_PATH=${python.prefix}/lib/python${python.branch}/site-packages
    configure.env-append PYTHON_BIN_PATH=${prefix}/bin/python${python.branch}
    configure.env-append JAVA_HOME=${java.home}
    build.env-append     TMPDIR=${workpath}/tmp
    build.env-append     JAVA_HOME=${java.home}
    set base_march "-march=x86-64"
    if {![variant_isset native]} {
        configure.env-append CC_OPT_FLAGS=${base_march}
        build.env-append     CC_OPT_FLAGS=${base_march}
        notes "This version is built based on a base architecture for convenience,
              which may not be optimized for your system. To build a version
              customized for your machine, use the +native variant"
    }
    # Disable Xcode detection on older OSes, as we want the
    # MP provided commandline utilities to be used instead.
    if {[vercmp ${xcodeversion} ${tf_min_xcode}] < 0} {
        configure.env-append BAZEL_USE_CPP_ONLY_TOOLCHAIN=1
        build.env-append     BAZEL_USE_CPP_ONLY_TOOLCHAIN=1
    }
    # Remove all arguments
    configure.args
    configure.pre_args
    # configure command
    configure.cmd ./configure
    # Patch configuration
    pre-configure {
        # enforce correct build settings
        foreach f [ exec find ${worksrcpath}/ -name "configure" -or -name "configure.py" -or -name "compile.sh" -or -name "*.tpl" -or -name "*.bzl" -or -name "CROSSTOOL" -or -name "configure.py" -or -name "MOCK_CROSSTOOL" ] {
            foreach cmd {ar nm strip libtool ld objdump} {
                reinplace -q "s|/usr/bin/${cmd}|${prefix}/bin/${cmd}|g" ${f}
            }
            reinplace -q "s|/usr/bin/clang|\"${configure.cc}\"|g"   ${f}
            reinplace -q "s|\"clang\"|\"${configure.cc}\"|g"        ${f}
            reinplace -q "s| clang | ${configure.cc} |g"            ${f}
            reinplace -q "s|/usr/local/include|${prefix}/include|g" ${f}
            reinplace -q "s|std=c++0x|std=c++11|g"                  ${f}
            reinplace -q "s|std=c++1y|std=c++14|g"                  ${f}
            reinplace -q "s|std=c++1z|std=c++17|g"                  ${f}
        }
        # If not native build, make sure not used...
        if {![variant_isset native]} {
            foreach f [ exec find ${worksrcpath}/ -name "configure" -or -name "configure.py" -or -name "CMakeLists.txt" -or -name "Makefile" -or -name "*.sh" ] {
                reinplace -q "s|-march=native|${base_march}|g" ${f}
            }
        }
    }

    build {
        
        # Limit the number of parallel jobs to the number of physical, not logical, cpus.
        # First current setting to ensure we would be reducing the current setting.
        set physicalcpus [sysctl hw.physicalcpu]
        if { ${build.jobs} > ${physicalcpus} } {
            build.jobs ${physicalcpus}
        }

        # tensorflow(via bazel) cannot be built if gcc is 'port selected'
        # https://trac.macports.org/ticket/58569
        # https://trac.macports.org/ticket/58679
        # Until it can be figured out how to stop bazel finding and using macports gcc
        # just detect when this situation arises and error out...
        if { [file exists ${prefix}/bin/gcc] } {
            ui_error "${subport} cannot be built with 'port select gcc' active."
            ui_error "Please run 'sudo port select gcc none' and try again."
            ui_error "Once the build is complete, you can safely re-select your preferred gcc."
            return -code error "build error"
        }
        # Build using the wonderful bazel build system ...
        set tf_bazel_cmd "bazel --max_idle_secs=60 --output_user_root=${workpath}"
        set tf_bazel_build_opts "-s -c opt --config=opt"
        # Limit bazel resource utilisation
        set tf_bazel_build_opts "${tf_bazel_build_opts} --jobs ${build.jobs} --local_ram_resources=HOST_RAM*0.5 --local_cpu_resources=HOST_CPUS*.5"
        # Explicitly pass SDK https://github.com/bazelbuild/rules_go/issues/1554
        # Check versioned SDK actually exists... https://trac.macports.org/ticket/60317
        if {[string first ${configure.sdk_version} ${configure.sdkroot}] != -1} {
            set tf_bazel_build_opts "${tf_bazel_build_opts} --macos_sdk_version=${configure.sdk_version}"
        } else {
            ui_warn "configure.sdkroot='${configure.sdkroot}' does not match configure.sdk_version='${configure.sdk_version}'"
        }
        # hack to try and transfer MP c, c++ and ld options to bazel...
        foreach opt [list {*}${configure.cflags} ] {
            set tf_bazel_build_opts "${tf_bazel_build_opts} --conlyopt '${opt}'"
        }
        foreach opt [list {*}${configure.cxxflags} ] {
            set tf_bazel_build_opts "${tf_bazel_build_opts} --cxxopt '${opt}'"
        }
        foreach opt [list {*}${configure.ldflags} ] {
            set tf_bazel_build_opts "${tf_bazel_build_opts} --linkopt '${opt}'"
        }
        if {[vercmp ${xcodeversion} ${tf_min_xcode}] < 0} {
            set tf_bazel_build_opts "${tf_bazel_build_opts} --action_env CC=${configure.cc}"
            set tf_bazel_cmd "BAZEL_USE_CPP_ONLY_TOOLCHAIN=1 ${tf_bazel_cmd}"
        }
        if {[variant_isset mkl]} {
            set tf_bazel_build_opts "${tf_bazel_build_opts} --config=mkl"
        }
        if {![variant_isset native]} {
            set tf_bazel_build_opts "${tf_bazel_build_opts} --copt=${base_march}"
            set tf_bazel_cmd "CC_OPT_FLAGS=${base_march} ${tf_bazel_cmd}"
        }
        ui_debug "Bazel build command : ${tf_bazel_cmd}"
        ui_debug "Bazel build options : ${tf_bazel_build_opts}"
        # Run the build
        system -W ${worksrcpath} "${tf_bazel_cmd} build ${tf_bazel_build_opts} //tensorflow/tools/pip_package:build_pip_package"
        # Build the python wheel
        system -W ${worksrcpath} "./bazel-bin/tensorflow/tools/pip_package/build_pip_package ${workpath}"
        # Clean up
        system -W ${worksrcpath} "${tf_bazel_cmd} clean"
    }

    destroot.cmd  pip-${python.branch}
    destroot.args           \
        --ignore-installed  \
        --no-cache-dir      \
        --no-dependencies   \
        --root ${destroot}  \
        ${workpath}/tensorflow-*.whl
    destroot.post_args

    post-destroot {
        file delete ${destroot}${python.prefix}/bin/tensorboard
        file delete ${destroot}${prefix}/bin/tensorboard-${python.branch}
    }

    livecheck.type  none

}
