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

# rust.SlackBuild
# Heavily based on the original Slackware build scripts,
# Modified by Stuart Winter for Slackware ARM.
#
# Copyright 2017  Andrew Clemons, Wellington, New Zealand
# Copyright 2017-2026  Patrick J. Volkerding, Sebeka, Minnesota, 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.

#################################################################################################
# Rust stuff:
# rustc  --print target-list
# rustc  --print cfg --target  arm-unknown-linux-gnueabihf
# NEON stuff:
# 1) https://github.com/rust-lang/rust/pull/38413
# 2) https://github.com/rust-lang/rust/commit/9e01f76349ec358009099dd5dc87b921960defc2
# 3) https://github.com/rust-lang/rust/issues/36913 << NEON issue on Fedora (but from 2016)
# Settings:
# rustc-1.23.0-src/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs
#
# Description about rust's targets:
# https://github.com/rust-lang/rust/issues/35590
#
#################################################################################################

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

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

# In /testing, the path is different:
pwd | grep -q testing && export CWD=$SLACKUPSTREAMROOTDIR/testing/source/rust

# Temporary build locations:
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

# Version information:
SRCNAM="${PKGNAM}c"

# Set this to YES to build with the system LLVM, or NO to use the bundled LLVM.
# YES is probably better (when it works...)
SYSTEM_LLVM=${SYSTEM_LLVM:-NO}
#SYSTEM_LLVM=${SYSTEM_LLVM:-YES}

# Include the massive documentation in the package?
RUSTDOCS=${RUSTDOCS:-NO}

# "docs" option for bootstrap.toml:
if [ "$RUSTDOCS" = "NO" ]; then
   BUILDDOCS_OPTION="docs = false"
else
   BUILDDOCS_OPTION="docs = true"
fi

case $ARCH in
   aarch64) #export SLKCFLAGS="-O2"
            export BARCH="aarch64"
            export BABI="gnu" ;;
   arm)     # Tune down to armv7.  armv7-a (according to LLVM) has NEON instructions,
            # but Nvidia Tegra 20 and some Marvell SoCs don't.
            # See https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=834003
            #export SLKCFLAGS="${SLKCFLAGS/armv7-a/armv6zk}"
            #export RUSTFLAGS="$RUSTFLAGS -C link-args=-lffi"
            # Disable NEON instructions - - no need since they're off by default in src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs
            # Doesn't help..
            #export RUSTFLAGS="$RUSTFLAGS -C target-feature=-neon"
            export SLKLDFLAGS="-Wl,-z,relro -Wl,--as-needed  -Wl,-z,now" # RAM issues on ARM
            export RUSTFLAGS="-Clink-arg=-Wl,-z,relro,-z,now"
            export BARCH="armv7" # or set to 'arm' if you want to switch to the other target quadlet.
            export BABI="gnueabihf";;
   *)       export SLKCFLAGS="-O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions" ;;
esac

# Assemble the build target:
export SLK_ARCH_TARGET="${BARCH}-unknown-linux-${BABI}"
echo "Build target: $SLK_ARCH_TARGET"
echo "CFLAGS: $SLKCFLAGS / Rust CFLAGS (usually empty): $RUSTFLAGS"

# Clean up from any previous builds:
#rm -rfv $HOME/{.cargo,.rustup}

# Extract source:
echo "Unpacking source - will take a while.."
tar xf $CWD/$SRCNAM-$VERSION-src.tar.!(*sign|*asc|*sig)
cd $SRCNAM-$VERSION-src || failextract
slackhousekeeping

# Try and remove NEON (this doesn't actually have +neon, but I wanted to check
# if removing it entirely helped). It doesn't.
#sed -i 's?,-neon??g' src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs || exit 1

# If you already have rust and cargo installed, you can bootstrap from the
# previous version.
# If you want to build from boot strap binaries: removepkg rust
if [ -x /usr/bin/cargo -a -x /usr/bin/rustc ] ; then
   LOCAL_BOOTSTRAP=yes
fi

