#!/bin/bash
shopt -s extglob
set +o posix
#ulimit -s unlimited
ulimit -n 4096

# mozilla-firefox.SlackBuild
# by Stuart Winter
# Based on Unbranded 'Firefox' build script from Slackware 13.
# 03-April-2009
#
# Copyright 2009-2025  Stuart Winter, Earth, Milky Way, "".
# Copyright 2008-2025  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.

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

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

# If there is a private Google API key available at compile time, use
# it to enable support for Google Safe Browsing. For Slackware builds,
# we use a private key issued for the Slackware project. If you are
# rebuilding and need this support, or you are producing your own
# distribution, you may obtain your own Google API key at no charge by
# following these instructions:
# https://bugzilla.mozilla.org/show_bug.cgi?id=1377987#c0
if [ -f "$PORTCWD/.GoogleSafeBrowsingAPI_Key" ]; then
   GOOGLE_API_KEY="--with-google-safebrowsing-api-keyfile=$PORTCWD/.GoogleSafeBrowsingAPI_Key"
fi

# Major version number - needed for /usr/lib/firefox dir:
MAJORVER=$VERSION
# If not specified, figure out if this is a beta or a release
MOZVERS=${MOZVERS:-release}
if echo $VERSION | grep -q b ; then MOZVERS=beta ; fi
RELEASEVER=$(echo $VERSION | cut -f 1 -d r | cut -f 1 -d b | cut -f 1 -d e)

# Specify this variable for a localized build.
# For example, to build a version of Firefox with Italian support, run
# the build script like this:
#
# MOZLOCALIZE=it ./arm/build
#
MOZLOCALIZE=${MOZLOCALIZE:-}

# Without LANG=C, building the Python environment may fail with:
# "UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 36: ordinal not in range(128)"
LANG=C

# Add a shell script to start the firefox binary with MOZ_ALLOW_DOWNGRADE=1
# to avoid backing up (and disabling) the user profile if a browser downgrade
# is detected. We made it fine for years without this feature, and all the
# feedback we've seen suggests that it is causing more problems than it
# solves. For example, this feature causes a profile reset trying to switch
# between a 32-bit and 64-bit browser on installations that share a common
# /home directory. If you want to build with the stock default behavior, set
# this to something other than "YES":
MOZ_ALLOW_DOWNGRADE=${MOZ_ALLOW_DOWNGRADE:-YES}

# 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

# Much builds with distcc but it fails eventually, so we'll retry without it.
# There's some code to rm /tmp/DISTCC if the variable ! null, but any errors
# won't be trapped, so /tmp/DISTCC will no longer invoke distcc.
# I need to fix this bug using trap to a cleanup function.
function disable_distcc() {
  if [ -d /tmp/DISTCC ]; then
      DISTCCDISABLED=yes
      export PATH=$( echo $PATH | sed -e 's?/tmp/DISTCC:??g' )
      unset NUMJOBS
      # And since some paths get harded coded from configuration time, point them back
      # to local:
      pushd /tmp/DISTCC
      find . -name '*g++' | while read line ; do ln -vfs /usr/bin/g++ ${line} ; done
      find . -name '*c++' | while read line ; do ln -vfs /usr/bin/g++ ${line} ; done
      find . -name '*cc' | while read line ; do ln -vfs /usr/bin/gcc ${line} ; done
      find . -name '*gcc' | while read line ; do ln -vfs /usr/bin/gcc ${line} ; done
      popd
      echo "*** WARNING: distcc is now disabled"
  fi
}
function distcc_cleanup() {
# Remove distcc if we had to disable it:
  if [ ! -z "$DISTCCDISABLED" ]; then
     rm -rfv /tmp/DISTCC
  fi
}

export NUMJOBS="-j$(( $(nproc) -1 ))"

# PGO is disabled by default:
PGO=${PGO:-no}

