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

name                arm-elf-gcc
version             4.7.3
revision            1
set branch          [join [lrange [split ${version} .] 0 1] .]
conflicts           arm-elf-gcc3

# Parameters for this port.
set newlibversion   1.20.0
set crossgcc-target arm-elf
set default-languages --enable-languages="c,c++,objc"

description         gcc cross-compilers for arm-elf, with newlib runtime library.
long_description    gnu compilers collection (including c++ and objc) for \
                    arm-elf, with newlib runtime library.
homepage            https://gcc.gnu.org/
platforms           darwin
categories          cross devel
maintainers         nomaintainer
# an exception in the license allows dependents to not be GPL
license             {GPL-3+ Permissive}
master_sites        gnu:gcc/gcc-${version}/:gcc \
                    ftp://sources.redhat.com/pub/newlib/:newlib \
                    https://www.mirrorservice.org/sites/sourceware.org/pub/newlib/:newlib
distfiles           gcc-${version}.tar.bz2:gcc newlib-${newlibversion}.tar.gz:newlib
worksrcdir          gcc-${version}

checksums           gcc-${version}.tar.bz2 \
                    rmd160  b4ba153b098cad726ecd28195ee445aa542d37ae \
                    sha256  2f7c37eb4fc14422ff2358a9ef59c974a75ab41204ef0e49fc34ab1d8981a9c3 \
                    newlib-${newlibversion}.tar.gz \
                    rmd160  e36c5337a74633456b47d09594974c7dd7a9cc3e \
                    sha256  c644b2847244278c57bec2ddda69d8fab5a7c767f3b9af69aa7aa3da823ff692

patchfiles          patch-gcc-config-arm-t-arm-elf.diff

# All cross ports violate the mtree layout.
destroot.violate_mtree  yes

# Download everything to gcc/
dist_subdir         gcc

depends_lib         port:${crossgcc-target}-binutils \
                    port:gmp \
                    port:mpfr \
                    port:gettext \
                    port:libmpc

# arm-elf-binutils is not universal
universal_variant   no

# gcc is .bz2, newlib is .gz.
# let's extract only gcc with MacPorts infrastructure, we'll do newlib manually.
use_bzip2           yes
extract.only        gcc-${version}.tar.bz2

# Extract newlib and create a symlink of newlib/newlib in gcc directory.
post-extract    {
    system "cd ${workpath} && gzip -dc ${distpath}/newlib-${newlibversion}.tar.gz | tar -xf -"
    system "ln -s ${workpath}/newlib-${newlibversion}/newlib ${workpath}/gcc-${version}/"
}

# Since we don't build gcc and binutils at the same time, gcc's Makefile will try to transform
# program names as gcc's name (add -${version} with ${version} being the version of gcc).
# But it won't work because binutils binaries don't have the ${version} suffix, and even if they
# had, they would actually have the binutils' version suffix (and not gcc's version).
# So let's tell gcc's Makefile not to do that mistake.

set environment [list AR_FOR_TARGET=${crossgcc-target}-ar \
                AS_FOR_TARGET=${crossgcc-target}-as \
                LD_FOR_TARGET=${crossgcc-target}-ld \
                NM_FOR_TARGET=${crossgcc-target}-nm \
                RANLIB_FOR_TARGET=${crossgcc-target}-ranlib]

proc multilibpatch_enable { options dirnames exceptions matches } {
    global worksrcpath
    system "echo 'MULTILIB_OPTIONS += ${options}' >> ${worksrcpath}/gcc/config/arm/t-arm-elf"
    system "echo 'MULTILIB_DIRNAMES += ${dirnames}' >> ${worksrcpath}/gcc/config/arm/t-arm-elf"
    system "echo 'MULTILIB_EXCEPTIONS += ${exceptions}' >> ${worksrcpath}/gcc/config/arm/t-arm-elf"
    system "echo 'MULTILIB_MATCHES += ${matches}' >> ${worksrcpath}/gcc/config/arm/t-arm-elf"
}

variant be description {big endian multilib support} {
    post-patch {
        multilibpatch_enable \
            "mlittle-endian/mbig-endian" \
            "le be" \
            "" \
            "mbig-endian=mbe mlittle-endian=mle"
    }
}

variant ep9312 description {ep9312 multilib support} {
    post-patch {
        multilibpatch_enable \
            "mcpu=ep9312" \
            "ep9312" \
            "*mthumb/*mcpu=ep9312* *mcpu=ep9312*/*mhard-float*" \
            ""
    }
}

variant fpu description {fpu multilib support} {
    post-patch {
        multilibpatch_enable \
            "mhard-float/msoft-float" \
            "fpu soft" \
            "*mthumb/*mhard-float*" \
            ""
    }
    configure.args-append   --enable-fpu
}

