#!/bin/bash
ulimit -s unlimited
shopt -s extglob

# llvm.SlackBuild
# Heavily based on the original Slackware build scripts,
# Modified by Stuart Winter for Slackware ARM.
#
# Copyright 2008-2015 Heinz Wiesinger, Amsterdam, The Netherlands
# Copyright 2012, 2013, 2014, 2015, 2016  Patrick J. Volkerding, Sebeka, MN, USA
# All rights reserved.
#
# Redistribution and use of this script, with or without modification, is
# permitted provided that the following conditions are met:
#
# 1. Redistributions of this script must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

# Record toolchain & other info for the build log:
slackbuildinfo

# Paths to skeleton port's source & real Slackware source tree:
slackset_var_cwds

# Temporary build locations:
export TMPBUILD=$TMP/build-$PKGNAM
export PKG=$TMP/package-$PKGNAM
mkpkgdirs # Delete & re-create temporary directories then cd into $TMPBUILD

# Temporary hack until slackkit and the build system is updated.
# Eventually this will be configured within slackit/buildkit.sh
# Presently it's set to null to avoid embedding it into the package
# This also needs changing in binutils, gcc and glibc once ready.
# SLK_ARCH_TARGET is set in slackkit/buildkit

# llvm is a bit ropey on ARM, so we needed to disable the sanitisers in compiler-rt:
#  http://lists.llvm.org/pipermail/llvm-dev/2016-May/099915.html
case $ARCH in
   # Use -g1 to decrease debuginfo verbosity to reduce memory consumption during final library linking
   #  -std=c++0x << needed for compiling with gcc (not with gcc 9 and llvm8)
   #  -std=c++11 is taken from Fedora's libcxxabi-8.0.0-1.fc31.src.rpm spec file
   arm|aarch64)  export SLKCFLAGS="$SLKCFLAGS -g1 -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -DNDEBUG"
                 export SLKCXXFLAGS="$SLKCFLAGS -std=c++11"
                 #export SLKCONFARGS="-DCOMPILER_RT_BUILD_BUILTINS=OFF \
                 export SLKCONFARGS="-DLLVM_HOST_TRIPLE=${SLK_ARCH_TARGET} -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON"
                 # export LDFLAGS="-Wl,-z,relro,--build-id"
                 export LDFLAGS="-Wl,-z,relro -Wl,--as-needed -Wl,-z,now";;
   *)            export SLKCFLAGS="-O2" ;;
esac

# Python2 short version:
PY2=$(python -c 'from distutils.sysconfig import get_python_lib; print(get_python_lib())' | cut -f 2 -d n | cut -f 1 -d /)
# Python3 short version:
PY3=$(python3 -c 'from distutils.sysconfig import get_python_lib; print(get_python_lib())' | cut -f 2 -d n | cut -f 1 -d /)

# Determine whether we should build with gcc or clang.
# If clang is present (as post boot strap) we'll build with that (as x86 upstream does)
# otherwise we'll build with gcc.
# r2b needs to be called with -b|--slackware-bootstrap
#if [ "$R2B_SLKBOOTSTRAP" = "Yes" ]; then
#   echo "*** Bootstrapping Slackware: using gcc to build llvm"
#   CCOMPILER=gcc
#   CPPCOMPILER=g++
# else
#   # Slackware x86 builds LLVM with clang, so we do too.
#   # I think this 'which' below used to be part of something more compact.
#   # Think of this as 'Unix art' ;-)
#   which clang > /dev/null 2>&1 && { CCOMPILER=clang ; CPPCOMPILER=clang++ ;}
#fi
#echo "Building LLVM using this compiler: $CCOMPILER / $CPPCOMPILER"

# Build options:
# ARM note: we're not explicitly disabling clangd for ARM but it doesn't
# get built automatically, where as it does on aarch64.
case $ARCH in
  arm)     BUILD_LLD=YES
           CCOMPILER=clang
           CPPCOMPILER=clang++ ;;
  aarch64) BUILD_LLD=YES
           # This broke with llvm12 - will be addressed later so llvm is self-hosting again:
           CCOMPILER=gcc
           CPPCOMPILER=g++ ;;
    *) unset CLANGD ;;