# Determine the CFLAGS for the known architectures:
case $ARCH in
   aarch64)
     # Switch -O2 -> -O - old ARM hack.
     ##SLKCFLAGS="${SLKCFLAGS/-O2/-O} -g0 --param ggc-min-expand=10 -pipe -fstack-protector-strong -Wformat -Wformat-security -fno-schedule-insns2 -fno-lifetime-dse -fno-schedule-insns"
     #SLKCXXFLAGS+=" -Wno-error=nonnull"

     # Building with gcc:
     #-------------------
     #SLKCFLAGS="${SLKCFLAGS/-O2/-O} -g0 --param ggc-min-expand=10 -pipe -fstack-protector-strong -Wformat -Wformat-security -fno-schedule-insns2 -fno-lifetime-dse -fno-schedule-insns"
     # To enable useful debugging, remove -g0 and comment the 'slackstripall' at the bottom.
     # -g0 is to conserve memory during build:
     #SLKCFLAGS+=" -g0 --param ggc-min-expand=10 -pipe -fexceptions -fpermissive "
     #SLKCFLAGS+=" -pipe -fexceptions -fpermissive "
     # Linker flags for ld.bfd
     #SLKLINKER="bfd"
     #SLKLDFLAGS="-Wl,-z,relro -Wl,--as-needed  -Wl,-z,now -Wl,--undefined-version -Wl,--no-keep-memory -Wl,--reduce-memory-overheads -Wl,--stats"
     #SLKLDFLAGS="-Wl,--undefined-version -Wl,--stats"
     # Linker flags for ld.gold
     #SLKLINKER="gold"
     #SLKLDFLAGS="-Wl,--no-keep-memory -Wl,--no-keep-files-mapped -Wl,--no-map-whole-files -Wl,--no-mmap-output-file -Wl,--stats"
     #SLKLDFLAGS="-Wl,--no-keep-memory -Wl,--strip-debug "

     # Building with clang:
     #-------------------
     # Deliberaretely overwrite the CFLAGS from slackkit to remove -fPIC as it causes build failures.
     SLKCFLAGS="-g0"
     SLKLINKER="lld"
     #SLKLDFLAGS="-Wl,--as-needed -Wl,--undefined-version"

     # Trying without on ARM as this may be cause of breakage:
     # As of FF version=90.0.2 this has been removed from Slackware64.
     #--enable-rust-simd \
     # Retrying with rust-simd, Jan 2023:
     #    --disable-jemalloc \
     #    --disable-webrtc \
     # --disable-phc added May 2024, Firefox 106 to fix segfault
     #   --disable-av1 \
     #    --disable-elf-hack" ;;
     #export SLKCONFARGS="$SLKCONFARGS \
     #    --enable-linker=$SLKLINKER " ;;

     SLKCONFARGS="--with-system-libdrm"
     ;;
   *)    export SLKCFLAGS="-O" ;;
esac

#######################################################################

# Extract source:
echo "Extracting source"
tar xf $CWD/firefox-$VERSION*source.tar.!(*sign|*asc|*sig)
#tar xf $PORTCWD/sources/firefox-$VERSION*source*tar*
cd mozilla*/ || cd firefox*/ || failextract
slackhousekeeping

#######################################################################################
########### Patch & fix  ##############################################################
#######################################################################################

# Delete object directory if it was mistakenly included in the tarball:
rm -rf obj-x86_64-pc-linux-gnu

# Prevent failures building gkrust by suppressing useless warnings:
sed -i.allow-warnings -e '/#!\[deny(warnings)\]/a #![allow(unused_imports)]' \
  servo/components/style/lib.rs

# Retain GTK+ v2 scrolling behavior:
zcat $CWD/ff.ui.scrollToClick.diff.gz | patch -p1 --verbose || exit 1

# Don't enable LTO for Rust unless the whole build uses it:
zcat $CWD/0027-LTO-Only-enable-LTO-for-Rust-when-complete-build-use.patch.gz | patch -p1 --verbose || exit 1