variant interwork description {thumb interwork multilib support} {
    post-patch {
        multilibpatch_enable \
            "mno-thumb-interwork/mthumb-interwork" \
            "normal interwork" \
            "" \
            ""
    }
    configure.args-append   --enable-interwork
}

variant under description {leading underscore multilib support} {
    post-patch {
        multilibpatch_enable \
            "fno-leading-underscore/fleading-underscore" \
            "elf under" \
            "" \
            ""
    }
    configure.args-append   --enable-underscore
}

variant nofmult description {no fpu multiplication multilib support} {
    post-patch {
        multilibpatch_enable \
            "mcpu=arm7" \
            "nofmult" \
            "*mthumb*/*mcpu=arm7*" \
            ""
    }
    configure.args-append   --enable-nofmult
}

# Fails to build with llvm-gcc, at least in Xcode 4.1; use clang (#29551)
compiler.blacklist-append  *llvm-gcc-4.2

# Build in a different directory, as advised in the README file.
pre-configure   {
    file mkdir "${workpath}/build"
}
configure.dir   ${workpath}/build
configure.cmd   ${workpath}/gcc-${version}/configure
configure.cc-append    -I${prefix}/include
configure.env   ${environment}
configure.args  --infodir='${prefix}/share/info' \
                --mandir='${prefix}/share/man' \
                --target=${crossgcc-target} \
                --program-prefix=${crossgcc-target}- \
                --program-suffix=-${branch} \
                --without-included-gettext \
                --enable-obsolete \
                --with-newlib \
                --disable-__cxa_atexit \
                --enable-multilib \
                --enable-biendian \
                --disable-libgfortran \
                --with-gxx-include-dir=${prefix}/${crossgcc-target}/include/c++/${version}/ \
                ${default-languages}
configure.cc_archflags
configure.cxx_archflags
configure.objc_archflags
configure.ld_archflags
if {${os.platform} eq "darwin" && (${build_arch} eq "x86_64" || ${build_arch} eq "ppc64")} {
    configure.args-append --build=${build_arch}-apple-darwin${os.major}
}

# the bootstrap compiler doesn't accept -stdlib
configure.cxx_stdlib

build.dir       ${workpath}/build

build.args      ${environment}
destroot.args   ${environment}

post-patch {
    namespace eval crossgcc {}

    # Fix the info pages and related stuff.
    #
    # path: path to the doc directory (e.g. gas/doc/)
    # makefile: path to Makefile.in (e.g. gas/doc/Makefile.in)
    # name: name of the info page (e.g. as)
    # suffix: suffix of the souce page (texinfo or texi)
    proc crossgcc::fixinfo { path makefile name suffix } {
        global crossgcc-target worksrcpath

        # Fix the source
        reinplace "s|setfilename ${name}.info|setfilename ${crossgcc-target}-${name}.info|g" \
            ${worksrcpath}/${path}/${name}.${suffix}
        reinplace "s|(${name})|(${crossgcc-target}-${name})|g" \
            ${worksrcpath}/${path}/${name}.${suffix}
        reinplace "s|@file{${name}}|@file{${crossgcc-target}-${name}}|g" \
            ${worksrcpath}/${path}/${name}.${suffix}

        # Fix the Makefile
        reinplace "s| ${name}.info| ${crossgcc-target}-${name}.info|g" \
            ${worksrcpath}/${makefile}
        reinplace "s|/${name}.info|/${crossgcc-target}-${name}.info|g" \
            ${worksrcpath}/${makefile}
        reinplace "s|^${name}.info|${crossgcc-target}-${name}.info|g" \
            ${worksrcpath}/${makefile}
        reinplace "s| ${name}.pod| ${crossgcc-target}-${name}.pod|g" \
            ${worksrcpath}/${makefile}
        reinplace "s|/${name}.pod|/${crossgcc-target}-${name}.pod|g" \
            ${worksrcpath}/${makefile}
        reinplace "s|^${name}.pod|${crossgcc-target}-${name}.pod|g" \
            ${worksrcpath}/${makefile}
        reinplace "s| ${name}.${suffix}| ${crossgcc-target}-${name}.${suffix}|g" \
            ${worksrcpath}/${makefile}
        reinplace "s|/${name}.${suffix}|/${crossgcc-target}-${name}.${suffix}|g" \
            ${worksrcpath}/${makefile}
        reinplace "s|^${name}.${suffix}|${crossgcc-target}-${name}.${suffix}|g" \
            ${worksrcpath}/${makefile}

        # Rename the source
        file rename ${worksrcpath}/${path}/${name}.${suffix} \
            ${worksrcpath}/${path}/${crossgcc-target}-${name}.${suffix}

        # Fix install-info's dir.
        # (note: this may be effectless if there was no info dir to be fixed)
        reinplace "s|--info-dir=\$(DESTDIR)\$(infodir)|--dir-file=\$(DESTDIR)\$(infodir)/${crossgcc-target}-gcc-dir|g" \
            "${worksrcpath}/${makefile}"
    }

    # Fix the gettext files and related stuff.
    #
    # module: name of the module (e.g. gas)
    proc crossgcc::fixgettext { module } {
        global crossgcc-target worksrcpath

        if { [ file exists "${worksrcpath}/${module}/Makefile.in" ] } {
            reinplace "s|@PACKAGE@|${crossgcc-target}-@PACKAGE@|g" \
                "${worksrcpath}/${module}/Makefile.in"
            reinplace "s|${module}\.mo|${crossgcc-target}-${module}.mo|g" \
                "${worksrcpath}/${module}/Makefile.in"
        }
        if { [ file exists "${worksrcpath}/${module}/doc/Makefile.in" ] } {
            reinplace "s|@PACKAGE@|${crossgcc-target}-@PACKAGE@|g" \
                "${worksrcpath}/${module}/doc/Makefile.in"
        }
    }

    # gcc/doc/cpp.texi
    crossgcc::fixinfo gcc/doc/ gcc/Makefile.in cpp texi

    # gcc/doc/cppinternals.texi
    crossgcc::fixinfo gcc/doc/ gcc/Makefile.in cppinternals texi

    # gcc/doc/gcc.texi
    crossgcc::fixinfo gcc/doc/ gcc/Makefile.in gcc texi

    # gcc/doc/gccint.texi
    crossgcc::fixinfo gcc/doc/ gcc/Makefile.in gccint texi

    # gcc/fortran/gfortran.texi
    crossgcc::fixinfo gcc/fortran/ gcc/fortran/Make-lang.in gfortran texi

    # gcc/java/gcj.texi
    crossgcc::fixinfo gcc/java/ gcc/java/Make-lang.in gcj texi

    # gcc/doc/gccinstall.info
    crossgcc::fixinfo gcc/doc/ gcc/Makefile.in gccinstall info

    # gettext stuff.
    crossgcc::fixgettext gcc
    crossgcc::fixgettext libcpp
}

