# -*- 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               cltversion 1.0

name                    cctools

# Xcode 11.3.1
version                 949.0.1
set ld64_version        530
revision                1

categories              devel
platforms               darwin
maintainers             {jeremyhu @jeremyhu} {kencu @kencu} openmaintainer
license                 {APSL-2 GPL-2+}
installs_libs           no
description             Compiler Tools for Mac OS X and Darwin
long_description        A set of essential tools to support development \
                        on Mac OS X and Darwin. Conceptually similar \
                        to binutils on other platforms.

homepage                https://opensource.apple.com/source/${name}/
master_sites            https://opensource.apple.com/tarballs/${name}:main \
                        https://opensource.apple.com/tarballs/ld64:ld64

distfiles               ld64-${ld64_version}.tar.gz:ld64 ${name}-${version}.tar.gz:main

checksums               ld64-530.tar.gz \
                        rmd160  793d012a611de5a044db3f97c6a9ec149072aff6 \
                        sha256  ee37f0487601c08c7d133bc91cad2e9084d00d02aa4709d228a9a065960aa187 \
                        size    744871 \
                        cctools-949.0.1.tar.gz \
                        rmd160  6412d9c5aea6aadd88cd9abdde6c1383f103b582 \
                        sha256  830485ac7c563cd55331f643952caab2f0690dfbd01e92eb432c45098b28a5d0 \
                        size    1968671

patchfiles              cctools-829-lto.patch \
                        PR-37520.patch \
                        PR-12400897.patch \
                        cctools-862-prunetrie.patch \
                        cctools-921-noavx512.patch \
                        as-try-clang.patch \
                        cctools-949-libstuff-add-args-c.diff \
                        cctools-949-redo_prebinding-add-segg-addr-table-header.diff \
                        cctools-949-build-with-SDKs-older-than-1012.diff \
                        cctools-949-nm-allow-no-lto-support.diff \
                        cctools-949-write_object-fix.diff \
                        cctools-949-lipo-segalign-log2fix.diff

# lipo-segalign-log2fix https://trac.macports.org/ticket/63164

# small fixes and sdk adjustments made to 949 but
# there is a bug in cctools as/write_object.c in 949 that needs upstreaming
# see https://github.com/macports/macports-ports/pull/9796

post-patch {
    if {![variant_isset xcode]} {
        system "cd ${workpath}/ld64-${ld64_version} && patch -p0 < ${filespath}/ld64-512-work-around-older-compilers-without-has-include.diff"
    }
}

if {${os.major} < 11} {
    patchfiles-append snowleopard-strnlen.patch
}

set all_llvm_variants {llvm10 llvmdev}
if {${os.major} < 12} {
    lappend all_llvm_variants llvm34
}
if {${os.major} < 14} {
    lappend all_llvm_variants llvm37
}
if {${os.major} < 19} {
    lappend all_llvm_variants llvm50 llvm60 llvm70 llvm80 llvm90
}
array set llvm_variant_version {llvm34 3.4 llvm37 3.7 llvm50 5.0 llvm60 6.0 llvm70 7.0 llvm80 8.0 llvm90 9.0 llvm10 10 llvmdev devel}
set llvm_version {}

foreach variantname $all_llvm_variants {
    set this_llvm_version $llvm_variant_version($variantname)
    variant $variantname conflicts xcode {*}[ldelete $all_llvm_variants $variantname] description "Use llvm-${this_llvm_version} for libLTO, llvm-mc, llvm-size, and llvm-nm" "
        set llvm_version        $this_llvm_version
        depends_lib-append      port:llvm-${this_llvm_version}
    "
}

proc some_llvm_variant_set {} {
    global all_llvm_variants
    foreach variantname $all_llvm_variants {
        if {[variant_isset $variantname]} {
            return yes
        }
    }
    return no
}

if { ![some_llvm_variant_set] && ![variant_isset xcode] } {
    # Xcode 11 has a newer cctools than the current cctools port
    # Check if Xcode is 11 or newer, or if not installed if the CLT is 11 or newer
    # This +xcode cutoff can be moved up as the cctools port is updated
    set xcode_ok [ expr { ${xcodeversion} ne "none" && [ vercmp ${xcodeversion} "11.0" ] >= 0 } ]
    set clt_ok   [ expr { ${xcodeversion} eq "none" && ${cltversion} ne "none" && [ vercmp ${cltversion} "11.0" ] >= 0 } ]
    if { ${xcode_ok} || ${clt_ok} } {
        default_variants +xcode
    } elseif {${os.major} >= 14} {
        # llvm-11 changed the arguments accepted by llvm-objdump
        # this causes a number of errors in scripts that still use the old arguments
        # we will default to +llvm11 when xcode changes to require the new arguments
        # see https://reviews.llvm.org/D92310 and https://trac.macports.org/ticket/61852
        default_variants +llvm10
    } elseif {${os.major} >= 12} {
        # Using llvm-3.7 to break a dependency cycle (https://trac.macports.org/ticket/53138)
        default_variants +llvm37
    } elseif {${os.major} >= 10 && ${configure.build_arch} ne "ppc"} {
        default_variants +llvm34
    }

    # we purposefully don't force an llvm variant on cctools for < darwin10
    # to avoid a dependency loop. Folks who want LTO support on
    # systems prior to darwin10 can reinstall cctools with an llvm variant manually
    # see https://trac.macports.org/ticket/52091

    # If a default llvm is still not set, use +llvm10
    # this fail-safe ensures some cctools variant can build
    if {![some_llvm_variant_set] && ![variant_isset xcode] && ${os.major} >= 10 && ${configure.build_arch} ne "ppc"} {
        default_variants +llvm10
    }
}

