#!/bin/sh -ex
#
# Couple of useful links:
# + http://pcc.ludd.ltu.se/cross-compiler/
# + http://wiki.osdev.org/Cross-Compiler_Successful_Builds
# + https://git.framasoft.org/Ypnose/solyste/blob/master/scripts/create-crossenv
# + http://kegel.com/crosstool/
# + https://github.com/GregorR/musl-cross/tree/master/patches
#
# 0. download and extract sources
# 1. patch everything that require patching
# 2. install linux headers
# 3. build binutils
# 4. build musl
# 5. build pcc with gcc
# 6. add pkg-config wrapper

# cross compiler environment
MARCH=$(uname -m)
TRIPLE=${TRIPLE:-${MARCH}-linux-musl}
PREFIX=${PREFIX:-${HOME}/cross/pcc-${MARCH}}
BLDDIR=${BLDDIR:-${HOME}/cross/build}
SRCDIR=${SRCDIR:-${HOME}/cross/source}
PATCHD=${PATCHD:-${HOME}/cross/patches}

# compilation variables
PATH="${PREFIX}/bin:${PATH}"
CFLAGS="-Os -fomit-frame-pointer -pipe"
CXXFLAGS="${CFLAGS}"
CPPFLAGS="${CFLAGS}"
LDFLAGS="-Wl,--as-needed"
MAKEFLAGS="-j8"

# versions
PCCV=${PCCV:-1.1.0}
BINV=${BINV:-2.25}
MUSLV=${MUSLV:-1.1.10}
KERNV=${KERNV:-4.1.4}


# source mirrors
PCCMIRROR=ftp://pcc.ludd.ltu.se/pub/pcc-releases
GNUMIRROR=ftp://ftp.gnu.org/gnu
MUSLMIRROR=http://www.musl-libc.org/releases
LINUXMIRROR=https://www.kernel.org/pub/linux/kernel/v4.x

# Preparing sources
mkdir -p "${SRCDIR}" "${BLDDIR}" "${PREFIX}"
cd "${SRCDIR}"

# 
# ┏━┓ 
# ┃┃┃ 
# ┗━┛╹
# Get all GNU tarballs
grab_sources() {
curl -# "${PCCMIRROR}/pcc-${PCCV}.tgz"                          | tar xz
curl -# "${PCCMIRROR}/pcc-libs-${PCCV}.tgz"                     | tar xz
curl -# "${GNUMIRROR}/binutils/binutils-${BINV}.tar.gz"         | tar xz
curl -# "${MUSLMIRROR}/musl-${MUSLV}.tar.gz"                    | tar xz
curl -# "${LINUXMIRROR}/linux-${KERNV}.tar.xz"                  | tar xJ
}

#
# ╺┓  
#  ┃  
# ╺┻╸╹
# Patch all source trees.
# This will take all patches in $PATCHD matching the programs
patch_sources() {
for DIR in $(find "${SRCDIR}" -maxdepth 1 -type d); do
        cd "${DIR}"
        cat "${PATCHD}/$(basename ${DIR})"-*.diff | patch -Np1
done
}

#
# ┏━┓ 
# ┏━┛ 
# ┗━╸╹
# Get linux headers
install_headers() {
cd "${SRCDIR}/linux-${KERNV}"
make ARCH=${MARCH} headers_check
make ARCH=${MARCH} INSTALL_HDR_PATH=${PREFIX}/${TRIPLE} headers_install
rm -r "${SRCDIR}/linux-${KERNV}"
}

#
# ┏━┓ 
# ╺━┫ 
# ┗━┛╹
# Build binutils and install them to ${PREFIX}
install_binutils() {
mkdir -p "${BLDDIR}/binutils"
cd "${BLDDIR}/binutils"
${SRCDIR}/binutils-${BINV}/configure --target=${TRIPLE} \
                                     --prefix=${PREFIX} \
                                     --with-sysroot=${PREFIX}/${TRIPLE} \
                                     --disable-nls \
                                     --disable-shared \
                                     --disable-multilib
make configure-host
make LDFLAGS="${LDFLAGS} -all-static -static"
make install
rm -rf "${BLDDIR}/binutils"
rm -rf "${SRCDIR}/binutils-${BINV}"
}