esac

# Extract source:
echo "Extracting source - will take a few minutes.."
tar xf $CWD/$PKGNAM-$VERSION.src.tar.!(*sign|*asc|*sig) || exit 1

cd $PKGNAM-${VERSION}/tools 2> /dev/null || cd $PKGNAM-${VERSION}.src/tools || exit 1
  tar xf $CWD/clang-$VERSION.src.tar.xz || exit 1
  mv clang-${VERSION} clang 2>/dev/null || mv clang-${VERSION}.src clang || exit 1
  #tar xvf $CWD/flang-$VERSION.src.tar.xz || exit 1
  #mv flang-${VERSION} flang 2>/dev/null || mv flang-${VERSION}.src flang || exit 1
  tar xf $CWD/lldb-$VERSION.src.tar.!(*sign|*asc|*sig) || exit 1
  mv lldb-${VERSION} lldb 2>/dev/null || mv lldb-${VERSION}.src lldb || exit 1
  if [ "$BUILD_LLD" = "YES" ]; then
     tar xvf $CWD/lld-$VERSION.src.tar.xz || exit 1
     mv lld-${VERSION} lld 2>/dev/null || mv lld-${VERSION}.src lld || exit 1
  fi
cd ../

cd tools/clang/tools || exit 1
  tar xf $CWD/clang-tools-extra-$VERSION.src.tar.!(*sign|*asc|*sig) || exit 1
  mv -fv clang-tools-extra-${VERSION} extra 2>/dev/null || mv -fv clang-tools-extra-${VERSION}.src extra || exit 1
  # HACK # Otherwise the build fails because files aren't found.
  rm -rf $TMPBUILD/clang-tools-extra
  cp -a extra $TMPBUILD/clang-tools-extra
cd ../../../

cd projects || exit 1
  tar xf $CWD/compiler-rt-$VERSION.src.tar.!(*sign|*asc|*sig) || exit 1
  mv -fv compiler-rt-${VERSION} compiler-rt 2>/dev/null || mv -fv compiler-rt-${VERSION}.src compiler-rt || exit 1
  tar xf $CWD/openmp-$VERSION.src.tar.!(*sign|*asc|*sig) || exit 1
  mv openmp-${VERSION} openmp 2>/dev/null|| mv openmp-${VERSION}.src openmp || exit 1
  tar xf $CWD/libcxx-${VERSION}.src.tar.!(*sign|*asc|*sig) || exit 1
  mv libcxx-${VERSION} libcxx 2>/dev/null || mv libcxx-${VERSION}.src libcxx || exit 1
  tar xf $CWD/libcxxabi-${VERSION}.src.tar.!(*sign|*asc|*sig) || exit 1
  mv libcxxabi-${VERSION} libcxxabi 2>/dev/null || mv libcxxabi-${VERSION}.src libcxxabi || exit 1
  tar xvf $CWD/polly-$VERSION.src.tar.xz || exit 1
  mv polly-${VERSION} polly 2>/dev/null || mv polly-${VERSION}.src polly || exit 1
  # We just need a header file from this...
  tar xvf $CWD/libunwind-${VERSION}.src.tar.xz || exit 1
  mv -fv libunwind-${VERSION} libunwind || mv -fv libunwind-${VERSION}.src libunwind || exit 1
cd ../

# Set sane permissions and ownerships:
( cd $TMPBUILD ; slackhousekeeping )

# Support GCC built for i586-slackware-linux:
zcat $CWD/clang.toolchains.i586.triple.diff.gz | patch -p1 --verbose || exit 1

# Hack to fix build with polly. Maybe we should just not use polly... ?
zcat $CWD/llvm.polly.hack.diff.gz | patch -p1 --verbose || exit 1