pre-destroot {
    # gcc needs the cross directory structure to be present
    # in order to fill it during installation.
    file mkdir "${destroot}${prefix}/${crossgcc-target}/bin"
    file mkdir "${destroot}${prefix}/${crossgcc-target}/lib"
}

post-destroot {
    namespace eval crossgcc {}

    # Rename a man page if it exists.
    #
    # section: section of the man page (e.g. 1)
    # manpage: name of the man page (e.g. cpp)
    proc crossgcc::rename_man_page { section manpage } {
        global crossgcc-target destroot prefix

        set manpage_path "${destroot}${prefix}/share/man/man${section}/${manpage}.${section}"
        if { [ file exists ${manpage_path} ] } {
            file rename ${manpage_path} \
                "${destroot}${prefix}/share/man/man${section}/${crossgcc-target}-${manpage}.${section}"
        }
    }

    # Stuff I don't want (either because they're in the system
    # or because they would conflict with other FSF ports)
    # (it's easier for maintainability purposes to fix things here)

    # aliases for locales (should be on the system)
    file delete "${destroot}${prefix}/share/locale/locale.alias"

    # FSF propaganda (should already be there or would conflict)
    file delete -force "${destroot}${prefix}/share/man/man7"

    # (host) libiberty
    foreach f [glob -directory "${destroot}${prefix}/lib" libiberty.a */libiberty.a] {
        file delete $f
    }

    # aliases for charsets (should already be there)
    file delete "${destroot}${prefix}/lib/charset.alias"

    # Remove man pages for tools that are not built as part of cross-gcc
    file delete "${destroot}${prefix}/share/man/man1/rmic.1"
    file delete "${destroot}${prefix}/share/man/man1/rmiregistry.1"
    file delete "${destroot}${prefix}/share/man/man1/jv-convert.1"
    file delete "${destroot}${prefix}/share/man/man1/gij.1"

    # For some reason, some man pages are not prefixed while they should have been
    # (to avoid conflicting).
    crossgcc::rename_man_page 1 cpp
    crossgcc::rename_man_page 1 gcjh
    crossgcc::rename_man_page 1 gcov
    crossgcc::rename_man_page 1 jcf-dump
    crossgcc::rename_man_page 1 jv-scan

    # There is a bug in gcc/Makefile::install-driver
    # For cross compilers, $(GCC_INSTALL_NAME) is equal to
    # $(target_noncanonical)-gcc-$(version)
    # and hence the driver isn't installed.
    xinstall -c "${workpath}/build/gcc/xgcc" \
        "${destroot}${prefix}/bin/${crossgcc-target}-gcc-${version}"
}

livecheck.type      regex
livecheck.url       https://gcc.gnu.org/releases.html
livecheck.regex     {<tr><td><a href="gcc-.*/">GCC (.*)</a></td>   <td>.*</td></tr>}