diff --git a/build-package.sh b/build-package.sh index 89885b0870..5ae9ce0357 100755 --- a/build-package.sh +++ b/build-package.sh @@ -1,6 +1,21 @@ #!/bin/bash # shellcheck disable=SC1117 +# Setting the TMPDIR variable +: "${TMPDIR:=/tmp}" +export TMPDIR + +# Set the build-package.sh call depth +# If its the root call, then create a file to store the list of packages and their dependencies +# that have been compiled at any instant by recursive calls to build-package.sh +if [[ ! "$TERMUX_BUILD_PACKAGE_CALL_DEPTH" =~ ^[0-9]+$ ]]; then + export TERMUX_BUILD_PACKAGE_CALL_DEPTH=0 + export TERMUX_BUILD_PACKAGE_CALL_BUILT_PACKAGES_LIST_FILE_PATH="${TMPDIR}/build-package-call-built-packages-list-$(date +"%Y-%m-%d-%H.%M.%S.")$((RANDOM%1000))" + echo -n " " > "$TERMUX_BUILD_PACKAGE_CALL_BUILT_PACKAGES_LIST_FILE_PATH" +else + export TERMUX_BUILD_PACKAGE_CALL_DEPTH=$((TERMUX_BUILD_PACKAGE_CALL_DEPTH+1)) +fi + set -e -o pipefail -u cd "$(realpath "$(dirname "$0")")" @@ -10,13 +25,12 @@ export TERMUX_SCRIPTDIR # Store pid of current process in a file for docker__run_docker_exec_trap source "$TERMUX_SCRIPTDIR/scripts/utils/docker/docker.sh"; docker__create_docker_exec_pid_file +# Functions for working with packages +source "$TERMUX_SCRIPTDIR/scripts/utils/package/package.sh" SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct 2>/dev/null || date "+%s") export SOURCE_DATE_EPOCH -: "${TMPDIR:=/tmp}" -export TMPDIR - if [ "$(uname -o)" = "Android" ] || [ -e "/system/bin/app_process" ]; then if [ "$(id -u)" = "0" ]; then echo "On-device execution of this script as root is disabled." @@ -348,6 +362,20 @@ if [ "$TERMUX_ON_DEVICE_BUILD" = "true" ]; then export TERMUX_ARCH fi +# Check if the package is in the compiled list +termux_check_package_in_built_packages_list() { + [ ! -f "$TERMUX_BUILD_PACKAGE_CALL_BUILT_PACKAGES_LIST_FILE_PATH" ] && termux_error_exit "ERROR: file '$TERMUX_BUILD_PACKAGE_CALL_BUILT_PACKAGES_LIST_FILE_PATH' not found." + cat "$TERMUX_BUILD_PACKAGE_CALL_BUILT_PACKAGES_LIST_FILE_PATH" | grep -q " $1 " + return $? +} + +# Adds a package to the list of built packages if it is not in the list +termux_add_package_to_built_packages_list() { + if ! termux_check_package_in_built_packages_list "$1"; then + echo -n "$1 " >> $TERMUX_BUILD_PACKAGE_CALL_BUILT_PACKAGES_LIST_FILE_PATH + fi +} + # Special hook to prevent use of "sudo" inside package build scripts. # build-package.sh shouldn't perform any privileged operations. sudo() { @@ -364,6 +392,7 @@ _show_usage() { echo " -d Build with debug symbols." echo " -D Build a disabled package in disabled-packages/." echo " -f Force build even if package has already been built." + echo " -F Force build even if package and its dependencies have already been built." [ "$TERMUX_ON_DEVICE_BUILD" = "false" ] && echo " -i Download and extract dependencies instead of building them." echo " -I Download and extract dependencies instead of building them, keep existing $TERMUX_BASE_DIR files." echo " -q Quiet build." @@ -409,6 +438,7 @@ while (($# >= 1)); do -d) export TERMUX_DEBUG_BUILD=true;; -D) TERMUX_IS_DISABLED=true;; -f) TERMUX_FORCE_BUILD=true;; + -F) TERMUX_FORCE_BUILD_DEPENDENCIES=true && TERMUX_FORCE_BUILD=true;; -i) if [ "$TERMUX_ON_DEVICE_BUILD" = "true" ]; then termux_error_exit "./build-package.sh: option '-i' is not available for on-device builds" @@ -577,6 +607,13 @@ for ((i=0; i<${#PACKAGE_LIST[@]}; i++)); do else termux_error_exit "Unknown packaging format '$TERMUX_PACKAGE_FORMAT'." fi + # Saving a list of compiled packages for further work with it + termux_add_package_to_built_packages_list "$TERMUX_PKG_NAME" termux_step_finish_build ) 5< "$TERMUX_BUILD_LOCK_FILE" done + +# Removing a file to store a list of compiled packages +if [ "$TERMUX_BUILD_PACKAGE_CALL_DEPTH" = "0" ]; then + rm "$TERMUX_BUILD_PACKAGE_CALL_BUILT_PACKAGES_LIST_FILE_PATH" +fi diff --git a/scripts/build/termux_step_get_dependencies.sh b/scripts/build/termux_step_get_dependencies.sh index 2cbc865dfc..758988db0c 100644 --- a/scripts/build/termux_step_get_dependencies.sh +++ b/scripts/build/termux_step_get_dependencies.sh @@ -1,5 +1,9 @@ termux_step_get_dependencies() { - if [ "$TERMUX_SKIP_DEPCHECK" = false ] && [ "$TERMUX_INSTALL_DEPS" = true ] && [ "$TERMUX_PKG_METAPACKAGE" = "false" ]; then + if [ "$TERMUX_SKIP_DEPCHECK" = true ] || [ "$TERMUX_PKG_METAPACKAGE" = true ]; then + return 0 + fi + + if [ "$TERMUX_INSTALL_DEPS" = true ]; then # Download repo files termux_get_repo_files @@ -10,8 +14,6 @@ termux_step_get_dependencies() { "pacman") pacman -Sy;; esac fi - - # Download dependencies while read PKG PKG_DIR; do if [ -z $PKG ]; then continue @@ -21,29 +23,39 @@ termux_step_get_dependencies() { # llvm doesn't build if ndk-sysroot is installed: if [ "$PKG" = "ndk-sysroot" ]; then continue; fi read DEP_ARCH DEP_VERSION DEP_VERSION_PAC <<< $(termux_extract_dep_info $PKG "${PKG_DIR}") - - if [ ! "$TERMUX_QUIET_BUILD" = true ]; then - echo "Downloading dependency $PKG@$DEP_VERSION if necessary..." + [ ! "$TERMUX_QUIET_BUILD" = true ] && echo "Downloading dependency $PKG@$DEP_VERSION if necessary..." + local force_build_dependency="$TERMUX_FORCE_BUILD_DEPENDENCIES" + if [ "$TERMUX_FORCE_BUILD_DEPENDENCIES" = "true" ] && [ "$TERMUX_ON_DEVICE_BUILD" = "true" ] && ! pacakge__is_package_on_device_build_supported "$PKG_DIR"; then + echo "Building dependency $PKG on device is not supported. It will be downloaded..." + force_build_dependency="false" fi - - if [ -e "$TERMUX_BUILT_PACKAGES_DIRECTORY/$PKG" ]; then - if [ "$(cat "$TERMUX_BUILT_PACKAGES_DIRECTORY/$PKG")" = "$DEP_VERSION" ]; then - if [ ! "$TERMUX_QUIET_BUILD" = true ]; then - echo "Skipping already built dependency $PKG@$DEP_VERSION" - fi + local build_dependency=false + if [ "$force_build_dependency" = "true" ]; then + [ ! "$TERMUX_QUIET_BUILD" = true ] && echo "Force building dependency $PKG instead of downloading due to -I flag..." + termux_force_check_package_dependency && continue + build_dependency=true + else + if pacakge__is_package_version_built "$PKG" "$DEP_VERSION"; then + [ ! "$TERMUX_QUIET_BUILD" = true ] && echo "Skipping already built dependency $PKG@$DEP_VERSION" continue fi + if ! termux_download_deb_pac $PKG $DEP_ARCH $DEP_VERSION $DEP_VERSION_PAC; then + if [ "$TERMUX_FORCE_BUILD_DEPENDENCIES" = "true" ] && [ "$TERMUX_ON_DEVICE_BUILD" = "true" ]; then + echo "Download of $PKG@$DEP_VERSION from $TERMUX_REPO_URL failed" + return 1 + else + echo "Download of $PKG@$DEP_VERSION from $TERMUX_REPO_URL failed, building instead" + build_dependency=true + fi + fi fi - - if ! termux_download_deb_pac $PKG $DEP_ARCH $DEP_VERSION $DEP_VERSION_PAC; then - echo "Download of $PKG@$DEP_VERSION from $TERMUX_REPO_URL failed, building instead" - TERMUX_BUILD_IGNORE_LOCK=true ./build-package.sh $(test "${TERMUX_FORCE_BUILD}" = "true" && echo "-f" || true) -I --format $TERMUX_PACKAGE_FORMAT "${PKG_DIR}" + if $build_dependency; then + TERMUX_BUILD_IGNORE_LOCK=true ./build-package.sh -I $(test "${TERMUX_FORCE_BUILD_DEPENDENCIES}" = "true" && echo "-F" || true) --format $TERMUX_PACKAGE_FORMAT "${PKG_DIR}" continue fi + termux_add_package_to_built_packages_list "$PKG" if [ "$TERMUX_ON_DEVICE_BUILD" = "false" ]; then - if [ ! "$TERMUX_QUIET_BUILD" = true ]; then - echo "extracting $PKG to $TERMUX_COMMON_CACHEDIR-$DEP_ARCH..." - fi + [ ! "$TERMUX_QUIET_BUILD" = true ] && echo "extracting $PKG to $TERMUX_COMMON_CACHEDIR-$DEP_ARCH..." ( cd $TERMUX_COMMON_CACHEDIR-$DEP_ARCH ar x ${PKG}_${DEP_VERSION}_${DEP_ARCH}.deb data.tar.xz @@ -57,11 +69,10 @@ termux_step_get_dependencies() { fi ) fi - mkdir -p $TERMUX_BUILT_PACKAGES_DIRECTORY echo "$DEP_VERSION" > "$TERMUX_BUILT_PACKAGES_DIRECTORY/$PKG" done<<<$(./scripts/buildorder.py -i "$TERMUX_PKG_BUILDER_DIR" $TERMUX_PACKAGES_DIRECTORIES || echo "ERROR") - elif [ "$TERMUX_SKIP_DEPCHECK" = false ] && [ "$TERMUX_INSTALL_DEPS" = false ] && [ "$TERMUX_PKG_METAPACKAGE" = "false" ]; then + else # Build dependencies while read PKG PKG_DIR; do if [ -z $PKG ]; then @@ -69,9 +80,27 @@ termux_step_get_dependencies() { elif [ "$PKG" = "ERROR" ]; then termux_error_exit "Obtaining buildorder failed" fi - echo "Building dependency $PKG if necessary..." # Built dependencies are put in the default TERMUX_OUTPUT_DIR instead of the specified one - TERMUX_BUILD_IGNORE_LOCK=true ./build-package.sh $(test "${TERMUX_FORCE_BUILD}" = "true" && echo "-f" || true) -s --format $TERMUX_PACKAGE_FORMAT "${PKG_DIR}" + if [ "$TERMUX_FORCE_BUILD_DEPENDENCIES" = "true" ]; then + [ ! "$TERMUX_QUIET_BUILD" = true ] && echo "Force building dependency $PKG..." + if [ "$TERMUX_ON_DEVICE_BUILD" = "true" ] && ! pacakge__is_package_on_device_build_supported "$PKG_DIR"; then + echo "Building $PKG on device is not supported. Consider passing -I flag to download it instead" + return 1 + fi + read DEP_ARCH DEP_VERSION DEP_VERSION_PAC <<< $(termux_extract_dep_info $PKG "${PKG_DIR}") + termux_force_check_package_dependency && continue + else + [ ! "$TERMUX_QUIET_BUILD" = true ] && echo "Building dependency $PKG if necessary..." + fi + TERMUX_BUILD_IGNORE_LOCK=true ./build-package.sh -s $(test "${TERMUX_FORCE_BUILD_DEPENDENCIES}" = "true" && echo "-F" || true) --format $TERMUX_PACKAGE_FORMAT "${PKG_DIR}" done<<<$(./scripts/buildorder.py "$TERMUX_PKG_BUILDER_DIR" $TERMUX_PACKAGES_DIRECTORIES || echo "ERROR") fi } + +termux_force_check_package_dependency() { + if termux_check_package_in_built_packages_list "$PKG" && pacakge__is_package_version_built "$PKG" "$DEP_VERSION"; then + [ ! "$TERMUX_QUIET_BUILD" = true ] && echo "Skipping already built dependency $PKG@$DEP_VERSION" + return 0 + fi + return 1 +} diff --git a/scripts/build/termux_step_setup_variables.sh b/scripts/build/termux_step_setup_variables.sh index 05805b875c..658ee512b3 100644 --- a/scripts/build/termux_step_setup_variables.sh +++ b/scripts/build/termux_step_setup_variables.sh @@ -3,6 +3,7 @@ termux_step_setup_variables() { : "${TERMUX_OUTPUT_DIR:="${TERMUX_SCRIPTDIR}/output"}" : "${TERMUX_DEBUG_BUILD:="false"}" : "${TERMUX_FORCE_BUILD:="false"}" + : "${TERMUX_FORCE_BUILD_DEPENDENCIES:="false"}" : "${TERMUX_INSTALL_DEPS:="false"}" : "${TERMUX_MAKE_PROCESSES:="$(nproc)"}" : "${TERMUX_NO_CLEAN:="false"}" @@ -124,6 +125,7 @@ termux_step_setup_variables() { TERMUX_PKG_GROUPS="" # https://wiki.archlinux.org/title/Pacman#Installing_package_groups TERMUX_PKG_NO_SHEBANG_FIX=false # if true, skip fixing shebang accordingly to TERMUX_PREFIX TERMUX_PKG_IS_HASKELL_LIB=true # by default assume haskell package is lib package as most of them will always be libs. + TERMUX_PKG_ON_DEVICE_BUILD_NOT_SUPPORTED=false # if the package does not support compilation on a device, then this package should not be compiled on devices unset CFLAGS CPPFLAGS LDFLAGS CXXFLAGS } diff --git a/scripts/build/termux_step_start_build.sh b/scripts/build/termux_step_start_build.sh index ca01706e4b..cc38671b6d 100644 --- a/scripts/build/termux_step_start_build.sh +++ b/scripts/build/termux_step_start_build.sh @@ -78,6 +78,11 @@ termux_step_start_build() { # a continued build return fi + + if [ "$TERMUX_ON_DEVICE_BUILD" = "true" ] && [ "$TERMUX_PKG_ON_DEVICE_BUILD_NOT_SUPPORTED" = "true" ]; then + termux_error_exit "Package '$TERMUX_PKG_NAME' is not available for on-device builds." + fi + if [ "$TERMUX_ON_DEVICE_BUILD" = "true" ]; then case "$TERMUX_APP_PACKAGE_MANAGER" in "apt") apt install -y termux-elf-cleaner;; diff --git a/scripts/utils/package/package.sh b/scripts/utils/package/package.sh new file mode 100644 index 0000000000..a11be7da99 --- /dev/null +++ b/scripts/utils/package/package.sh @@ -0,0 +1,49 @@ +# shellcheck shell=sh +# shellcheck disable=SC2039,SC2059 + +# Title: package +# Description: A library for package utils. + + + +## +# Check if package on device builds are supported by checking +# `$TERMUX_PKG_ON_DEVICE_BUILD_NOT_SUPPORTED` value in its `build.sh` +# file. +# . +# . +# **Parameters:** +# `package_dir` - The directory path for the package `build.sh` file. +# . +# **Returns:** +# Returns `0` if supported, otherwise `1`. +# . +# . +# pacakge__is_package_on_device_build_supported `package_dir` +## +pacakge__is_package_on_device_build_supported() { + [ $(. "${1}/build.sh"; echo "$TERMUX_PKG_ON_DEVICE_BUILD_NOT_SUPPORTED") != "true" ] + return $? +} + + + +## +# Check if a specific version of a package has been built by checking +# the `$TERMUX_BUILT_PACKAGES_DIRECTORY/` file. +# . +# . +# **Parameters:** +# `package_name` - The package name for the package. +# `package_version` - The package version for the package to check. +# . +# **Returns:** +# Returns `0` if built, otherwise `1`. +# . +# . +# pacakge__is_package_version_built `package_name` `package_version` +## +pacakge__is_package_version_built() { + [ -e "$TERMUX_BUILT_PACKAGES_DIRECTORY/$1" ] && [ "$(cat "$TERMUX_BUILT_PACKAGES_DIRECTORY/$1")" = "$2" ] + return $? +}