################ ARM modifications ################################################

# Taken from Fedora spec file:
# These tests are marked as XFAIL, but they still run and hang on ARM.
for f in `grep -Rl 'XFAIL.\+arm' test/ExecutionEngine `; do  rm -fv $f; done

# This hack comes from the libcxxabi package's spec file, not llvm:
# Slackware unpacks the libcxxabi archive bundled with the llvm source (above) and move it in to place.
# https://kojipkgs.fedoraproject.org/packages/libcxxabi/5.0.1/1.fc28/data/logs/armv7hl/build.log
sed -i 's|#define _LIBCXXABI_ARM_EHABI||g' projects/libcxxabi/include/__cxxabi_config.h || exit 1

############ End ARM modifications ################################################

# Configure:
# need to disable assertions to make llvm thread-safe
# clang resource dir is a relative path based on the location of the clang binary
#
# Note: Anything separated by multiple '\' has been added for ARM.
#
mkdir build
cd build
  mkdir include
  # Copy this LLVM libunwind header or it won't be found:
  cp -a ../projects/libunwind/include/mach-o include
  # Nuke LLVM libunwind as it conflicts with the one already on the system:
  rm -r ../projects/libunwind
  cmake -GNinja \
   \
   \
   $SLKCONFARGS \
   \
   \
    -DCMAKE_C_COMPILER="$CCOMPILER" \
    -DCMAKE_CXX_COMPILER="$CPPCOMPILER" \
    -DCMAKE_C_FLAGS:STRING="$SLKCFLAGS" \
    -DCMAKE_CXX_FLAGS:STRING="$SLKCXXFLAGS" \
    -DCMAKE_INSTALL_PREFIX=/usr \
    -DLLVM_LIBDIR_SUFFIX=${LIBDIRSUFFIX} \
    -DCMAKE_BUILD_TYPE=Release \
    -DBUILD_SHARED_LIBS=ON \
    -DLLVM_USE_LINKER=gold \
    -DLLVM_ENABLE_RTTI=ON \
    -DLLVM_ENABLE_FFI=ON \
    -DLLVM_ENABLE_ASSERTIONS=OFF \
    -DLLVM_INSTALL_UTILS=ON \
    -DLLVM_BINUTILS_INCDIR=/usr/include \
    -DCLANG_RESOURCE_DIR="../lib${LIBDIRSUFFIX}/clang/${VERSION}" \
    -DLLVM_TARGETS_TO_BUILD="host;AMDGPU;BPF" \
    -DLLDB_USE_SYSTEM_SIX=1 \
    $CLANGD \
    .. || exit 1

# Switch errors back to warnings:
pushd ..
find . -type f -iname '*make*' -print0 | xargs -0 sed -i 's?-Werror=?-Wno-error=?g'
popd

# Build:
# We'll leave 1 core free to keep the machine running smoothly:
export NUMJOBS="-j$(( $(nproc) -1 ))"
"${NINJA:=ninja}" $NUMJOBS || ${NINJA} || failmake

# Install into package framework:
DESTDIR=$PKG "$NINJA" install || exit 1
cd ..

# Add symlinks for ${SLK_ARCH_TARGET}-{clang,clang++}:
( cd $PKG/usr/bin
#  ln -vsf clang ${SLK_ARCH_TARGET}-clang
#  ln -vsf clang++ ${SLK_ARCH_TARGET}-clang++
  ln -vsf clang ${SLK_ARCH_TARGET}-clang
  ln -vsf clang++ ${SLK_ARCH_TARGET}-clang++ )

# Install clang-static-analyzer:
for i in ccc c++; do
  ln -vfs /usr/libexec/$i-analyzer \
    $PKG/usr/bin/$i-analyzer || exit 1
done

# Ensure lit-cpuid is installed:
if [ ! -r $PKG/usr/bin/lit-cpuid ]; then
   install -vpm755 build/bin/lit-cpuid $PKG/usr/bin/lit-cpuid
fi

