#!/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  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

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

case $ARCH in
   aarch64) #export SLKCFLAGS="-O2"
            export BARCH="aarch64"
            export BABI="gnu" ;;

            # 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
   arm)     #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) || exit 1
cd $SRCNAM-$VERSION-src || exit 1
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

####################################################################################
# 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 > config.toml
[llvm]
ccache = "/usr/bin/ccache"
link-shared = true

[build]
build = "${SLK_ARCH_TARGET}"
host = ["${SLK_ARCH_TARGET}"]
target = ["${SLK_ARCH_TARGET}"]
tools = ["analysis", "cargo", "clippy", "rls", "rustfmt", "src"]
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

[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
ignore-git = true

# 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 >> config.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\"|" config.toml
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:
#fgrep -lr -- '-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"
python3 x.py build -j2 --stage 2 || 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 ) || failmake

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

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

# 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