if {[variant_isset llvm34] && ${os.major} < 11} {
    # This port is used by clang-3.4 to bootstrap libcxx
    configure.cxx_stdlib    libstdc++
}

variant xcode description "Use Xcode supplied cctools" {
    supported_archs noarch
    patchfiles
    distfiles
    build {}
    destroot {
        set xcode_cmds {bitcode-strip nm nm-classic as ar otool ranlib lipo libtool segedit strip size size-classic strings objdump}
        foreach xcode_cmd $xcode_cmds {
            set mp_cmd ${destroot}${prefix}/bin/${xcode_cmd}
            # Create script that uses xcrun to run the Xcode provided command
            system "echo '#!/bin/bash'                                          > ${mp_cmd}"
            system "echo 'if \[\[ \-x \/usr\/bin\/xcrun \]\] \; then'          >> ${mp_cmd}"
            system "echo '  exec \/usr\/bin\/xcrun ${xcode_cmd} \"\$\{\@\}\"'  >> ${mp_cmd}"
            system "echo 'elif \[\[ \-x \/usr\/bin\/${xcode_cmd} \]\] \; then' >> ${mp_cmd}"
            system "echo '  exec \/usr\/bin/${xcode_cmd} \"\$\{\@\}\"'         >> ${mp_cmd}"
            system "echo 'else'                                                >> ${mp_cmd}"
            system "echo '  exec ${xcode_cmd} \"\$\{\@\}\"'                    >> ${mp_cmd}"
            system "echo 'fi'                                                  >> ${mp_cmd}"
            # make executable
            system "chmod +x ${mp_cmd}"
        }
    }
}

destroot.args           RAW_DSTROOT=${destroot} DSTROOT=${destroot}${prefix} RC_ProjectSourceVersion=${version}

# reconfirmed 20210818 - cctools +llvm10 will not build universal on BigSur
if {${os.major} >= 20} {
    universal_variant no
} else {
    universal_variant yes
}

if {![variant_isset xcode]} {
    depends_build       port:libunwind-headers
}

post-extract {
    if {![variant_isset xcode]} {
        file copy ${worksrcpath}/../ld64-${ld64_version}/src/other/PruneTrie.cpp ${worksrcpath}/misc
        system "touch ${worksrcpath}/../ld64-${ld64_version}/src/abstraction/configure.h"
    }
}

post-patch {
    if {![variant_isset xcode]} {
        # We don't want to build cctools ld.  We want to use ld64
        reinplace "/^SUBDIRS_32/s/ld//" ${worksrcpath}/Makefile
        reinplace "/^COMMON_SUBDIRS/s/ ld / /" ${worksrcpath}/Makefile

        # Use our chosen version of llvm
        if {${llvm_version} ne ""} {
            reinplace "s:\"llvm-objdump\":\"llvm-objdump-mp-${llvm_version}\":" ${worksrcpath}/otool/main.c
            reinplace "s:\"llvm-mc\":\"llvm-mc-mp-${llvm_version}\":" ${worksrcpath}/as/driver.c
            reinplace "s:@@LLVM_LIBDIR@@:${prefix}/libexec/llvm-${llvm_version}/lib:" ${worksrcpath}/libstuff/lto.c
        }

        # List of clang versions to search for at runtime internally by 'as'
        # Build list from llvm variants, excluding clang < 5 and devel version
        # (unless devel variant is used in which case it is included first)
        set as_comps ""
        foreach variantname ${all_llvm_variants} {
            set ver $llvm_variant_version($variantname)
            # Use all non-devel and clang > 4 versions
            if { ${ver} ne "devel" && ${ver} > 4.999 } {
                if { ${as_comps} ne "" } {
                    set as_comps ",${as_comps}"
                }
                set as_comps "\"clang-mp-${ver}\"${as_comps}"
            }
        }
        # If llvmdev variant is active, include at start of list
        if {[variant_isset llvmdev]} {
            set as_comps "\"clang-mp-devel\",${as_comps}"
        }
        ui_debug "as compiler list ${as_comps}"
        reinplace "s:__MP_CLANG_NAMES__:${as_comps}:" ${worksrcpath}/as/driver.c

        if {${os.major} >= 11} {
            set try_system_clang 1
        } else {
            # clang's integrated assembler may not work well on 10.6 and doesn't
            # exist on older OS versions.
            set try_system_clang 0
        }
        reinplace "s:__TRY_SYSTEM_CLANG__:${try_system_clang}:" ${worksrcpath}/as/driver.c

        foreach file [glob ${worksrcpath}/{*/,}Makefile] {
            reinplace -q "s:/usr/local:@PREFIX@:g" ${file}
            reinplace -q "s:/usr:@PREFIX@:g" ${file}
            reinplace -q "s:@PREFIX@:${prefix}:g" ${file}
            reinplace -q "s:${prefix}/efi:${prefix}:g" ${file}
            reinplace -q "s:/Developer${prefix}:${prefix}:g" ${file}
            reinplace -q "s:${prefix}/man:${prefix}/share/man:g" ${file}

            # Don't strip installed binaries
            reinplace -q "s:\\(install .*\\)-s :\\1:g" ${file}

            if {${os.major} < 10} {
                reinplace -q "s:${prefix}/bin/mig:/usr/bin/mig:g" ${file}
            }
        }

        # macOS 10.14's SDKs have newer versions that are needed to compile
        if {${os.major} > 17} {
            file delete -force ${worksrcpath}/include/mach/i386
        }
    }
}