if [ -z "$LOCAL_BOOTSTRAP" ] ; then
  # rust requires bootstrapping with the previous rust version.
  # versions are defined in src/stage0.txt
  #
  # Note that in Slackware ARM, we don't update these unless we need to re-bootstrap,
  # at which point it'll need some heavy lifting and sleeve rolling, since rust on ARM
  # proved to be a challenge!
  RSTAGE0_VERSION=${RSTAGE0_VERSION:-1.53.0}
  RSTAGE0_DIR=${RSTAGE0_DIR:-2021-06-17}
  CSTAGE0_VERSION=${CSTAGE0_VERSION:-1.53.0}
  CSTAGE0_DIR=${CSTAGE0_DIR:-$RSTAGE0_DIR}

  mkdir -p build/cache/$RSTAGE0_DIR
  cp $PORTCWD/bootstrap/$PKGNAM-std-*-$SLK_ARCH_TARGET.tar.!(*sign|*asc|*sig) \
     $PORTCWD/bootstrap/$SRCNAM-*-$SLK_ARCH_TARGET.tar.!(*sign|*asc|*sig) \
     build/cache/$RSTAGE0_DIR

  mkdir -p build/cache/$CSTAGE0_DIR
  cp $PORTCWD/bootstrap/cargo-*-$SLK_ARCH_TARGET.tar.!(*sign|*asc|*sig) build/cache/$CSTAGE0_DIR
fi

###################################################################################
# Apply patches:
###################################################################################
# Slackware upstream patches:
#----------------------------------------------------------------------------------

# Link with -lffi in case of using system LLVM:
if [ "${SYSTEM_LLVM}" = "YES" ]; then
  zcat $CWD/link_libffi.diff.gz | patch -p1 --verbose || exit 1
fi

cat $CWD/0004-compiler-Use-wasm-ld-for-wasm-targets.patch | patch -p1 --verbose || exit 1

# Support libdir other than "lib":
# This will be removed in 1.89 and we'll need the patch below and possible some other bits.
#cat $PORTCWD/sources/141729.patch | patch -p1 --verbose || exit 1

# Support libdir other than "lib":
cat $CWD/141729.patch | patch -p1 --verbose || exit 1

# This patch will also be useful once we copy /usr/lib64/rustlib > /usr/lib/
#https://src.fedoraproject.org/rpms/rust/raw/rawhide/f/0001-only-copy-rustlib-into-stage0-sysroot.patch
#patch --verbose -p1 < $PORTCWD/sources/0001-only-copy-rustlib-into-stage0-sysroot.patch || failpatch

# Fix build with glibc-2.42:
( cd src/llvm-project
cat $CWD/59978b21ad9c65276ee8e14f26759691b8a65763.patch | patch -p1 --verbose || exit 1
cat $CWD/0a17483c481d82eace3b36aee9cacb619eb027af.patch | patch -p1 --verbose || exit 1
cat $CWD/c99b1bcd505064f2e086e6b1034ce0b0c91ea5b9.patch | patch -p1 --verbose || exit 1
) || failpatch

####################################################################################
# Patches applied to Slackware ARM:
# These are taken from Fedora
#----------------------------------------------------------------------------------
#for pf in \
#  rust-pr57840-llvm7-debuginfo-variants.patch.xz \
#  ; do auto_apply_patch $PORTCWD/sources/patches/$pf || exit 1
#done

# Build configuration. We'll go ahead and build with rpath because it may be
# needed during the build, and then we'll strip the rpaths out of the
# binaries later.
cat << EOF > bootstrap.toml

# Avoid triggering "git --local" on non-git vendored sources:
profile = "dist"

[llvm]
#ccache = "/usr/bin/ccache"
link-shared = true
download-ci-llvm = false

[build]
build = "${SLK_ARCH_TARGET}"
host = ["${SLK_ARCH_TARGET}"]
target = ["${SLK_ARCH_TARGET}"]
tools = ["analysis", "cargo", "clippy", "rustfmt", "src", "rust-analyzer", "rust-demangler"]
submodules = false
vendor = true