# Remove symlink to libgomp, which is already provided by gcc
rm -f $PKG/usr/lib$LIBDIRSUFFIX/libgomp.so

# Install Python bindings:
for pyver in ${PY2} ${PY3}; do
  mkdir -p "$PKG/usr/lib$LIBDIRSUFFIX/python$pyver/site-packages"
  cp -a tools/clang/bindings/python/clang "$PKG/usr/lib$LIBDIRSUFFIX/python$pyver/site-packages/"
done

# Remove bundled python-six
rm -f "$PKG/usr/lib$LIBDIRSUFFIX/python${PY2}/site-packages/six.py"

# Compile Python scripts:
python -m compileall "$PKG/usr/lib$LIBDIRSUFFIX/python${PY2}/site-packages/clang"
python -O -m compileall "$PKG/usr/lib$LIBDIRSUFFIX/python${PY2}/site-packages/clang"
python3 -m compileall "$PKG/usr/lib$LIBDIRSUFFIX/python${PY3}/site-packages/clang"
python3 -O -m compileall "$PKG/usr/lib$LIBDIRSUFFIX/python${PY3}/site-packages/clang"
python -m compileall "$PKG/usr/lib$LIBDIRSUFFIX/python${PY2}/site-packages/lldb"
python -O -m compileall "$PKG/usr/lib$LIBDIRSUFFIX/python${PY2}/site-packages/lldb"
python -m compileall "$PKG/usr/share/scan-view"
python -O -m compileall "$PKG/usr/share/scan-view"
python -m compileall "$PKG/usr/share/clang"
python -O -m compileall "$PKG/usr/share/clang"
python -m compileall "$PKG/usr/share/opt-viewer"
python -O -m compileall "$PKG/usr/share/opt-viewer"

# Move man page directory:
mv -fv $PKG/usr/share/man $PKG/usr/

# Add documentation:
mkdir -vpm755 $PKG/usr/doc/$PKGNAM-$VERSION/{clang,lldb,clang-tools-extra,compiler-rt,openmp,polly}
cp -fav CREDITS* LICENSE* README* $PKG/usr/doc/$PKGNAM-$VERSION
cp -fav tools/clang/{INSTALL,LICENSE,NOTES,README}* \
  $PKG/usr/doc/$PKGNAM-$VERSION/clang
cp -fav tools/lldb/{CODE_OWNERS,INSTALL,LICENSE}* \
  $PKG/usr/doc/$PKGNAM-$VERSION/lldb
cp -fav tools/clang/tools/extra/{CODE_OWNERS,LICENSE,README}* \
  $PKG/usr/doc/$PKGNAM-$VERSION/clang-tools-extra
cp -fav projects/compiler-rt/{CODE_OWNERS,CREDITS,LICENSE,README}* \
  $PKG/usr/doc/$PKGNAM-$VERSION/compiler-rt
cp -fav projects/openmp/{CREDITS,LICENSE}* \
  $PKG/usr/doc/$PKGNAM-$VERSION/openmp
cp -fav projects/polly/{CREDITS,LICENSE,README}* \
  $PKG/usr/doc/$PKGNAM-$VERSION/polly
mv -fv $PKG/usr/docs/llvm/* $PKG/usr/doc/$PKGNAM-$VERSION
rm -rf $PKG/usr/docs

#changelogliposuction ChangeLog $PKGNAM $VERSION # Trim down a "ChangeLog" file

# Apply generic Slackware packaging policies:
cd $PKG
slackstripall   # strip all .a archives and all ELFs
#slackstriprpaths     # strip rpaths
slack_delete_lafiles # delete usr/lib{,64}/*.la
slackgzpages -i # compress man & info pages and delete usr/info/dir
slackslack      # set standard Slackware file/dir permissions and ownerships
slackdesc       # install slack-desc and doinst.sh
slackmp         # run makepkg -l y -c n

# Perform any final checks on the package:
cd $PKG
slackhlinks     # search for any hard links