use_configure           no

# https://trac.macports.org/ticket/43745
configure.cflags-append -std=gnu99

build.target            all

set cxx_stdlibflags {}
if {[string match *clang* ${configure.cxx}]} {
    set cxx_stdlibflags -stdlib=${configure.cxx_stdlib}
}

configure.cppflags-append \
                        -I${worksrcpath}/../ld64-${ld64_version}/src/abstraction \
                        -I${worksrcpath}/../ld64-${ld64_version}/src/other \
                        -I${worksrcpath}/include

pre-build {
    if {![variant_isset xcode]} {
        build.args-append \
            RC_ProjectSourceVersion=${version} \
            USE_DEPENDENCY_FILE=NO \
            BUILD_DYLIBS=NO \
            CC="${configure.cc} ${configure.cflags}" \
            CXX="${configure.cxx} ${configure.cxxflags}" \
            CXXLIB="${cxx_stdlibflags}" \
            TRIE=-DTRIE_SUPPORT \
            RC_ARCHS="[get_canonical_archs]" \
            SDK="${configure.cppflags}"

        if {${llvm_version} ne ""} {
            build.args-append \
                LTO=-DLTO_SUPPORT \
                RC_CFLAGS="[get_canonical_archflags] `llvm-config-mp-${llvm_version} --cflags`" \
                LLVM_MC="llvm-mc-mp-${llvm_version}"
        } else {
            build.args-append \
                LTO= \
                RC_CFLAGS="[get_canonical_archflags]"
        }
    }
}

pre-destroot {
    if {![variant_isset xcode]} {
        destroot.args-append \
            RC_ProjectSourceVersion=${version} \
            USE_DEPENDENCY_FILE=NO \
            BUILD_DYLIBS=NO \
            CC="${configure.cc} ${configure.cflags}" \
            CXX="${configure.cxx} ${configure.cxxflags}" \
            CXXLIB="${cxx_stdlibflags}" \
            TRIE=-DTRIE_SUPPORT \
            RC_ARCHS="[get_canonical_archs]" \
            SDK="${configure.cppflags}"

        if {${llvm_version} ne ""} {
            destroot.args-append \
                LTO=-DLTO_SUPPORT \
                RC_CFLAGS="[get_canonical_archflags] `llvm-config-mp-${llvm_version} --cflags`" \
                LLVM_MC="llvm-mc-mp-${llvm_version}"
        } else {
            destroot.args-append \
                LTO= \
                RC_CFLAGS="[get_canonical_archflags]"
        }
    }
}

platform macosx {
    build.args-append RC_OS="macos"
    destroot.args-append RC_OS="macos"
}

destroot.target install_tools
destroot.args-append DSTROOT=${destroot}
post-destroot {
    if {![variant_isset xcode]} {
        file delete -force ${destroot}${prefix}/OpenSourceLicenses
        file delete -force ${destroot}${prefix}/OpenSourceVersions
        file delete -force ${destroot}${prefix}/RelNotes

        if {${os.major} < 10} {
            file delete -force ${destroot}/Developer
        }

        # Provided by port:cctools-headers
        file delete -force ${destroot}${prefix}/include

        # Older versions of llvm either don't have some tools, or they're not compatible

        file delete -force ${destroot}${prefix}/bin/nm
        file delete -force ${destroot}${prefix}/bin/size
        if {${llvm_version} eq "3.4" || ${llvm_version} eq "3.7" || ${llvm_version} eq ""} {
            ln -s nm-classic ${destroot}${prefix}/bin/nm
            ln -s size-classic ${destroot}${prefix}/bin/size

            # https://trac.macports.org/ticket/53099
            file delete -force ${destroot}${prefix}/bin/otool
            file delete -force ${destroot}${prefix}/bin/llvm-otool
            ln -s otool-classic ${destroot}${prefix}/bin/otool
        } else {
            ln -s llvm-nm-mp-${llvm_version} ${destroot}${prefix}/bin/nm
            ln -s llvm-size-mp-${llvm_version} ${destroot}${prefix}/bin/size
        }
    }
}

livecheck.type          regex
livecheck.regex         "${name}-(\[\\d.\]+)"
