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

# llvm.SlackBuild
# Heavily based on the original Slackware build scripts,
# Copyright 2008-2025 Stuart Winter, Donostia, Spain.
#
# Copyright 2008-2015 Heinz Wiesinger, Amsterdam, The Netherlands
# Copyright 2012-2026  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:
# Use the regular location, since this location is embedded within the package
# contents in places:
shm_tmp # Use /dev/shm if >8GB RAM is available & not mounted 'noexec'
export TMPBUILD=$TMP/build-$PKGNAM
export PKG=$TMP/package-$PKGNAM
mkpkgdirs # Delete & re-create temporary directories then cd into $TMPBUILD

# Select projects to build:
if [ "$ARCH" = "i586" -o "$ARCH" = "i686" ]; then
  # bolt and flang are not available on 32-bit
  LLVM_ENABLE_PROJECTS=${LLVM_ENABLE_PROJECTS:-"clang;clang-tools-extra;lld;lldb;llvm;mlir;polly"}
else
  LLVM_ENABLE_PROJECTS=${LLVM_ENABLE_PROJECTS:-"bolt;clang;clang-tools-extra;flang;lld;lldb;llvm;mlir;polly"}
fi

# Select runtimes to build:
LLVM_ENABLE_RUNTIMES=${LLVM_ENABLE_RUNTIMES:-"compiler-rt;openmp;libcxx;libcxxabi"}

# Ignore that which should be ignored to avoid long build times and
# massive warning spew:
#
# ARM note: these flags are relevant when self-hosting (llvm compiles llvm) but
# we're using gcc, since llvm cannot self host on aarch64 (at least for me), plus
# we have a x86 x-toolchain for gcc but not llvm, which enables us to benefit from
# the speed improvements gained from using x86 cores.
# These don't cause any issues with gcc, so we'll leave them in.
IGNORE_GNU_EXTENSIONS=${IGNORE_GNU_EXTENSIONS:--Wno-unknown-warning-option -Wno-gnu-line-marker -Wno-gnu-anonymous-struct -Wno-gnu-include-next}

# LLVM 18: Commented -g1.. CFLAGS & LDFLAGS as they're not required on the HoneyCombLX2 with 32GB RAM.
#          Switched to building with clang as gcc can no longer build llvm.
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
   #                https://src.fedoraproject.org/rpms/libcxx (renamed from libcxxabi)
   aarch64)  export SLKCFLAGS="$SLKCFLAGS $IGNORE_GNU_EXTENSIONS" # -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
             #-DLLVM_ENABLE_LIBCXX=ON was to enable switching target triplet
             # Host target triplet=aarch64-slackware-linux-gnu (GCC's path /usr/lib64/gcc/)
             #export SLKCONFARGS="-DLLVM_ENABLE_LIBCXX=ON -DLLVM_DEFAULT_TARGET_TRIPLE=aarch64-unknown-linux-gnu -DLLVM_HOST_TRIPLE=${SLK_ARCH_TARGET} -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON"
             # This was from the arm32 days when we needed to build llvm with gcc:
             #export SLKCONFARGS="-DLLVM_HOST_TRIPLE=${SLK_ARCH_TARGET} -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON"
             # Don't change the llvm host triplet - keep it default "aarch64-unknown-linux-gnu"
             # as with Slackware x86.
             # Not hard coding the host & target triplet uses the defaults, which is what everyone else uses.
             # This way it's in line with rust's target triplet which enables it to build c++
             export SLKCONFARGS="-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON"
             #export LDFLAGS="-Wl,-z,relro -Wl,--as-needed -Wl,-z,now"
             ;;
   *)        export SLKCFLAGS="-O2" ;;
esac

# 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:
case $ARCH in
  arm)     CCOMPILER=clang
           CPPCOMPILER=clang++ ;;

  aarch64) # Compiling llvm with gcc:
           #CCOMPILER=gcc
           #CPPCOMPILER=g++
           #SLKLINKER="gold";;
           # Compiling llvm with llvm:
           #SLKLINKER="gold"
           SLKLINKER="lld"
           CCOMPILER=clang
           CPPCOMPILER=clang++ ;;
esac

echo "Extracting $CWD/llvmorg-$VERSION.tar.?z..."
tar xf $CWD/llvmorg-$VERSION.tar.?z
cd llvm-project-llvmorg-$VERSION || cd llvmorg-$VERSION || failextract

# Support GCC built for i?86-slackware-linux:
zcat $CWD/clang.toolchains.32-bit.triple.diff.gz | patch -p2 --verbose || exit 1

# We require libatomic on 32-bit platforms:
if [ -f ./tools/lldb/source/Utility/CMakeLists.txt ]; then
   if [ "$ARCH" = "i586" -o "$ARCH" = "i686" ]; then
      zcat $CWD/lldb.32-bit.link.libatomic.diff.gz | patch -p1 --verbose || exit 1
   fi
fi

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

################ ARM modifications ################################################
# These are not required for AArch64
# 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 'libcxx' package's spec file, not llvm:
# https://src.fedoraproject.org/rpms/libcxx
# Slackware unpacks the libcxx archive bundled with the llvm source (above) and move it in to place.
# https://kojipkgs.fedoraproject.org/packages/libcxx/18.1.0~rc4/2.fc41/data/logs/aarch64/build.log
#sed -i 's|#define _LIBCXXABI_ARM_EHABI||g' projects/libcxxabi/include/__cxxabi_config.h || exit 1