# Don't define a function that's included starting in glibc-2.36:
zcat $CWD/arc4random_buf.glibc-2.36.diff.gz | patch -p1 --verbose || exit 1

# Fetch localization, if requested:
if [ ! -z $MOZLOCALIZE ]; then
  LOC_TAG="FIREFOX_$( echo $VERSION | tr \. _ )_RELEASE"
  rm -f $LOC_TAG.tar.!(*sign|*asc|*sig)
  if echo $MOZVERS | grep -q esr ; then LOC_VERS=release ; else LOC_VERS=$MOZVERS ; fi
   wget https://hg.mozilla.org/releases/l10n/mozilla-$MOZVERS/$MOZLOCALIZE/archive/$LOC_TAG.tar.!(*sign|*asc|*sig)
  tar xf $LOC_TAG.tar.!(*sign|*asc|*sig)
  mv $MOZLOCALIZE-$LOC_TAG $MOZLOCALIZE
fi

# Apply some patches for ARM:
#for pf in $( grep -Ev '^$' $PORTCWD/sources/patches/patchlist ) ; do
#   auto_apply_patch $PORTCWD/sources/patches/${pf}.xz || failpatch
#done

# Update the various config.guess to upstream release for aarch64 support
# Do not update config.guess in the ./third_party/rust because that would break checksums
find ./ -path ./third_party/rust -prune -o -name config.guess -exec cp -fav /usr/share/libtool/build-aux/config.guess {} ';'

##########
########## Patches from Slackware x86
##########


#######################################################################################
########### Configure    ##############################################################
#######################################################################################

# Put Rust objects on a diet to keep the linker from running into memory
# issues (especially on 32-bit):
# These cause a build failure.  rust on Slackware ARM sets these as default also, so they
# may not be needed.
#export RUSTFLAGS="-Cdebuginfo=0 -Copt-level=0"
#export MOZ_RUST_DEFAULT_FLAGS="$RUSTFLAGS"
export RUSTFLAGS="-Cdebuginfo=0"

# Disable debuginfo being compiled in. Helps reduce RAM use at build time.
#export MOZ_DEBUG_FLAGS="-g0"

# Configure:
# Need to re-generate because of the 'no neon' patch:
# We also need to use autoconf-2.13 (in /extra).
#autoreconf2.13  -vif

# Turn errors back into warnings:
#sed -i 's?-Werror?-Wall?g' configure

# Our building options, in a configure-like display ;)
#    --host=${SLK_ARCH_BUILD} \
#    --target=${SLK_ARCH_BUILD} \
OPTIONS="\
   \
   $SLKCONFARGS \
   \
   --enable-official-branding \
   --prefix=/usr \
   --libdir=/usr/lib${LIBDIRSUFFIX} \
   --with-system-zlib \
   --with-system-nss \
   --with-system-nspr \
   --with-unsigned-addon-scopes=app,system \
   --without-wasm-sandboxed-libraries \
   --allow-addon-sideload \
   --enable-linker=$SLKLINKER \
   --enable-alsa \
   --enable-application=browser \
   --enable-default-toolkit=cairo-gtk3-wayland \
   --enable-optimize \
   $GOOGLE_API_KEY \
   --disable-strip \
   --disable-install-strip \
   --disable-tests \
   --enable-cpp-rtti \
   --enable-accessibility \
   --disable-crashreporter \
   --disable-debug-symbols \
   --disable-debug \
   --disable-elf-hack \
   --disable-updater"
   # Complains about missing APNG support in Slackware's libpng:
   #--with-system-png \
   # won't build:
   #--enable-system-cairo \
   #--enable-strip \
if [ ! -z $MOZLOCALIZE ]; then
  OPTIONS=$OPTIONS" \
   --enable-ui-locale=$MOZLOCALIZE
   --with-l10n-base=.."
  # There are no dictionaries in localized builds
  sed -i \
    -e "/@BINPATH@\/dictionaries\/\*/d" \
    -e "/@RESPATH@\/dictionaries\/\*/d" \
    browser/installer/package-manifest.in || exit 1