#
# ╻ ╻ 
# ┗━┫ 
#   ╹╹
# Build the musl libc
install_musl() {
cd "${SRCDIR}/musl-${MUSLV}"
./configure --prefix=${PREFIX}/${TRIPLE} \
            --target=${TRIPLE} \
            --disable-gcc-wrapper \
            --disable-debug \
            --disable-shared \
            --disable-warning
make LDFLAGS="${LDFLAGS}"
make install
rm -rf "${SRCDIR}/musl-${MUSLV}"
}

#
# ┏━╸ 
# ┗━┓ 
# ┗━┛╹
# Build pcc linked against musl
install_pcc() {
mkdir -p "${BLDDIR}/pcc"
mkdir -p "${BLDDIR}/pcc-libs"
cd "${BLDDIR}/pcc"
${SRCDIR}/pcc-${PCCV}/configure --target=${TRIPLE} \
                                --with-libdir=${PREFIX}/${TRIPLE}/lib \
                                --with-incdir=${PREFIX}/${TRIPLE}/include \
                                --prefix=${PREFIX}

make LDFLAGS="${LDFLAGS} -static" \
     PCCLIBDIR=${PREFIX}/${TRIPLE}/pcc/lib \
     PCCINCDIR=${PREFIX}/${TRIPLE}/pcc/include
make PCCLIBDIR=${PREFIX}/${TRIPLE}/pcc/lib \
     PCCINCDIR=${PREFIX}/${TRIPLE}/pcc/include \
     install
rm -rf "${BLDDIR}/pcc"
rm -rf "${SRCDIR}/pcc-${PCCV}"
}

#
# ┏━┓ 
# ┣━┓ 
# ┗━┛╹
# Build pcc libraries against musl
install_pcc_libs() {
cd "${BLDDIR}/pcc-libs"
${SRCDIR}/pcc-libs-${PCCV}/configure --target=${TRIPLE} \
                                     --prefix=${PREFIX}

make PCCLIBDIR=${PREFIX}/${TRIPLE}/pcc/lib \
     PCCINCDIR=${PREFIX}/${TRIPLE}/pcc/include
make PCCLIBDIR=${PREFIX}/${TRIPLE}/pcc/lib \
     PCCINCDIR=${PREFIX}/${TRIPLE}/pcc/include \
     install
rm -rf "${BLDDIR}/pcc-libs"
rm -rf "${SRCDIR}/pcc-libs-${PCCV}"
}

#
# ┏━┓ 
#   ┃ 
#   ╹╹
# Add pkg-config wrapper
install_pkgconfig() {
cat << EOF > "${PREFIX}/bin/${TRIPLE}-pkg-config"
#!/bin/sh
export PKG_CONFIG_SYSROOT_DIR=${PREFIX}/${TRIPLE}
export PKG_CONFIG_LIBDIR=${PREFIX}/${TRIPLE}/usr/lib/pkgconfig
export PKG_CONFIG_PATH=\$PKG_CONFIG_LIBDIR

exec pkg-config --static "\$@"
EOF
chmod 755 "${PREFIX}/bin/${TRIPLE}-pkg-config"
}

grab_sources
patch_sources
install_headers
install_binutils
install_musl
install_pcc
install_pcc_libs
install_pkgconfig

# clean environment
rm -rf "${SRCDIR}"
rm -rf "${BLDDIR}"
rm -rf "${PREFIX}/share"
rm -f  "${PREFIX}/lib/libiberty.a"

cat << EOF | tee ${PREFIX}/README
TRIPLET :       $TRIPLE
PREFIX  :       $PREFIX
PCC     :       $PCCV
BINUTILS:       $BINV
MUSL    :       $MUSLV
KERNEL  :       $KERNV
EOF