# Enable a build of the extended rust tool set which is not only the compiler
# but also tools such as Cargo. This will also produce "combined installers"
# which are used to install Rust and Cargo together. This is disabled by
# default.
extended = true
profiler = true
sanitizers = true

# Do not query new versions of dependencies online.
locked-deps = true
$BUILDDOCS_OPTION

[install]
prefix = "/usr"
docdir = "doc/rust-$VERSION"
libdir = "lib$LIBDIRSUFFIX"
mandir = "man"

[rust]
# This may need to be set to =1 at some point - see comments in
# https://archlinuxarm.org/packages/armv7h/rust/files/PKGBUILD
codegen-units = 0
channel = "stable"
rpath = false
codegen-tests = false

# Added by Slackware ARM:
# Debuginfo level for most of Rust code, corresponds to the -C debuginfo=N option of rustc.
# 0 - no debug info
# 1 - line tables only
# 2 - full debug info with variable and type information
# Can be overriden for specific subsets of Rust code (rustc, std or tools).
# Debuginfo for tests run with compiletest is not controlled by this option
# and needs to be enabled separately with debuginfo-level-tests.
debuginfo-level = 0

# Debuginfo level for the compiler.
#debuginfo-level-rustc = debuginfo-level
debuginfo-level-rustc = 0

# Debuginfo level for the standard library.
# Fedora sets this to 2.  Slackware doesn't ship debug packages.
debuginfo-level-std = 0

# Emits extraneous output from tests to ensure that failures of the test
# harness are debuggable just from logfiles.
verbose-tests = true

# Whether to deny warnings in crates
# Otherwise it fails to bootstrap with llvm-10 and rust-1.42.
# Also see some code above using sed to remove -Dwarnings.
deny-warnings = false

EOF

# Add this stuff to build with the system LLVM:
# If you're changing architecture, you can add in the new and old ones here.
# I don't know if it actually makes a difference though but it does not hurt!
if [ "${SYSTEM_LLVM}" = "YES" ]; then
  cat << EOF >> bootstrap.toml
[target.${SLK_ARCH_TARGET}]
llvm-config = "/usr/bin/llvm-config"
cc = 'gcc'
cxx = 'g++'
linker = 'gcc'

[target.armv7l-unknown-linux-gnueabihf]
llvm-config = "/usr/bin/llvm-config"
cc = 'gcc'
cxx = 'g++'
linker = 'gcc'

[target.arm-unknown-linux-gnueabihf]
llvm-config = "/usr/bin/llvm-config"
cc = 'gcc'
cxx = 'g++'
linker = 'gcc'

EOF

fi

if [ ! -z "$LOCAL_BOOTSTRAP" ] ; then
   sed -i "s|^\(extended = true\)$|\1\nrustc = \"/usr/bin/rustc\"\ncargo = \"/usr/bin/cargo\"|" bootstrap.toml
fi

# Fix path to the rust libraries in rust-analyzer:
if [ -r src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs ]; then
  if [ ! "$LIBDIRSUFFIX" = "" ]; then
    sed -i "s,\"lib/rustlib,\"lib${LIBDIRSUFFIX}/rustlib,g" src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
  fi
fi

# Don't warn, otherwise it fails to build during bootstrap:
# If the configuration option above doesn't work, look for where this is set and remove it; but
# you need to edit only specific files - not the sweeping hack below:
#grep -Flr -- '-Dwarnings' . | xargs sed -i 's?-Dwarnings??g'

# Configure:
#export CC=cc \
#export CXX=c++ \
export PKG_CONFIG_ALLOW_CROSS=1

# Build:
echo "*** Running x.py build ***"
# https://forge.rust-lang.org/x-py.html
#
#CC=clang \
#CXX=clang++ \
export RUST_BACKTRACE=full
#export RUST_BACKTRACE=1
export CFLAGS="$SLKCFLAGS"
export CXXFLAGS="$SLKCFLAGS"
export LDFLAGS="$SLKLDFLAGS"

# in rust 1.84.0
# We're unsetting them since this is what the x86 build script now does, due to a
# build error there. We'll do the same, at least for now..
unset CFLAGS CXXFLAGS LDFLAGS