fi

# old way of doing it:
export MACH_USE_SYSTEM_PYTHON="1"
# new way:
#1 - breaks.export MACH_BUILD_PYTHON_NATIVE_PACKAGE_SOURCE=system
#2 - to try: export MACH_BUILD_PYTHON_NATIVE_PACKAGE_SOURCE=none
export MOZILLA_OFFICIAL="1"
export BUILD_OFFICIAL="1"
export MOZ_PHOENIX="1"
export MOZ_PACKAGE_JSSHELL="1"
export CFLAGS="$SLKCFLAGS"
export CXXFLAGS="$SLKCFLAGS -fno-delete-null-pointer-checks -Wno-error=c++11-narrowing-const-reference"
export MOZ_MAKE_FLAGS="$NUMJOBS"
export MOZBUILD_STATE_PATH="$TMPBUILD/firefox-$RELEASEVER/.mozbuild"
export MOZ_APP_REMOTINGNAME="firefox"
export LDFLAGS="$SLKLDFLAGS"
export MOZ_LINK_FLAGS="$SLKLDFLAGS"

# Clear some variables that could break the build
unset DBUS_SESSION_BUS_ADDRESS ORBIT_SOCKETDIR SESSION_MANAGER \
  XDG_SESSION_COOKIE XAUTHORITY MAKEFLAGS

# Assemble our .mozconfig, we use this method for building, seems
# needed for PGO.
echo ". \$topsrcdir/browser/config/mozconfig" > .mozconfig

# Mozilla devs enforce using an objdir for building
# https://developer.mozilla.org/en/Configuring_Build_Options#Building_with_an_objdir
mkdir obj
echo "mk_add_options MOZ_OBJDIR=$(pwd)/obj" >> .mozconfig

if [ "$MOZLOCALIZE" ]; then
  echo "mk_add_options MOZ_CO_LOCALES=\"$MOZLOCALIZE\"" >> .mozconfig
fi

#echo 'ac_add_options --enable-optimize="-g0 -O2"' >> .mozconfig
#echo 'ac_add_options --enable-optimize="-O2"' >> .mozconfig

# Write in it the options above
for option in $OPTIONS; do echo "ac_add_options $option" >> .mozconfig; done

cat << 'EOF' >> .mozconfig

# We'll use GCC to compile since we have the x-toolchain for Slackware ARM
# but not for LLVM (yet):
#export CC="gcc"
#export CXX="g++"
#export AR="gcc-ar"
#export NM="gcc-nm"
#export RANLIB="gcc-ranlib"

# Use clang for Firefox 126 onwards since that's what everyone else is using
# and gcc no longer builds Firefox, or it segfaults.
export CC=clang
export CXX=clang++
#export AR=llvm-ar
#export NM=llvm-nm
#export RANLIB=llvm-ranlib
EOF

#######################################################################################
########### Build        ##############################################################
#######################################################################################

# https://developer.mozilla.org/en-US/docs/Building_with_Profile-Guided_Optimization
# Thanks to ArchLinux and Gentoo for the additional hints.
if [ "$PGO" = "yes" ]; then
  # Do a PGO build, double time and disk space but worth it.
  export MOZ_PGO=1
  echo "mk_add_options PROFILE_GEN_SCRIPT='EXTRA_TEST_ARGS=10 \$(MAKE) -C \$(MOZ_OBJDIR) pgo-profile-run'" >> .mozconfig
  export DISPLAY=:99
  # Launch Xvfb to let the profile scripts run in a X session.
  # Ugly note: if the build breaks you may want to do a "killall Xvfb".
  Xvfb -nolisten tcp -extension GLX -screen 0 1280x1024x24 $DISPLAY &
  dbus-launch --exit-with-session ./mach build -v || exit 1
  kill $! || true