# Support GCC built for aarch64-slackware-linux-gnu:
#sed -i 's?aarch64-redhat-linux?aarch64-slackware-linux-gnu?g' ./tools/clang/lib/Driver/ToolChains/Gnu.cpp || exit 1
#sed -i 's?aarch64-suse-linux?aarch64-unknown-linux-gnu?g' ./tools/clang/lib/Driver/ToolChains/Gnu.cpp || exit 1
# Support GCC built for aarch64-slackware-linux-gnu:
auto_apply_patch $PORTCWD/sources/aarch64-slackware-toolchain.diff || failpatch
# Our linker lives in /lib64 (although we do carry a symlink in /lib):
auto_apply_patch $PORTCWD/sources/ld-lib64.diff || failpatch

############ 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
pushd build
cmake -GNinja \
   \
   \
   $SLKCONFARGS \
   \
   \
    -DCMAKE_C_COMPILER="clang" \
    -DCMAKE_CXX_COMPILER="clang++" \
    -DCMAKE_C_FLAGS:STRING="$SLKCFLAGS" \
    -DCMAKE_CXX_FLAGS:STRING="$SLKCFLAGS" \
    -DCMAKE_INSTALL_PREFIX=/usr \
    -DLLVM_LIBDIR_SUFFIX=${LIBDIRSUFFIX} \
    -DCMAKE_BUILD_TYPE=Release \
    -DLLVM_BUILD_LLVM_DYLIB=ON \
    -DLLVM_LINK_LLVM_DYLIB=ON \
    -DCLANG_LINK_CLANG_DYLIB=ON \
    -DLLVM_USE_LINKER=lld \
    -DLLVM_ENABLE_PROJECTS="$LLVM_ENABLE_PROJECTS" \
    -DLLVM_ENABLE_RUNTIMES="$LLVM_ENABLE_RUNTIMES" \
    -DLLVM_ENABLE_RTTI=ON \
    -DLLVM_ENABLE_FFI=ON \
    -DLLVM_ENABLE_ZLIB=ON \
    -DLLVM_ENABLE_ASSERTIONS=OFF \
    -DLLVM_ENABLE_PER_TARGET_RUNTIME_DIR=OFF \
    -DLLVM_INSTALL_UTILS=ON \
    -DLLVM_BINUTILS_INCDIR=/usr/include \
    -DCLANG_RESOURCE_DIR="../lib${LIBDIRSUFFIX}/clang/$(echo $VERSION | cut -f 1 -d .)" \
    -DLLVM_TARGETS_TO_BUILD="host;AMDGPU;BPF;WebAssembly" \
    -DLLVM_INCLUDE_BENCHMARKS=OFF \
    -DCOMPILER_RT_BUILD_LIBFUZZER=OFF \
    -DCLANG_DEFAULT_PIE_ON_LINUX=ON \
    -DLIBCXX_LIBDIR_SUFFIX=${LIBDIRSUFFIX} \
    -DLIBCXXABI_LIBDIR_SUFFIX=${LIBDIRSUFFIX} \
    -DLIBCXX_INCLUDE_BENCHMARKS=OFF \
    -DLIBCXX_ENABLE_ABI_LINKER_SCRIPT=ON \
    -DLIBCXXABI_USE_LLVM_UNWINDER=OFF \
    ../llvm  || failconfig

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

# Build:
# We'll leave 1 core free to keep the machine running smoothly
# if not building with gcc (i.e. natively with clang):
[ "$CCOMPILER" != "gcc" ] && export NUMJOBS="-j$(( $(nproc) -1 ))"
"${NINJA:=ninja}" $NUMJOBS || failmake

# Install into package framework:
DESTDIR=$PKG "$NINJA" install || failinstall
popd

# 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 -s /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 ${PY3}; do
  mkdir -vpm755 "$PKG/usr/lib$LIBDIRSUFFIX/python$pyver/site-packages"
  cp -a clang/bindings/python/clang "$PKG/usr/lib$LIBDIRSUFFIX/python$pyver/site-packages/"
done

# Remove bundled python-six:
rm -f "$PKG/usr/lib$LIBDIRSUFFIX/python2*/site-packages/six.py"

# Compile Python scripts:
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"
python3 -m compileall "$PKG/usr/share/scan-view"
python3 -O -m compileall "$PKG/usr/share/scan-view"
python3 -m compileall "$PKG/usr/share/clang"
python3 -O -m compileall "$PKG/usr/share/clang"
python3 -m compileall "$PKG/usr/share/opt-viewer"
python3 -O -m compileall "$PKG/usr/share/opt-viewer"

# Nevermind, we're not shipping this python2 crap:
rm -rf $PKG/usr/lib$LIBDIRSUFFIX/python2*

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

# Just copy anything top or next level that looks like it might be docs.
# Maybe we'll include it someday. ;-)
mkdir -vpm755 $PKG/usr/doc/$PKGNAM-$VERSION
cp -a *.{txt,md,TXT,rst} $PKG/usr/doc/$PKGNAM-$VERSION
cp -a --parents */*.{txt,md,TXT,rst} $PKG/usr/doc/$PKGNAM-$VERSION
cp -a --parents */README* $PKG/usr/doc/$PKGNAM-$VERSION
find $PKG/usr/doc/$PKGNAM-$VERSION -name CMakeLists.txt -exec rm -f "{}" \;
rmdir $PKG/usr/doc/$PKGNAM-$VERSION/* 2> /dev/null
#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