#python3 x.py build $NUMJOBS --stage 2 || failmake
#python3 x.py build $NUMJOBS || failmake
# Rust compiles natively also, so let's not overload the build machine:
python3 x.py build -j$( nproc ) || failmake
#echo "*** Running x.py doc ***"
#python3 x.py doc --stage 2 || failmake
#python3 x.py dist -j$( nproc ) || python3 x.py dist -j2 || python3 x.py dist -j1 || exit 1

echo "*** Running x.py install ***"
#mkdir -vpm755 $PKG
# This currently fails, but it produces what looks like to be a useful package anyway
# Needs investigating, but let's go with what we have so far:
#RUST_BACKTRACE=full DESTDIR=$PKG ./x.py install #|| exit
#DESTDIR=$PKG ./x.py install || exit
#RUST_BACKTRACE=full DESTDIR=$PKG python3 x.py install -j$( nproc ) || failinstall
RUST_BACKTRACE=full DESTDIR=$PKG python3 x.py install || failinstall

# Fix path to lldb_commands:
if [ -x $PKG/usr/bin/rust-lldb ]; then
  if [ ! "$LIBDIRSUFFIX" = "" ]; then
    sed -i "s,/lib/rustlib/,/lib$LIBDIRSUFFIX/rustlib/,g" $PKG/usr/bin/rust-lldb
  fi
fi

# Make sure the paths are correct:
sed -i 's?'"$TMPBUILD"'?/?g' $PKG/usr/lib$LIBDIRSUFFIX/rustlib/install.log $PKG/usr/lib$LIBDIRSUFFIX/rustlib/manifest-*
# And a little compression doesn't hurt either:
gzip -9 $PKG/usr/lib$LIBDIRSUFFIX/rustlib/manifest-*

# Move bash completions to the system location:
if [ -d $PKG/etc/bash_completion.d ]; then
   mkdir -p $PKG/usr/share/bash-completion
   mv $PKG/etc/bash_completion.d $PKG/usr/share/bash-completion/completions
   rmdir $PKG/etc 2> /dev/null
fi

# Correct permissions on shared libraries:
find $PKG/usr/lib$LIBDIRSUFFIX -name "*.so" -exec chmod 755 "{}" \;

# Evidently there are a lot of duplicated libraries in this tree, so let's
# try to save some space:
( cd $PKG/usr/lib${LIBDIRSUFFIX}/rustlib/*-linux-gnu*/lib && for file in *.so ; do if cmp -s $file ../../../$file ; then ln -sf ../../../$file .; fi; done )

# Get rid of possible .old files in these locations:
rm -f $PKG/usr/lib${LIBDIRSUFFIX}/*.old
rm -f $PKG/usr/bin/*.old

# Remove any compiled-in RPATHs:
#find $PKG -print0 | xargs -0 file | grep -e "executable" -e "shared object" | grep ELF \
#  | cut -f 1 -d : | while read elfobject ; do
#  patchelf --remove-rpath $elfobject || exit 1
#done

# Add documentation:
mkdir -vpm755 $PKG/usr/doc
mv -fv $PKG/usr/share/doc/rust $PKG/usr/doc/$PKGNAM-$VERSION
rmdir $PKG/usr/share/doc
cp -fav \
   *.md COPYRIGHT* LICENSE* \
   $PKG/usr/doc/$PKGNAM-$VERSION/
# Include licenses from third party vendors:
mkdir -vpm755 $PKG/usr/doc/$PKGNAM-$VERSION/vendor
( cd vendor
  tar cf - $(find . -maxdepth 2 | grep -e README -e LICENSE -e COPYING -e CHANGELOG -e PERFORMANCE -e UPGRADE ) | ( cd $PKG/usr/doc/$PKGNAM-$VERSION/vendor ; tar xf - )
)

# If $RUSTDOCS=NO then toss the html docs:
if [ "$RUSTDOCS" = "NO" ]; then
   rm -rf $PKG/usr/doc/$PKGNAM-$VERSION/html
fi

# 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
# There are tonnes in here.. forget it. I don't want to see the output!
#slackhlinks     # search for any hard links