else
  # Do a normal build
  echo "**** Running ./mach build *****"
  #./mach build -v || { disable_distcc ; ./mach build -v ;} || { distcc_cleanup ; failmake ;}
  ./mach build -v || failmake
fi

# Install into package framework:
echo "**** Running ./mach buildsymbols *****"
#./mach buildsymbols || { disable_distcc ; ./mach buildsymbols ;} || { distcc_cleanup ; failmake ;}
./mach buildsymbols || failmake

echo "**** Running DESTDIR=$PKG ./mach install ***"
#echo "*** Disabling distcc for package installation ***"
#disable_distcc
#DESTDIR=$PKG ./mach install || { distcc_cleanup ; failinstall ;}
DESTDIR=$PKG ./mach install || failinstall

#######################################################################################
########### Installation ##############################################################
#######################################################################################

# We don't need these (just symlinks anyway):
rm -rf $PKG/usr/lib${LIBDIRSUFFIX}/firefox-devel-$RELEASEVER
# Nor these:
rm -rf $PKG/usr/include

mkdir -p $PKG/usr/lib${LIBDIRSUFFIX}/mozilla/plugins
mkdir -p $PKG/usr/share/applications
cat $CWD/firefox.desktop > $PKG/usr/share/applications/firefox.desktop

# Need some default icons in the right place:
for i in 16 22 24 32 48 256; do
  install -m 0644 -D browser/branding/official/default${i}.png \
    $PKG/usr/share/icons/hicolor/${i}x${i}/apps/firefox.png
done
mkdir -p $PKG/usr/share/pixmaps
( cd $PKG/usr/share/pixmaps ; ln -sf /usr/share/icons/hicolor/256x256/apps/firefox.png . )
mkdir -p $PKG/usr/lib$LIBDIRSUFFIX/firefox-$RELEASEVER/chrome/icons/default
install -m 644 browser/branding/official/default16.png \
  $PKG/usr/lib$LIBDIRSUFFIX/firefox-$RELEASEVER/icons/
install -m 644 browser/branding/official/default16.png \
  $PKG/usr/lib$LIBDIRSUFFIX/firefox-$RELEASEVER/chrome/icons/default/

# Copy over the LICENSE
install -p -c -m 644 LICENSE $PKG/usr/lib${LIBDIRSUFFIX}/firefox-$RELEASEVER/

# If MOZ_ALLOW_DOWNGRADE=YES, replace the /usr/bin/firefox symlink with a
# shell script that sets the MOZ_ALLOW_DOWNGRADE=1 environment variable so
# that a detected browser downgrade does not reset the user profile:
if [ "$MOZ_ALLOW_DOWNGRADE" = "YES" ]; then
  rm -vf $PKG/usr/bin/firefox
  cat << EOF > $PKG/usr/bin/firefox
#!/bin/sh
#
# Shell script to start Mozilla Firefox.
#
# Don't reset the user profile on a detected browser downgrade:
export MOZ_ALLOW_DOWNGRADE=1

# Start Firefox:
exec /usr/lib${LIBDIRSUFFIX}/firefox/firefox "\$@"
EOF
  chown root:root $PKG/usr/bin/firefox
  chmod 755 $PKG/usr/bin/firefox
fi

# Fix duplicate binary, https://bugzilla.mozilla.org/show_bug.cgi?id=658850
( cd $PKG/usr/lib$LIBDIRSUFFIX/firefox
  if cmp firefox firefox-bin ; then
    ln -vsf firefox-bin firefox
  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      # chown -R root:root, chmod -R og-w, slackchown, slack644docs
slackdesc       # install slack-desc and doinst.sh

if [ ! -z $MOZLOCALIZE ]; then
  BUILD="${BUILD}_${MOZLOCALIZE}"
fi

slackmp         # run makepkg -l y -c n

# Perform any final checks on the package:
cd $PKG

slackhlinks     # search for any hard links

# Cleanup any distcc stuff:
distcc_cleanup
