#!/bin/bash # Version: 0.6.1 # Copyright (c) 2005-2022: # Darren 'Tadgy' Austin # Licensed under the terms of the GNU General Public License version 3. ######################################################################## # None of this section requires editing. # # Scroll down to the "Begin section that will require editing" marker. # ######################################################################## # Silence shellcheck. # shellcheck disable=SC2015,SC2174 # Functions. check_installed() { # $1 = The package name to check is installed. [[ -z "$1" ]] && return 1 printf "%s\\n" /var/lib/pkgtools/packages/* | grep -P "^/var/lib/pkgtools/packages/\Q$1\E-([^-]*)-([^-]*)-([^-]*)$" >/dev/null 2>&1 return $? } die() { # $1 = The message to write to stderr on exit. printf "\\033[1;31;40m%s: %s\\033[0;39m\\n" "${0##*/}" "${1:-Abort}" >&2 exit 1 } # Make sure to be in the build directory. # shellcheck disable=SC2164 cd "$(cd "${BASH_SOURCE[0]%/*}"; pwd -P)" # Read global buildconf settings. # shellcheck disable=SC1091 [[ -e ../buildconf ]] && { . ../buildconf 2>/dev/null || die "Error sourcing global buildconf" } # Package specific buildconf settings. # shellcheck disable=SC2015,SC1090 [[ -e "./$(basename "${BASH_SOURCE[0]}" .SlackBuild).buildconf" ]] && . "./$(basename "${BASH_SOURCE[0]}" .SlackBuild).buildconf" 2>/dev/null || \ die "Error sourcing package buildconf" # Package storage path. # Be safe and leave it in /tmp by default (can be overridden). # shellcheck disable=SC2016 PKG_STORE='${PKG_STORE:-/tmp/pkg-store/$DIST_OS_ID$BUILD_LIBDIRSUFFIX-$DIST_OS_VERSION_ID}' # Parse command line options. while (( $# > 0 )); do if [[ "$1" =~ ^-(-)?f(orce)?$ ]]; then BUILD_FORCE=1 elif [[ "$1" =~ ^-(-)?n(o-cleanup)?$ ]]; then BUILD_CLEANUP=0 elif [[ "$1" =~ ^-(-)?v(ersion)?$ ]]; then printf "%s=\"%s\"\\n" "NAME" "$PKG_NAME" printf "%s=\"%s\"\\n" "VERSION" "$PKG_VERSION" printf "%s=\"%s\"\\n" "BUILD" "$PKG_BUILD$PKG_TAG" exit 0 else printf "%s: %s: %s\\n" "${0##*/}" "Invalid option" "$1" >&2 printf "%s: %s %s\\n" "Usage" "${0##*/}" "[[-f|--force]|[-n|--no-cleanup]|[-v|--version]]" >&2 exit 1 fi shift done # Pre-build checks. (( ${BUILD_FORCE:-0} != 1 )) && { while read -r PKG; do check_installed "$PKG" && die "Conflicting package installed: $PKG" done < <(printf "%s\\n" "${BUILD_CONFLICTS[@]}") while read -r PKG; do check_installed "$PKG" || die "Required package not installed: $PKG" done < <(printf "%s\\n" "${BUILD_REQUIRES[@]}") } # Gather some system information. # shellcheck disable=SC2046 declare DIST_OS_$(grep "^ID=" /etc/os-release) # shellcheck disable=SC2046 declare DIST_OS_$(grep "^VERSION_ID=" /etc/os-release) # Try to detect a 'current' build environment. # shellcheck disable=SC2046 declare DIST_OS_$(grep "^VERSION_CODENAME=" /etc/os-release) [[ "$DIST_OS_VERSION_CODENAME" == "current" ]] && DIST_OS_VERSION_ID="current" unset DIST_OS_VERSION_CODENAME # Build environment. BUILD_WORKDIR="${BUILD_WORKDIR:-/tmp/pkg-build}" BUILD_ROOT="$BUILD_WORKDIR/pkg-$PKG_NAME" BUILD_PREFIX="${BUILD_PREFIX:-/opt}" BUILD_ALTCC="${BUILD_ALTCC:-}" BUILD_ALTCXX="${BUILD_ALTCXX:-}" BUILD_NUMJOBS="${BUILD_NUMJOBS:-7}" case "${BUILD_ARCH:=$(uname -m)}" in i[45]86) BUILD_CFLAGS="${BUILD_CFLAGS:--march="$BUILD_ARCH" -mtune=i586 -O2}" BUILD_CXXFLAGS="${BUILD_CXXFLAGS:-$BUILD_CFLAGS}" BUILD_LDFLAGS="${BUILD_LDFLAGS:-}" BUILD_MAKEFLAGS=( "${BUILD_MAKEFLAGS[@]}" ) PKG_ARCH="${PKG_ARCH:-$BUILD_ARCH}" ;; i686) BUILD_CFLAGS="${BUILD_CFLAGS:--march="$BUILD_ARCH" -mtune=pentium4 -O2}" BUILD_CXXFLAGS="${BUILD_CXXFLAGS:-$BUILD_CFLAGS}" BUILD_LDFLAGS="${BUILD_LDFLAGS:-}" BUILD_MAKEFLAGS=( "${BUILD_MAKEFLAGS[@]}" ) PKG_ARCH="${PKG_ARCH:-$BUILD_ARCH}" ;; x86_64|x86-64) BUILD_CFLAGS="${BUILD_CFLAGS:--march=x86-64-v2 -mtune=ivybridge -O2 -fPIC}" BUILD_CXXFLAGS="${BUILD_CXXFLAGS:-$BUILD_CFLAGS}" BUILD_LDFLAGS="${BUILD_LDFLAGS:-}" BUILD_MAKEFLAGS=( "${BUILD_MAKEFLAGS[@]}" ) BUILD_LIBDIRSUFFIX="64" PKG_ARCH="${PKG_ARCH:-x86_64}" ;; aarch64) BUILD_CFLAGS="${BUILD_CFLAGS:-O2 -fPIC}" BUILD_CXXFLAGS="${BUILD_CXXFLAGS:-$BUILD_CFLAGS}" BUILD_LDFLAGS="${BUILD_LDFLAGS:-}" BUILD_MAKEFLAGS=( "${BUILD_MAKEFLAGS[@]}" ) BUILD_LIBDIRSUFFIX="64" PKG_ARCH="${PKG_ARCH:-aarch64}" DIST_OS_VERSION_ID="slackwareaarch" ;; arm*) BUILD_CFLAGS="${BUILD_CFLAGS:-O2}" BUILD_CXXFLAGS="${BUILD_CXXFLAGS:-$BUILD_CFLAGS}" BUILD_LDFLAGS="${BUILD_LDFLAGS:-}" BUILD_MAKEFLAGS=( "${BUILD_MAKEFLAGS[@]}" ) PKG_ARCH="${PKG_ARCH:-arm}" DIST_OS_VERSION_ID="slackwarearm" ;; *) die "Unsupported build architecture: $BUILD_ARCH" ;; esac # Now all possible changes to variables in PKG_STORE are complete, expand out the embedded variables. eval "$(declare -p PKG_STORE | sed -re 's/\\\$/$/g')" # Sanity. SRC_DIR="$(pwd)" umask 0022 [[ ! -e "$BUILD_WORKDIR" ]] || mkdir -p -m 750 "$BUILD_WORKDIR" || die "Failed to create working directory" rm -rf "$BUILD_ROOT" && mkdir -m 755 "$BUILD_ROOT" || die "Failed to clear build root" [[ -n "${SRC_DIRNAMES[*]}" ]] && { rm -rf "${SRC_DIRNAMES[@]/#/$BUILD_WORKDIR/}" || die "Failed to clear source directories"; } # Get sources if they aren't downloaded already. [[ -n "${SRC_DOWNLOADS[*]}" ]] && { WGET="$(command -v wget)" I=0 while read -r SRC; do [[ ! -e "${SRC_FILENAMES[$I]}" ]] && { [[ -z "$WGET" ]] && die "wget is required to download sources" "$WGET" -t 3 -c -T 30 -w 5 --retry-connrefused --retry-on-host-error --no-check-certificate --passive-ftp -O "${SRC_FILENAMES[$I]}" "$SRC" || \ { rm "${SRC_FILENAMES[$I]}"; die "Failed to download source file: $SRC"; } } [[ "$(md5sum "${SRC_FILENAMES[$I]}" | cut -d' ' -f1)" != "${SRC_MD5SUMS[$I]}" ]] && die "md5sum verification failed: ${SRC_FILENAMES[$I]}" (( I++ )) done < <(printf "%s\\n" "${SRC_DOWNLOADS[@]}") } # Unpack sources. while read -r SRC; do case "$SRC" in *.tar.?z|*.t?z) tar -xv -C "$BUILD_WORKDIR" -f "$SRC" || die "Failed to extract source: $SRC" ;; *.zip|*.ZIP) unzip -d "$BUILD_WORKDIR" "$SRC" || die "Failed to extract source: $SRC" ;; *) die "Un-handled source archive format: ${SRC##*.}" ;; esac done < <(printf "%s\\n" "${SRC_FILENAMES[@]}") # Fix any weird permissions on sources. chown -R root:root "${SRC_DIRNAMES[@]/#/$BUILD_WORKDIR/}" && chmod -R go-w "${SRC_DIRNAMES[@]/#/$BUILD_WORKDIR/}" || \ die "Failed to correct source directory permissions" # Standard ./configure options. CONFIGURE_OPTS=("${BUILD_ALTCC:+CC=\"$BUILD_ALTCC\"}" "${BUILD_ALTCXX:+CXX=\"$BUILD_ALTCXX\"}" "--prefix=\"$BUILD_PREFIX\"" "--libdir=\"$BUILD_PREFIX/lib$BUILD_LIBDIRSUFFIX\"" "--sysconfdir=\"/etc/$PKG_NAME\"" "--localstatedir=/var" "--mandir=\"$BUILD_PREFIX/man\"" "--infodir=\"$BUILD_PREFIX/info\"" "--build=\"$PKG_ARCH-slackware-linux\"" "--enable-shared" "--disable-static") # Process each of the sources. for ((I = 0; I < ${#SRC_DIRNAMES[@]}; I++)); do # Be in the source directory. cd "$BUILD_WORKDIR/${SRC_DIRNAMES[$I]}" || die "Failed to change to source directory: $BUILD_WORKDIR/${SRC_DIRNAMES[$I]}" ############################################ # Begin section that will require editing. # ############################################ # Build each source in the array. case "$I" in 0) # Patch before build. # zcat $SRC_DIR/patches/EDITME.diff.gz | patch -p0 || die "Source patching failed on: EDITME.diff.gz" # Configure. CFLAGS="$BUILD_CFLAGS" CXXFLAGS="$BUILD_CXXFLAGS" LDFLAGS="$BUILD_LDFLAGS" ./configure "${CONFIGURE_OPTS[@]}" \ --docdir="$BUILD_PREFIX/doc/${SRC_FILENAMES[$I]%%.*}" EDITME || \ die "Source ./configure failed: ${SRC_DIRNAMES[$I]}" # Build and install. make -j "$BUILD_NUMJOBS" "${BUILD_MAKEFLAGS[@]}" && make -j "$BUILD_NUMJOBS" "${BUILD_MAKEFLAGS[@]}" DESTDIR="$BUILD_ROOT" install || \ die "Failed to build and install source: ${SRC_DIRNAMES[$I]}" # Package documentation. mkdir -p -m 755 "$BUILD_ROOT/$BUILD_PREFIX/doc/${SRC_FILENAMES[$I]%%.*}" && cp --parents EDITME \ "$BUILD_ROOT/$BUILD_PREFIX/doc/${SRC_FILENAMES[$I]%%.*}" || die "Documentation copy failed: ${SRC_DIRNAMES[$I]}" ;; *) die "Un-handled source file - no build configuration" ;; esac done ################################################## # End of the only section that required editing. # ################################################## # Set up for sed replacements. SED_OPTS=("-e" "s:%BUILD_PREFIX%:$BUILD_PREFIX:g" "-e" "s:%BUILD_LIBDIR%:$BUILD_PREFIX/lib$BUILD_LIBDIRSUFFIX:g" "-e" "s:%BUILD_ARCH%:$BUILD_ARCH:g" "-e" "s:%DIST_OS_ID%:$DIST_OS_ID:g" "-e" "s:%DIST_OS_VERSION_ID%:$DIST_OS_VERSION_ID:g" "-e" "s:%PKG_NAME%:$PKG_NAME:g" "-e" "s:%PKG_VERSION%:$PKG_VERSION:g" "-e" "s:%PKG_FILE_VERSION%:${PKG_VERSION//-/_}:g" "-e" "s:%PKG_ARCH%:$PKG_ARCH:g" "-e" "s:%PKG_BUILD%:$PKG_BUILD:g" "-e" "s:%PKG_TAG%:${PKG_TAG//-/_}:g" "-e" "s:%PKG_EXT%:$PKG_EXT:g") # Add extra configuration/scripts. for DIR in cron.d cron.hourly cron.daily cron.weekly cron.monthly default logrotate.d profile.d rc.d; do [[ -e "$SRC_DIR/$DIR" ]] && { mkdir -p -m 755 "$BUILD_ROOT/etc/$DIR" || die "Failed to create directory: /etc/$DIR" for FILE in "$SRC_DIR/$DIR"/*; do sed -r "${SED_OPTS[@]}" <"$FILE" >"$BUILD_ROOT/etc/$DIR/${FILE##*/}" && chmod --reference="$FILE" "$BUILD_ROOT/etc/$DIR/${FILE##*/}" || \ die "Failed to copy $DIR/${FILE##*/} into package" done } done # Slackware packages don't ship with hardlinks (I don't know why...). HARDLINKS="$(find "$BUILD_ROOT" -type f -links +1 | tr $'\n' ' ')" [[ -n "$HARDLINKS" ]] && die "Found hardlinked files in package: $HARDLINKS" # Strip binaries. find "$BUILD_ROOT" -type f -exec file {} + | grep -E "ELF.*(executable|shared object)" | cut -d: -f1 | xargs -r strip --strip-unneeded || \ die "Failed to stip object files" # Move man and info pages if required. for DIR in "$BUILD_ROOT/$BUILD_PREFIX/share/man" "$BUILD_ROOT/usr/share/man" "$BUILD_ROOT/$BUILD_PREFIX/share/info" "$BUILD_ROOT/usr/share/info"; do [[ -e "$DIR" ]] && { mkdir -p -m 755 "$BUILD_ROOT/$BUILD_PREFIX/${DIR##*/}" || die "Failed to create $BUILD_PREFIX/${DIR##*/} directory" mv "$DIR"/* "$BUILD_ROOT/$BUILD_PREFIX/${DIR##*/}" && rmdir "$DIR" || die "Failed to move $DIR to correct directory" } done # Handle man pages. [[ -e "$BUILD_ROOT/$BUILD_PREFIX/man" ]] && { find "$BUILD_ROOT/$BUILD_PREFIX/man" -regextype posix-extended -type f -regex "^$BUILD_ROOT/$BUILD_PREFIX/man/([^/]*/)?man.*/.*\.[[:digit:]n]{1}[^.]*$" \ -exec gzip -9 {} + || die "Failed to compress man pages" find "$BUILD_ROOT/$BUILD_PREFIX/man" -type l -printf 'if [[ -e "%h/%l.gz" ]]; then (cd "%h" && ln -sf "%l.gz" "%f.gz" && rm -f "%f") || \ die "Failed to fix symlink: %f"; else die "Dangling symlink: %p"; fi\n' | bash || die "Man pages' symlinks correction failed" } # Compress and fix info pages. [[ -e "$BUILD_ROOT/$BUILD_PREFIX/info" ]] && { rm -f "$BUILD_ROOT/$BUILD_PREFIX/info/dir" find "$BUILD_ROOT/$BUILD_PREFIX/info" -regextype posix-extended -type f -regex "^$BUILD_ROOT/$BUILD_PREFIX/info/.*(\.info){1}(-[[:digit:]]+)?$" \ -exec gzip -9 {} + || die "Failed to compress info pages" find "$BUILD_ROOT/$BUILD_PREFIX/info" -type l -printf 'if [[ -e "%h/%l.gz" ]]; then (cd "%h" && ln -sf "%l.gz" "%f.gz" && rm -f "%f") || \ die "Failed to fix symlink: %f"; else die "Dangling symlink: %p"; fi\n' | bash || die "Info pages' symlink correction failed" } # Fix paths for perl modules. [[ -e "$BUILD_ROOT/$BUILD_PREFIX/lib$BUILD_LIBDIRSUFFIX/perl5" ]] && { find "$BUILD_ROOT/$BUILD_PREFIX/lib$BUILD_LIBDIRSUFFIX/perl5" -name .packlist -exec sed -ri -e "s:^$BUILD_ROOT::g" \ -e "s:^($BUILD_PREFIX|/usr){1}/share:$BUILD_PREFIX:g" \ -e "s:^$BUILD_PREFIX/man/([^/]*/)?(man.*)/(.*)\.([[:digit:]n]){1}([^.])*$:$BUILD_PREFIX/man/\1\2/\3\.\4\5\.gz:g" \ -e "s:^$BUILD_PREFIX/info/(.*)(\.info){1}(-[[:digit:]]+)?$:$BUILD_PREFIX/info/\1\2\3.gz:g" {} + || die "Failed to modify incorrect perl paths" find "$BUILD_ROOT" -name perllocal.pod -exec rm -f {} + # Should never fail # Note: These will fail if $BUILD_ROOT == /usr, but are required to clean left over directories from perllocal.pod removal. rmdir "$BUILD_ROOT/usr/lib$BUILD_LIBDIRSUFFIX/perl5" 2>/dev/null # OK to fail rmdir "$BUILD_ROOT/usr/lib$BUILD_LIBDIRSUFFIX" 2>/dev/null # OK to fail rmdir "$BUILD_ROOT/usr" 2>/dev/null # OK to fail } # /opt/{,-} is a special case. # Technically, the FHS requires everything in /opt to be contained in its own package directory, # so - assuming this technicallity is in use - make symlinks into the standard /opt dirs. [[ "$BUILD_PREFIX" =~ ^/opt/$PKG_NAME.* ]] && { (cd "$BUILD_ROOT/opt" && for DIR in bin doc include info lib lib64 libexec man sbin share; do [[ -e "${BUILD_PREFIX##*/}/$DIR" ]] && { mkdir -m 755 "$DIR" && (cd "$DIR" && lndir -silent "../${BUILD_PREFIX##*/}/$DIR)") || exit 1; } done) || die "Failed to link /opt paths" } # Copy pkgtool special files into the package. mkdir -m 755 "$BUILD_ROOT/install" || die "Failed to make /install directory" for FILE in doinst.sh douninst.sh slack-{conflicts,desc,required,suggests}; do [[ -e "$SRC_DIR/$FILE" ]] && { sed -r -e '/(^#|^$|-handy-ruler-)/ d' "${SED_OPTS[@]}" <"$SRC_DIR/$FILE" >"$BUILD_ROOT/install/$FILE" || \ die "Failed to copy in pkgtool special file: $FILE" } done # Build the package. cd "$BUILD_ROOT" || die "Failed to cd to BUILD_ROOT to build package" rm -f "$BUILD_WORKDIR/$PKG_NAME-${PKG_VERSION//-/_}-$PKG_ARCH-$PKG_BUILD${PKG_TAG//-/_}".* makepkg -l y -p -c n --acls --xattrs "$BUILD_WORKDIR/$PKG_NAME-${PKG_VERSION//-/_}-$PKG_ARCH-$PKG_BUILD${PKG_TAG//-/_}.$PKG_EXT" || \ die "Package creation failed" # Clean up after ourselves. (( ${BUILD_CLEANUP:-1} == 1 )) && rm -rf "$BUILD_ROOT" "${SRC_DIRNAMES[@]/#/$BUILD_WORKDIR/}" # Move package to the store. mkdir -p -m 755 "$PKG_STORE" && mv --backup=numbered "$BUILD_WORKDIR/$PKG_NAME-${PKG_VERSION//-/_}-$PKG_ARCH-$PKG_BUILD${PKG_TAG//-/_}.$PKG_EXT" \ "$PKG_STORE" || die "Failed to move package to store - package left in $BUILD_WORKDIR" printf "\\033[1;32;40m%s:\\n %s\\033[0;39m\\n" "Package built and moved to store" \ "$PKG_STORE/$PKG_NAME-${PKG_VERSION//-/_}-$PKG_ARCH-$PKG_BUILD${PKG_TAG//-/_}.$PKG_EXT"