diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..33487390e --- /dev/null +++ b/.gitattributes @@ -0,0 +1,21 @@ +# Default. +* text eol=lf + +# Treat patch files as binaries but let diff'ing them +# as normal text. +*.diff binary diff +*.patch binary diff +*.patch32 binary diff +*.patch64 binary diff +*.patch.* binary diff + +# Powershell scripts. +*.ps1 text eol=crlf + +# Binaries. +*.gpg binary +*.gz binary +*.jpg binary +*.png binary +*.tar binary +*.tar.* binary diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 000000000..9a4e9b047 --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,14 @@ +daysUntilStale: 45 +daysUntilClose: 14 + +exemptLabels: + - "not stale" + - "package request" + +markComment: > + This issue/PR has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. + +staleLabel: wontfix + diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..108df79ee --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +# Vim +[._]*.s[a-w][a-z] +[._]s[a-w][a-z] +*.un~ +Session.vim +.netrwhist +*~ + +# Vagrant +scripts/*.log +scripts/.vagrant/ + +# Built *.deb files. +/debs/ +/output/ + +# Preinstalled build tools. +/build-tools/ + +# Predownloaded packages sources. +/packages/*/cache +/root-packages/*/cache +/x11-packages/*/cache diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 000000000..444b7be45 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,11 @@ +# License for package patches + +The scripts and patches to build each package is licensed under the same +license as the actual package (so the patches and scripts to build bash are +licensed under the same license as bash, while the patches and scripts to build +python are licensed under the same license as python). + +# License for the build infrastructure + +For build infrastructure outside the `packages/` folder the license is +[Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0). diff --git a/build-all.sh b/build-all.sh new file mode 100755 index 000000000..78f0a8de1 --- /dev/null +++ b/build-all.sh @@ -0,0 +1,88 @@ +#!/bin/bash +# build-all.sh - script to build all packages with a build order specified by buildorder.py + +set -e -u -o pipefail + +if [ "$(uname -o)" = "Android" ] || [ -e "/system/bin/app_process" ]; then + echo "On-device execution of this script is not supported." + exit 1 +fi + +# Read settings from .termuxrc if existing +test -f "$HOME"/.termuxrc && . "$HOME"/.termuxrc +: ${TERMUX_TOPDIR:="$HOME/.termux-build"} +: ${TERMUX_ARCH:="aarch64"} +: ${TERMUX_DEBUG_BUILD:=""} +: ${TERMUX_INSTALL_DEPS:="-s"} +# Set TERMUX_INSTALL_DEPS to -s unless set to -i + +_show_usage() { + echo "Usage: ./build-all.sh [-a ARCH] [-d] [-i] [-o DIR]" + echo "Build all packages." + echo " -a The architecture to build for: aarch64(default), arm, i686, x86_64 or all." + echo " -d Build with debug symbols." + echo " -i Build dependencies." + echo " -o Specify deb directory. Default: debs/." + exit 1 +} + +while getopts :a:hdio: option; do +case "$option" in + a) TERMUX_ARCH="$OPTARG";; + d) TERMUX_DEBUG_BUILD='-d';; + i) TERMUX_INSTALL_DEPS='-i';; + o) TERMUX_OUTPUT_DIR="$(realpath -m "$OPTARG")";; + h) _show_usage;; + *) _show_usage >&2 ;; +esac +done +shift $((OPTIND-1)) +if [ "$#" -ne 0 ]; then _show_usage; fi + +if [[ ! "$TERMUX_ARCH" =~ ^(all|aarch64|arm|i686|x86_64)$ ]]; then + echo "ERROR: Invalid arch '$TERMUX_ARCH'" 1>&2 + exit 1 +fi + +BUILDSCRIPT=$(dirname "$0")/build-package.sh +BUILDALL_DIR=$TERMUX_TOPDIR/_buildall-$TERMUX_ARCH +BUILDORDER_FILE=$BUILDALL_DIR/buildorder.txt +BUILDSTATUS_FILE=$BUILDALL_DIR/buildstatus.txt + +if [ -e "$BUILDORDER_FILE" ]; then + echo "Using existing buildorder file: $BUILDORDER_FILE" +else + mkdir -p "$BUILDALL_DIR" + ./scripts/buildorder.py > "$BUILDORDER_FILE" +fi +if [ -e "$BUILDSTATUS_FILE" ]; then + echo "Continuing build-all from: $BUILDSTATUS_FILE" +fi + +exec > >(tee -a "$BUILDALL_DIR"/ALL.out) +exec 2> >(tee -a "$BUILDALL_DIR"/ALL.err >&2) +trap 'echo ERROR: See $BUILDALL_DIR/${PKG}.err' ERR + +while read -r PKG PKG_DIR; do + # Check build status (grepping is a bit crude, but it works) + if [ -e "$BUILDSTATUS_FILE" ] && grep "^$PKG\$" "$BUILDSTATUS_FILE" >/dev/null; then + echo "Skipping $PKG" + continue + fi + + echo -n "Building $PKG... " + BUILD_START=$(date "+%s") + bash -x "$BUILDSCRIPT" -a "$TERMUX_ARCH" $TERMUX_DEBUG_BUILD \ + ${TERMUX_OUTPUT_DIR+-o $TERMUX_OUTPUT_DIR} $TERMUX_INSTALL_DEPS "$PKG_DIR" \ + > "$BUILDALL_DIR"/"${PKG}".out 2> "$BUILDALL_DIR"/"${PKG}".err + BUILD_END=$(date "+%s") + BUILD_SECONDS=$(( BUILD_END - BUILD_START )) + echo "done in $BUILD_SECONDS" + + # Update build status + echo "$PKG" >> "$BUILDSTATUS_FILE" +done<"${BUILDORDER_FILE}" + +# Update build status +rm -f "$BUILDSTATUS_FILE" +echo "Finished" diff --git a/build-package.sh b/build-package.sh new file mode 100755 index 000000000..20c9847f2 --- /dev/null +++ b/build-package.sh @@ -0,0 +1,556 @@ +#!/bin/bash +# shellcheck disable=SC1117 + +set -e -o pipefail -u + +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." + exit 1 + fi + + # This variable tells all parts of build system that build + # is performed on device. + export TERMUX_ON_DEVICE_BUILD=true +else + export TERMUX_ON_DEVICE_BUILD=false +fi + +cd "$(realpath "$(dirname "$0")")" +TERMUX_SCRIPTDIR=$(pwd) +export TERMUX_SCRIPTDIR + +# Automatically enable offline set of sources and build tools. +# Offline termux-packages bundle can be created by executing +# script ./scripts/setup-offline-bundle.sh. +if [ -f "${TERMUX_SCRIPTDIR}/build-tools/.installed" ]; then + export TERMUX_PACKAGES_OFFLINE=true +fi + +# Lock file to prevent parallel running in the same environment. +TERMUX_BUILD_LOCK_FILE="${TMPDIR}/.termux-build.lck" +if [ ! -e "$TERMUX_BUILD_LOCK_FILE" ]; then + touch "$TERMUX_BUILD_LOCK_FILE" +fi + +export TERMUX_PACKAGES_DIRECTORIES=$(jq --raw-output 'keys | .[]' ${TERMUX_SCRIPTDIR}/repo.json) + +# Special variable for internal use. It forces script to ignore +# lock file. +: "${TERMUX_BUILD_IGNORE_LOCK:=false}" + +# Utility function to log an error message and exit with an error code. +# shellcheck source=scripts/build/termux_error_exit.sh +source "$TERMUX_SCRIPTDIR/scripts/build/termux_error_exit.sh" + +# Utility function to download a resource with an expected checksum. +# shellcheck source=scripts/build/termux_download.sh +source "$TERMUX_SCRIPTDIR/scripts/build/termux_download.sh" + +# Utility function for setting up GHC toolchain. +# shellcheck source=scripts/build/setup/termux_setup_ghc.sh +source "$TERMUX_SCRIPTDIR/scripts/build/setup/termux_setup_ghc.sh" + +# Utility function to setup a GHC cross-compiler toolchain targeting Android. +# shellcheck source=scripts/build/setup/termux_setup_ghc_cross_compiler.sh +source "$TERMUX_SCRIPTDIR/scripts/build/setup/termux_setup_ghc_cross_compiler.sh" + +# Utility function to setup cabal-install (may be used by ghc toolchain). +# shellcheck source=scripts/build/setup/termux_setup_cabal.sh. +source "$TERMUX_SCRIPTDIR/scripts/build/setup/termux_setup_cabal.sh" + +# Utility function to setup jailbreak-cabal. It is used to remove version constraints +# from Cabal packages. +# shellcheck source=scripts/build/setup/termux_setup_jailbreak_cabal.sh +source "$TERMUX_SCRIPTDIR/scripts/build/setup/termux_setup_jailbreak_cabal.sh" + +# Utility function for setting up GN toolchain. +# shellcheck source=scripts/build/setup/termux_setup_gn.sh +source "$TERMUX_SCRIPTDIR/scripts/build/setup/termux_setup_gn.sh" + +# Utility function for golang-using packages to setup a go toolchain. +# shellcheck source=scripts/build/setup/termux_setup_golang.sh +source "$TERMUX_SCRIPTDIR/scripts/build/setup/termux_setup_golang.sh" + +# Utility function for python packages to setup a python crossenv. +# shellcheck source=scripts/build/setup/termux_setup_python_crossenv.sh +source "$TERMUX_SCRIPTDIR/scripts/build/setup/termux_setup_python_crossenv.sh" + +# Utility function for rust-using packages to setup a rust toolchain. +# shellcheck source=scripts/build/setup/termux_setup_rust.sh +source "$TERMUX_SCRIPTDIR/scripts/build/setup/termux_setup_rust.sh" + +# Utility function for swift-using packages to setup a swift toolchain +# shellcheck source=scripts/build/setup/termux_setup_swift.sh +source "$TERMUX_SCRIPTDIR/scripts/build/setup/termux_setup_swift.sh" + +# Utility function for zig-using packages to setup a zig toolchain. +# shellcheck source=scripts/build/setup/termux_setup_zig.sh +source "$TERMUX_SCRIPTDIR/scripts/build/setup/termux_setup_zig.sh" + +# Utility function to setup a current ninja build system. +# shellcheck source=scripts/build/setup/termux_setup_ninja.sh +source "$TERMUX_SCRIPTDIR/scripts/build/setup/termux_setup_ninja.sh" + +# Utility function to setup Node.js JavaScript Runtime +# shellcheck source=scripts/build/setup/termux_setup_nodejs.sh +source "$TERMUX_SCRIPTDIR/scripts/build/setup/termux_setup_nodejs.sh" + +# Utility function to setup a current meson build system. +# shellcheck source=scripts/build/setup/termux_setup_meson.sh +source "$TERMUX_SCRIPTDIR/scripts/build/setup/termux_setup_meson.sh" + +# Utility function to setup a current cmake build system +# shellcheck source=scripts/build/setup/termux_setup_cmake.sh +source "$TERMUX_SCRIPTDIR/scripts/build/setup/termux_setup_cmake.sh" + +# Utility function to setup protobuf: +# shellcheck source=scripts/build/setup/termux_setup_protobuf.sh +source "$TERMUX_SCRIPTDIR/scripts/build/setup/termux_setup_protobuf.sh" + +# Setup variables used by the build. Not to be overridden by packages. +# shellcheck source=scripts/build/termux_step_setup_variables.sh +source "$TERMUX_SCRIPTDIR/scripts/build/termux_step_setup_variables.sh" + +# Save away and restore build setups which may change between builds. +# shellcheck source=scripts/build/termux_step_handle_buildarch.sh +source "$TERMUX_SCRIPTDIR/scripts/build/termux_step_handle_buildarch.sh" + +# Function to get TERMUX_PKG_VERSION from build.sh +# shellcheck source=scripts/build/termux_extract_dep_info.sh +source "$TERMUX_SCRIPTDIR/scripts/build/termux_extract_dep_info.sh" + +# Function that downloads a .deb (using the termux_download function) +# shellcheck source=scripts/build/termux_download_deb_pac.sh +source "$TERMUX_SCRIPTDIR/scripts/build/termux_download_deb_pac.sh" + +# Script to download InRelease, verify it's signature and then download Packages.xz by hash +# shellcheck source=scripts/build/termux_get_repo_files.sh +source "$TERMUX_SCRIPTDIR/scripts/build/termux_get_repo_files.sh" + +# Download or build dependencies. Not to be overridden by packages. +# shellcheck source=scripts/build/termux_step_get_dependencies.sh +source "$TERMUX_SCRIPTDIR/scripts/build/termux_step_get_dependencies.sh" + +# Handle config scripts that needs to be run during build. Not to be overridden by packages. +# shellcheck source=scripts/build/termux_step_override_config_scripts.sh +source "$TERMUX_SCRIPTDIR/scripts/build/termux_step_override_config_scripts.sh" + +# Remove old src and build folders and create new ones +# shellcheck source=scripts/build/termux_step_setup_build_folders.sh +source "$TERMUX_SCRIPTDIR/scripts/build/termux_step_setup_build_folders.sh" + +# Source the package build script and start building. Not to be overridden by packages. +# shellcheck source=scripts/build/termux_step_start_build.sh +source "$TERMUX_SCRIPTDIR/scripts/build/termux_step_start_build.sh" + +# Download or build dependencies. Not to be overridden by packages. +# shellcheck source=scripts/build/termux_step_create_timestamp_file.sh +source "$TERMUX_SCRIPTDIR/scripts/build/termux_step_create_timestamp_file.sh" + +# Run just after sourcing $TERMUX_PKG_BUILDER_SCRIPT. Can be overridden by packages. +# shellcheck source=scripts/build/get_source/termux_step_get_source.sh +source "$TERMUX_SCRIPTDIR/scripts/build/get_source/termux_step_get_source.sh" + +# Run from termux_step_get_source if TERMUX_PKG_SRCURL ends with .git. +# shellcheck source=scripts/build/get_source/termux_step_get_source.sh +source "$TERMUX_SCRIPTDIR/scripts/build/get_source/termux_git_clone_src.sh" + +# Run from termux_step_get_source if TERMUX_PKG_SRCURL does not ends with .git. +# shellcheck source=scripts/build/get_source/termux_download_src_archive.sh +source "$TERMUX_SCRIPTDIR/scripts/build/get_source/termux_download_src_archive.sh" + +# Run from termux_step_get_source after termux_download_src_archive. +# shellcheck source=scripts/build/get_source/termux_unpack_src_archive.sh +source "$TERMUX_SCRIPTDIR/scripts/build/get_source/termux_unpack_src_archive.sh" + +# Hook for packages to act just after the package sources have been obtained. +# Invoked from $TERMUX_PKG_SRCDIR. +termux_step_post_get_source() { + return +} + +# Optional host build. Not to be overridden by packages. +# shellcheck source=scripts/build/termux_step_handle_hostbuild.sh +source "$TERMUX_SCRIPTDIR/scripts/build/termux_step_handle_hostbuild.sh" + +# Perform a host build. Will be called in $TERMUX_PKG_HOSTBUILD_DIR. +# After termux_step_post_get_source() and before termux_step_patch_package() +# shellcheck source=scripts/build/termux_step_host_build.sh +source "$TERMUX_SCRIPTDIR/scripts/build/termux_step_host_build.sh" + +# Setup a standalone Android NDK toolchain. Not to be overridden by packages. +# shellcheck source=scripts/build/termux_step_setup_toolchain.sh +source "$TERMUX_SCRIPTDIR/scripts/build/termux_step_setup_toolchain.sh" + +# Apply all *.patch files for the package. Not to be overridden by packages. +# shellcheck source=scripts/build/termux_step_patch_package.sh +source "$TERMUX_SCRIPTDIR/scripts/build/termux_step_patch_package.sh" + +# Replace autotools build-aux/config.{sub,guess} with ours to add android targets. +# shellcheck source=scripts/build/termux_step_replace_guess_scripts.sh +source "$TERMUX_SCRIPTDIR/scripts/build/termux_step_replace_guess_scripts.sh" + +# For package scripts to override. Called in $TERMUX_PKG_BUILDDIR. +termux_step_pre_configure() { + return +} + +# Setup configure args and run $TERMUX_PKG_SRCDIR/configure. This function is called from termux_step_configure +# shellcheck source=scripts/build/configure/termux_step_configure_autotools.sh +source "$TERMUX_SCRIPTDIR/scripts/build/configure/termux_step_configure_autotools.sh" + +# Setup configure args and run cmake. This function is called from termux_step_configure +# shellcheck source=scripts/build/configure/termux_step_configure_cmake.sh +source "$TERMUX_SCRIPTDIR/scripts/build/configure/termux_step_configure_cmake.sh" + +# Setup configure args and run meson. This function is called from termux_step_configure +# shellcheck source=scripts/build/configure/termux_step_configure_meson.sh +source "$TERMUX_SCRIPTDIR/scripts/build/configure/termux_step_configure_meson.sh" + +# Setup configure args and run haskell build system. This function is called from termux_step_configure. +# shellcheck source=scripts/build/configure/termux_step_configure_haskell_build.sh +source "$TERMUX_SCRIPTDIR/scripts/build/configure/termux_step_configure_haskell_build.sh" + +# Configure the package +# shellcheck source=scripts/build/configure/termux_step_configure.sh +source "$TERMUX_SCRIPTDIR/scripts/build/configure/termux_step_configure.sh" + +# Hook for packages after configure step +termux_step_post_configure() { + return +} + +# Make package, either with ninja or make +# shellcheck source=scripts/build/termux_step_make.sh +source "$TERMUX_SCRIPTDIR/scripts/build/termux_step_make.sh" + +# Make install, either with ninja, make of cargo +# shellcheck source=scripts/build/termux_step_make_install.sh +source "$TERMUX_SCRIPTDIR/scripts/build/termux_step_make_install.sh" + +# Hook function for package scripts to override. +termux_step_post_make_install() { + return +} + +# Add service scripts from array TERMUX_PKG_SERVICE_SCRIPT, if it is set +# shellcheck source=scripts/build/termux_step_install_service_scripts.sh +source "$TERMUX_SCRIPTDIR/scripts/build/termux_step_install_service_scripts.sh" + +# Link/copy the LICENSE for the package to $TERMUX_PREFIX/share/$TERMUX_PKG_NAME/ +# shellcheck source=scripts/build/termux_step_install_license.sh +source "$TERMUX_SCRIPTDIR/scripts/build/termux_step_install_license.sh" + +# Function to cp (through tar) installed files to massage dir +# shellcheck source=scripts/build/termux_step_extract_into_massagedir.sh +source "$TERMUX_SCRIPTDIR/scripts/build/termux_step_extract_into_massagedir.sh" + +# Hook function to create {pre,post}install, {pre,post}rm-scripts for subpkgs +termux_step_create_subpkg_debscripts() { + return +} + +# Create all subpackages. Run from termux_step_massage +# shellcheck source=scripts/build/termux_create_debian_subpackages.sh +source "$TERMUX_SCRIPTDIR/scripts/build/termux_create_debian_subpackages.sh" + +# Create all subpackages. Run from termux_step_massage +# shellcheck source=scripts/build/termux_create_pacman_subpackages.sh +source "$TERMUX_SCRIPTDIR/scripts/build/termux_create_pacman_subpackages.sh" + +# Function to run various cleanup/fixes +# shellcheck source=scripts/build/termux_step_massage.sh +source "$TERMUX_SCRIPTDIR/scripts/build/termux_step_massage.sh" + +# Hook for packages after massage step +termux_step_post_massage() { + return +} + +# Hook function to create {pre,post}install, {pre,post}rm-scripts and similar +termux_step_create_debscripts() { + # Create debscripts for haskell packages. + if ls "${TERMUX_PKG_SRCDIR}"/*.cabal &>/dev/null && [ "${TERMUX_PKG_IS_HASKELL_LIB}" = true ]; then + cat <<-EOF >./postinst + #!${TERMUX_PREFIX}/bin/sh + sh ${TERMUX_PREFIX}/share/haskell/register/${TERMUX_PKG_NAME}.sh + EOF + + cat <<-EOF >./prerm + #!${TERMUX_PREFIX}/bin/sh + if [ "${TERMUX_PACKAGE_FORMAT}" = "pacman" ] || [ "\$1" = "remove" ] || [ "\$1" = "update" ]; then + sh ${TERMUX_PREFIX}/share/haskell/unregister/${TERMUX_PKG_NAME}.sh + fi + EOF + else + return 0 + fi +} + +# Convert Debian maintainer scripts into pacman-compatible installation hooks. +# This is used only when creating pacman packages. +# shellcheck source=scripts/build/termux_step_create_pacman_install_hook.sh +source "$TERMUX_SCRIPTDIR/scripts/build/termux_step_create_pacman_install_hook.sh" + +# Create the build deb file. Not to be overridden by package scripts. +# shellcheck source=scripts/build/termux_step_create_debian_package.sh +source "$TERMUX_SCRIPTDIR/scripts/build/termux_step_create_debian_package.sh" + +# Create the build .pkg.tar.xz file. Not to be overridden by package scripts. +# shellcheck source=scripts/build/termux_step_create_pacman_package.sh +source "$TERMUX_SCRIPTDIR/scripts/build/termux_step_create_pacman_package.sh" + +# Finish the build. Not to be overridden by package scripts. +# shellcheck source=scripts/build/termux_step_finish_build.sh +source "$TERMUX_SCRIPTDIR/scripts/build/termux_step_finish_build.sh" + +################################################################################ + +# shellcheck source=scripts/properties.sh +. "$TERMUX_SCRIPTDIR/scripts/properties.sh" + +if [ "$TERMUX_ON_DEVICE_BUILD" = "true" ]; then + # Setup TERMUX_APP_PACKAGE_MANAGER + source "$TERMUX_PREFIX/bin/termux-setup-package-manager" + + # For on device builds cross compiling is not supported. + # Target architecture must be same as for environment used currently. + case "$TERMUX_APP_PACKAGE_MANAGER" in + "apt") TERMUX_ARCH=$(dpkg --print-architecture);; + "pacman") TERMUX_ARCH=$(pacman-conf | grep Architecture | sed 's/Architecture = //g');; + esac + export TERMUX_ARCH +fi + +# Special hook to prevent use of "sudo" inside package build scripts. +# build-package.sh shouldn't perform any privileged operations. +sudo() { + termux_error_exit "Do not use 'sudo' inside build scripts. Build environment should be configured through ./scripts/setup-ubuntu.sh." +} + +_show_usage() { + echo "Usage: ./build-package.sh [options] PACKAGE_1 PACKAGE_2 ..." + echo + echo "Build a package by creating a .deb file in the debs/ folder." + echo + echo "Available options:" + [ "$TERMUX_ON_DEVICE_BUILD" = "false" ] && echo " -a The architecture to build for: aarch64(default), arm, i686, x86_64 or all." + 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." + [ "$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." + echo " -s Skip dependency check." + echo " -o Specify directory where to put built packages. Default: output/." + echo " --format Specify package output format (debian, pacman)." + exit 1 +} + +declare -a PACKAGE_LIST=() + +if [ "$#" -lt 1 ]; then _show_usage; fi +while (($# >= 1)); do + case "$1" in + --) shift 1; break;; + -h|--help) _show_usage;; + --format) + if [ $# -ge 2 ]; then + shift 1 + if [ -z "$1" ]; then + termux_error_exit "./build-package.sh: argument to '--format' should not be empty" + fi + TERMUX_PACKAGE_FORMAT="$1" + else + termux_error_exit "./build-package.sh: option '--format' requires an argument" + fi + ;; + -a) + if [ $# -ge 2 ]; then + shift 1 + if [ -z "$1" ]; then + termux_error_exit "Argument to '-a' should not be empty." + fi + if [ "$TERMUX_ON_DEVICE_BUILD" = "true" ]; then + termux_error_exit "./build-package.sh: option '-a' is not available for on-device builds" + else + export TERMUX_ARCH="$1" + fi + else + termux_error_exit "./build-package.sh: option '-a' requires an argument" + fi + ;; + -d) export TERMUX_DEBUG_BUILD=true;; + -D) TERMUX_IS_DISABLED=true;; + -f) 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" + else + export TERMUX_INSTALL_DEPS=true + fi + ;; + -I) export TERMUX_INSTALL_DEPS=true && export TERMUX_NO_CLEAN=true;; + -q) export TERMUX_QUIET_BUILD=true;; + -s) export TERMUX_SKIP_DEPCHECK=true;; + -o) + if [ $# -ge 2 ]; then + shift 1 + if [ -z "$1" ]; then + termux_error_exit "./build-package.sh: argument to '-o' should not be empty" + fi + TERMUX_OUTPUT_DIR=$(realpath -m "$1") + else + termux_error_exit "./build-package.sh: option '-o' requires an argument" + fi + ;; + -c) TERMUX_CONTINUE_BUILD=true;; + -*) termux_error_exit "./build-package.sh: illegal option '$1'";; + *) PACKAGE_LIST+=("$1");; + esac + shift 1 +done +unset -f _show_usage + +if [ -n "${TERMUX_PACKAGE_FORMAT-}" ]; then + case "${TERMUX_PACKAGE_FORMAT-}" in + debian|pacman) :;; + *) termux_error_exit "Unsupported package format \"${TERMUX_PACKAGE_FORMAT-}\". Only 'debian' and 'pacman' formats are supported";; + esac +fi + +if [ "${TERMUX_INSTALL_DEPS-false}" = "true" ]; then + # Setup PGP keys for verifying integrity of dependencies. + # Keys are obtained from our keyring package. + gpg --list-keys 2C7F29AE97891F6419A9E2CDB0076E490B71616B > /dev/null 2>&1 || { + gpg --import "$TERMUX_SCRIPTDIR/packages/termux-keyring/grimler.gpg" + gpg --no-tty --command-file <(echo -e "trust\n5\ny") --edit-key 2C7F29AE97891F6419A9E2CDB0076E490B71616B + } + gpg --list-keys CC72CF8BA7DBFA0182877D045A897D96E57CF20C > /dev/null 2>&1 || { + gpg --import "$TERMUX_SCRIPTDIR/packages/termux-keyring/termux-autobuilds.gpg" + gpg --no-tty --command-file <(echo -e "trust\n5\ny") --edit-key CC72CF8BA7DBFA0182877D045A897D96E57CF20C + } +fi + +for ((i=0; i<${#PACKAGE_LIST[@]}; i++)); do + # Following commands must be executed under lock to prevent running + # multiple instances of "./build-package.sh". + # + # To provide sane environment for each package, builds are done + # in subshell. + ( + if ! $TERMUX_BUILD_IGNORE_LOCK; then + flock -n 5 || termux_error_exit "Another build is already running within same environment." + fi + + # Handle 'all' arch: + if [ "$TERMUX_ON_DEVICE_BUILD" = "false" ] && [ -n "${TERMUX_ARCH+x}" ] && [ "${TERMUX_ARCH}" = 'all' ]; then + for arch in 'aarch64' 'arm' 'i686' 'x86_64'; do + env TERMUX_ARCH="$arch" TERMUX_BUILD_IGNORE_LOCK=true ./build-package.sh \ + ${TERMUX_FORCE_BUILD+-f} ${TERMUX_INSTALL_DEPS+-i} ${TERMUX_IS_DISABLED+-D} \ + ${TERMUX_DEBUG_BUILD+-d} ${TERMUX_OUTPUT_DIR+-o $TERMUX_OUTPUT_DIR} \ + --format ${TERMUX_PACKAGE_FORMAT:=debian} "${PACKAGE_LIST[i]}" + done + exit + fi + + # Check the package to build: + TERMUX_PKG_NAME=$(basename "${PACKAGE_LIST[i]}") + export TERMUX_PKG_BUILDER_DIR= + if [[ ${PACKAGE_LIST[i]} == *"/"* ]]; then + # Path to directory which may be outside this repo: + if [ ! -d "${PACKAGE_LIST[i]}" ]; then termux_error_exit "'${PACKAGE_LIST[i]}' seems to be a path but is not a directory"; fi + export TERMUX_PKG_BUILDER_DIR=$(realpath "${PACKAGE_LIST[i]}") + else + # Package name: + for package_directory in $TERMUX_PACKAGES_DIRECTORIES; do + if [ -d "${TERMUX_SCRIPTDIR}/${package_directory}/${TERMUX_PKG_NAME}" ]; then + export TERMUX_PKG_BUILDER_DIR=${TERMUX_SCRIPTDIR}/$package_directory/$TERMUX_PKG_NAME + break + elif [ -n "${TERMUX_IS_DISABLED=""}" ] && [ -d "${TERMUX_SCRIPTDIR}/disabled-packages/${TERMUX_PKG_NAME}"]; then + export TERMUX_PKG_BUILDER_DIR=$TERMUX_SCRIPTDIR/disabled-packages/$TERMUX_PKG_NAME + break + fi + done + if [ -z "${TERMUX_PKG_BUILDER_DIR}" ]; then + termux_error_exit "No package $TERMUX_PKG_NAME found in any of the enabled repositories. Are you trying to set up a custom repository?" + fi + fi + TERMUX_PKG_BUILDER_SCRIPT=$TERMUX_PKG_BUILDER_DIR/build.sh + if test ! -f "$TERMUX_PKG_BUILDER_SCRIPT"; then + termux_error_exit "No build.sh script at package dir $TERMUX_PKG_BUILDER_DIR!" + fi + + termux_step_setup_variables + termux_step_handle_buildarch + + if [ "$TERMUX_CONTINUE_BUILD" == "false" ]; then + termux_step_setup_build_folders + fi + + termux_step_start_build + + if [ "$TERMUX_CONTINUE_BUILD" == "false" ]; then + termux_step_get_dependencies + termux_step_override_config_scripts + fi + + termux_step_create_timestamp_file + + if [ "$TERMUX_CONTINUE_BUILD" == "false" ]; then + cd "$TERMUX_PKG_CACHEDIR" + termux_step_get_source + cd "$TERMUX_PKG_SRCDIR" + termux_step_post_get_source + termux_step_handle_hostbuild + fi + + termux_step_setup_toolchain + + if [ "$TERMUX_CONTINUE_BUILD" == "false" ]; then + termux_step_patch_package + termux_step_replace_guess_scripts + cd "$TERMUX_PKG_SRCDIR" + termux_step_pre_configure + fi + + # Even on continued build we might need to setup paths + # to tools so need to run part of configure step + cd "$TERMUX_PKG_BUILDDIR" + termux_step_configure + + if [ "$TERMUX_CONTINUE_BUILD" == "false" ]; then + cd "$TERMUX_PKG_BUILDDIR" + termux_step_post_configure + fi + cd "$TERMUX_PKG_BUILDDIR" + termux_step_make + cd "$TERMUX_PKG_BUILDDIR" + termux_step_make_install + cd "$TERMUX_PKG_BUILDDIR" + termux_step_post_make_install + termux_step_install_service_scripts + termux_step_install_license + cd "$TERMUX_PKG_MASSAGEDIR" + termux_step_extract_into_massagedir + termux_step_massage + cd "$TERMUX_PKG_MASSAGEDIR/$TERMUX_PREFIX" + termux_step_post_massage + cd "$TERMUX_PKG_MASSAGEDIR" + if [ "$TERMUX_PACKAGE_FORMAT" = "debian" ]; then + termux_step_create_debian_package + elif [ "$TERMUX_PACKAGE_FORMAT" = "pacman" ]; then + termux_step_create_pacman_package + else + termux_error_exit "Unknown packaging format '$TERMUX_PACKAGE_FORMAT'." + fi + termux_step_finish_build + ) 5< "$TERMUX_BUILD_LOCK_FILE" +done diff --git a/clean.sh b/clean.sh new file mode 100755 index 000000000..0a6047a06 --- /dev/null +++ b/clean.sh @@ -0,0 +1,47 @@ +#!/bin/sh +# clean.sh - clean everything. +set -e -u + +# Checking if script is running on Android with 2 different methods. +# Needed for safety to prevent execution of potentially dangerous +# operations such as 'rm -rf /data/*' on Android device. +if [ "$(uname -o)" = "Android" ] || [ -e "/system/bin/app_process" ]; then + TERMUX_ON_DEVICE_BUILD=true +else + TERMUX_ON_DEVICE_BUILD=false +fi + +if [ "$(id -u)" = "0" ] && $TERMUX_ON_DEVICE_BUILD; then + echo "On-device execution of this script as root is disabled." + exit 1 +fi + +# Read settings from .termuxrc if existing +test -f "$HOME/.termuxrc" && . "$HOME/.termuxrc" +: "${TERMUX_TOPDIR:="$HOME/.termux-build"}" +: "${TMPDIR:=/tmp}" +export TMPDIR + +# Lock file. Same as used in build-package.sh. +TERMUX_BUILD_LOCK_FILE="${TMPDIR}/.termux-build.lck" +if [ ! -e "$TERMUX_BUILD_LOCK_FILE" ]; then + touch "$TERMUX_BUILD_LOCK_FILE" +fi + +{ + if ! flock -n 5; then + echo "Not cleaning build directory since you have unfinished build running." + exit 1 + fi + + if [ -d "$TERMUX_TOPDIR" ]; then + chmod +w -R "$TERMUX_TOPDIR" || true + fi + + if $TERMUX_ON_DEVICE_BUILD; then + # For on-device build cleanup /data shouldn't be erased. + rm -Rf "$TERMUX_TOPDIR" + else + rm -Rf /data/* "$TERMUX_TOPDIR" + fi +} 5< "$TERMUX_BUILD_LOCK_FILE" diff --git a/ndk-patches/bits-struct_file.h.patch b/ndk-patches/bits-struct_file.h.patch new file mode 100644 index 000000000..7e5bf09b3 --- /dev/null +++ b/ndk-patches/bits-struct_file.h.patch @@ -0,0 +1,85 @@ +--- ./usr/include/bits/struct_file.h.orig 2019-06-10 09:40:35.872857650 +1000 ++++ ./usr/include/bits/struct_file.h 2019-06-10 09:55:10.890308649 +1000 +@@ -31,14 +31,79 @@ + #include + + __BEGIN_DECLS ++#if defined(__LP64__) ++struct __sbuf { ++ unsigned char* _base; ++ size_t _size; ++}; ++#else ++struct __sbuf { ++ unsigned char *_base; ++ int _size; ++}; ++#endif ++#if defined(__LP64__) ++typedef int64_t _struct_file_off_t; ++#else ++typedef __kernel_off_t _struct_file_off_t; ++#endif ++ + + /** The opaque structure implementing `FILE`. Do not make any assumptions about its content. */ + struct __sFILE { ++ unsigned char *_p; /* current position in (some) buffer */ ++ int _r; /* read space left for getc() */ ++ int _w; /* write space left for putc() */ + #if defined(__LP64__) +- char __private[152]; ++ int _flags; /* flags, below; this FILE is free if 0 */ ++ int _file; /* fileno, if Unix descriptor, else -1 */ + #else +- char __private[84]; ++ short _flags; /* flags, below; this FILE is free if 0 */ ++ short _file; /* fileno, if Unix descriptor, else -1 */ + #endif +-} __attribute__((aligned(sizeof(void*)))); ++ struct __sbuf _bf; /* the buffer (at least 1 byte, if !NULL) */ ++ int _lbfsize; /* 0 or -_bf._size, for inline putc */ ++ ++ /* operations */ ++ void *_cookie; /* cookie passed to io functions */ ++ int (*_close)(void *); ++ int (*_read)(void *, char *, int); ++ _struct_file_off_t (*_seek)(void *, _struct_file_off_t, int); ++ int (*_write)(void *, const char *, int); ++ ++ /* extension data, to avoid further ABI breakage */ ++ struct __sbuf _ext; ++ /* data for long sequences of ungetc() */ ++ unsigned char *_up; /* saved _p when _p is doing ungetc data */ ++ int _ur; /* saved _r when _r is counting ungetc data */ ++ ++ /* tricks to meet minimum requirements even when malloc() fails */ ++ unsigned char _ubuf[3]; /* guarantee an ungetc() buffer */ ++ unsigned char _nbuf[1]; /* guarantee a getc() buffer */ ++ ++ /* separate buffer for fgetln() when line crosses buffer boundary */ ++ struct __sbuf _lb; /* buffer for fgetln() */ ++ ++ /* Unix stdio files get aligned to block boundaries on fseek() */ ++ int _blksize; /* stat.st_blksize (may be != _bf._size) */ ++ _struct_file_off_t _offset; /* current lseek offset */ ++}; ++#define __SLBF 0x0001 /* line buffered */ ++#define __SNBF 0x0002 /* unbuffered */ ++#define __SRD 0x0004 /* OK to read */ ++#define __SWR 0x0008 /* OK to write */ ++ /* RD and WR are never simultaneously asserted */ ++#define __SRW 0x0010 /* open for reading & writing */ ++#define __SEOF 0x0020 /* found EOF */ ++#define __SERR 0x0040 /* found error */ ++#define __SMBF 0x0080 /* _buf is from malloc */ ++#define __SAPP 0x0100 /* fdopen()ed in append mode */ ++#define __SSTR 0x0200 /* this is an sprintf/snprintf string */ ++#define __SOPT 0x0400 /* do fseek() optimization */ ++#define __SNPT 0x0800 /* do not do fseek() optimization */ ++#define __SOFF 0x1000 /* set iff _offset is in fact correct */ ++#define __SMOD 0x2000 /* true => fgetln modified _p text */ ++#define __SALC 0x4000 /* allocate string space dynamically */ ++#define __SIGN 0x8000 /* ignore this file in _fwalk */ + + __END_DECLS diff --git a/ndk-patches/dirent.h.patch b/ndk-patches/dirent.h.patch new file mode 100644 index 000000000..5865a9487 --- /dev/null +++ b/ndk-patches/dirent.h.patch @@ -0,0 +1,12 @@ +--- ./usr/include/dirent.h.orig ++++ ./usr/include/dirent.h +@@ -57,6 +57,9 @@ + #define DT_SOCK 12 + #define DT_WHT 14 + ++#define IFTODT(x) ((x)>>12 & 0xF) ++#define DTTOIF(x) ((x)<<12) ++ + #if defined(__LP64__) + #define __DIRENT64_INO_T ino_t + #else diff --git a/ndk-patches/grp.h.patch b/ndk-patches/grp.h.patch new file mode 100644 index 000000000..5a47373af --- /dev/null +++ b/ndk-patches/grp.h.patch @@ -0,0 +1,27 @@ +diff -u -r /home/fornwall/lib/android-ndk/sysroot/usr/include/grp.h ./usr/include/grp.h +--- /home/fornwall/lib/android-ndk/sysroot/usr/include/grp.h 2017-11-09 09:57:12.000000000 +0100 ++++ ./usr/include/grp.h 2017-11-15 11:43:43.065533963 +0100 +@@ -52,18 +52,11 @@ + + /* Note: Android has thousands and thousands of ids to iterate through. */ + +-#if __ANDROID_API__ >= 26 +-struct group* getgrent(void) __INTRODUCED_IN(26); +- +-void setgrent(void) __INTRODUCED_IN(26); +-void endgrent(void) __INTRODUCED_IN(26); +-#endif /* __ANDROID_API__ >= 26 */ +- +- +-#if __ANDROID_API__ >= 24 +-int getgrgid_r(gid_t __gid, struct group* __group, char* __buf, size_t __n, struct group** __result) __INTRODUCED_IN(24); +-int getgrnam_r(const char* __name, struct group* __group, char* __buf, size_t __n, struct group** __result) __INTRODUCED_IN(24); +-#endif /* __ANDROID_API__ >= 24 */ ++static struct group* getgrent(void) { return 0; } ++static void setgrent(void) {} ++static void endgrent(void) {} ++static int getgrgid_r(gid_t gid, struct group * grp, char * buf, size_t buflen, struct group ** result) { *result = 0; return 0; } ++static int getgrnam_r(const char * name, struct group * grp, char * buf, size_t buflen, struct group ** result) { *result = 0; return 0; } + + int getgrouplist(const char* __user, gid_t __group, gid_t* __groups, int* __group_count); + int initgroups(const char* __user, gid_t __group); diff --git a/ndk-patches/langinfo.h b/ndk-patches/langinfo.h new file mode 100644 index 000000000..db996d16b --- /dev/null +++ b/ndk-patches/langinfo.h @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * Copyright (C) 2016 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 + * COPYRIGHT OWNER OR CONTRIBUTORS 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. + */ +#ifndef _LANGINFO_H +#define _LANGINFO_H + +// __LP64__ + +#include +#include +#include + +#define _NL_ITEM(category,index) (((category) << 10) | (index)) + +#define _NL_ITEM_CATEGORY(nl) ((nl) >> 10) +#define _NL_ITEM_INDEX(nl) ((nl) & 0x3ff) + +#define CODESET 1 +#define D_T_FMT 2 +#define D_FMT 3 +#define T_FMT 4 +#define T_FMT_AMPM 5 +#define AM_STR 6 +#define PM_STR 7 +#define DAY_1 8 +#define DAY_2 9 +#define DAY_3 10 +#define DAY_4 11 +#define DAY_5 12 +#define DAY_6 13 +#define DAY_7 14 +#define ABDAY_1 15 +#define ABDAY_2 16 +#define ABDAY_3 17 +#define ABDAY_4 18 +#define ABDAY_5 19 +#define ABDAY_6 20 +#define ABDAY_7 21 +#define MON_1 22 +#define MON_2 23 +#define MON_3 24 +#define MON_4 25 +#define MON_5 26 +#define MON_6 27 +#define MON_7 28 +#define MON_8 29 +#define MON_9 30 +#define MON_10 31 +#define MON_11 32 +#define MON_12 33 +#define ABMON_1 34 +#define ABMON_2 35 +#define ABMON_3 36 +#define ABMON_4 37 +#define ABMON_5 38 +#define ABMON_6 39 +#define ABMON_7 40 +#define ABMON_8 41 +#define ABMON_9 42 +#define ABMON_10 43 +#define ABMON_11 44 +#define ABMON_12 45 +#define ERA 46 +#define ERA_D_FMT 47 +#define ERA_D_T_FMT 48 +#define ERA_T_FMT 49 +#define ALT_DIGITS 50 +#define RADIXCHAR 51 +#define THOUSEP 52 +#define YESEXPR 53 +#define NOEXPR 54 +#define CRNCYSTR 55 +#define INT_CURRENCY_SYMBOL 55 + +#ifdef __cplusplus +extern "C" { +#endif + +static char *nl_langinfo_l(nl_item item, locale_t loc) +{ + static const char c_time[] = + "Sun\0" "Mon\0" "Tue\0" "Wed\0" "Thu\0" "Fri\0" "Sat\0" + "Sunday\0" "Monday\0" "Tuesday\0" "Wednesday\0" + "Thursday\0" "Friday\0" "Saturday\0" + "Jan\0" "Feb\0" "Mar\0" "Apr\0" "May\0" "Jun\0" + "Jul\0" "Aug\0" "Sep\0" "Oct\0" "Nov\0" "Dec\0" + "January\0" "February\0" "March\0" "April\0" + "May\0" "June\0" "July\0" "August\0" + "September\0" "October\0" "November\0" "December\0" + "AM\0" "PM\0" + "%a %b %e %T %Y\0" + "%m/%d/%y\0" + "%H:%M:%S\0" + "%I:%M:%S %p\0" + "\0" + "%m/%d/%y\0" + "0123456789" + "%a %b %e %T %Y\0" + "%H:%M:%S"; + static const char c_messages[] = "^[yY]\0" "^[nN]"; + static const char c_numeric[] = ".\0" ""; + static const char c_zero[] = "UTF-8\0" "UTF-8\0" + "%F %T %z\0" "%F\0" "%T\0" "%I:%M:%S %p\0" + "AM\0" "PM\0" + "Sunday\0" "Monday\0" "Tuesday\0" "Wednesday\0" + "Thursday\0" "Friday\0" "Saturday\0" + "Sun\0" "Mon\0" "Tue\0" "Wed\0" "Thu\0" "Fri\0" "Sat\0" + "January\0" "February\0" "March\0" + "April\0" "May\0" "June\0" + "July\0" "August\0" "September\0" + "October\0" "November\0" "December\0" + "Jan\0" "Feb\0" "Mar\0" "Apr\0" "May\0" "Jun\0" + "Jul\0" "Aug\0" "Sep\0" "Oct\0" "Nov\0" "Dec\0" + "\0" "\0" "\0" "\0" "\0" ".\0" "\0" + "^[yY]\0" "^[nN]\0" "\0"; + + int cat = item >> 16; + int idx = item & 65535; + const char *str; + + if (item == CODESET) return "UTF-8"; + + switch (cat) { + case 0: + if (idx > 55) return NULL; + str = c_zero; + break; + case LC_NUMERIC: + if (idx > 1) return NULL; + str = c_numeric; + break; + case LC_TIME: + if (idx > 0x31) return NULL; + str = c_time; + break; + case LC_MONETARY: + if (idx > 0) return NULL; + str = ""; + break; + case LC_MESSAGES: + if (idx > 1) return NULL; + str = c_messages; + break; + default: + return NULL; + } + + for (; idx; idx--, str++) for (; *str; str++); + return (char *)str; +} + +static char *nl_langinfo(nl_item item) +{ + return nl_langinfo_l(item, 0); +} + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* _LANGINFO_H */ + diff --git a/ndk-patches/langinfo.h.patch b/ndk-patches/langinfo.h.patch new file mode 100644 index 000000000..14d8a1b9c --- /dev/null +++ b/ndk-patches/langinfo.h.patch @@ -0,0 +1,108 @@ +diff -N -a -u -r /home/fornwall/lib/android-ndk/sysroot/usr/include/langinfo.h ./usr/include/langinfo.h +--- /home/fornwall/lib/android-ndk/sysroot/usr/include/langinfo.h 2017-11-09 09:57:12.000000000 +0100 ++++ ./usr/include/langinfo.h 1970-01-01 01:00:00.000000000 +0100 +@@ -1,104 +0,0 @@ +-/* +- * Copyright (C) 2016 The Android Open Source Project +- * All rights reserved. +- * +- * Redistribution and use in source and binary forms, with or without +- * modification, are permitted provided that the following conditions +- * are met: +- * * Redistributions of source code must retain the above copyright +- * notice, this list of conditions and the following disclaimer. +- * * Redistributions in binary form must reproduce the above copyright +- * notice, this list of conditions and the following disclaimer in +- * the documentation and/or other materials provided with the +- * distribution. +- * +- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +- * "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 +- * COPYRIGHT OWNER OR CONTRIBUTORS 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. +- */ +- +-#ifndef _LANGINFO_H_ +-#define _LANGINFO_H_ +- +-#include +- +-#include +-#include +- +-__BEGIN_DECLS +- +-#define CODESET 1 +-#define D_T_FMT 2 +-#define D_FMT 3 +-#define T_FMT 4 +-#define T_FMT_AMPM 5 +-#define AM_STR 6 +-#define PM_STR 7 +-#define DAY_1 8 +-#define DAY_2 9 +-#define DAY_3 10 +-#define DAY_4 11 +-#define DAY_5 12 +-#define DAY_6 13 +-#define DAY_7 14 +-#define ABDAY_1 15 +-#define ABDAY_2 16 +-#define ABDAY_3 17 +-#define ABDAY_4 18 +-#define ABDAY_5 19 +-#define ABDAY_6 20 +-#define ABDAY_7 21 +-#define MON_1 22 +-#define MON_2 23 +-#define MON_3 24 +-#define MON_4 25 +-#define MON_5 26 +-#define MON_6 27 +-#define MON_7 28 +-#define MON_8 29 +-#define MON_9 30 +-#define MON_10 31 +-#define MON_11 32 +-#define MON_12 33 +-#define ABMON_1 34 +-#define ABMON_2 35 +-#define ABMON_3 36 +-#define ABMON_4 37 +-#define ABMON_5 38 +-#define ABMON_6 39 +-#define ABMON_7 40 +-#define ABMON_8 41 +-#define ABMON_9 42 +-#define ABMON_10 43 +-#define ABMON_11 44 +-#define ABMON_12 45 +-#define ERA 46 +-#define ERA_D_FMT 47 +-#define ERA_D_T_FMT 48 +-#define ERA_T_FMT 49 +-#define ALT_DIGITS 50 +-#define RADIXCHAR 51 +-#define THOUSEP 52 +-#define YESEXPR 53 +-#define NOEXPR 54 +-#define CRNCYSTR 55 +- +- +-#if __ANDROID_API__ >= 26 +-char* nl_langinfo(nl_item __item) __INTRODUCED_IN(26); +-char* nl_langinfo_l(nl_item __item, locale_t __l) __INTRODUCED_IN(26); +-#endif /* __ANDROID_API__ >= 26 */ +- +- +-__END_DECLS +- +-#endif diff --git a/ndk-patches/libintl.h b/ndk-patches/libintl.h new file mode 100644 index 000000000..16eb25225 --- /dev/null +++ b/ndk-patches/libintl.h @@ -0,0 +1,53 @@ +#ifndef _LIBINTL_H +#define _LIBINTL_H + +#include +#include + +static __inline__ char* gettext(const char* msgid) +{ return (char*) msgid; } + +static __inline__ char* dgettext(const char* domainname, const char* msgid) +{ return (char*) msgid; } + +static __inline__ char* dcgettext(const char* domainname, const char* msgid, int category) +{ return (char*) msgid; } + +static __inline__ char* ngettext(const char* msgid1, const char* msgid2, unsigned long int n) +{ return (char *) ((n == 1) ? msgid1 : msgid2); } + +static __inline__ char* dngettext(const char* domainname, const char* msgid1, const char* msgid2, unsigned long int n) +{ return (char *) ((n == 1) ? msgid1 : msgid2); } + +static __inline__ char* dcngettext(const char* domainname, const char* msgid1, const char* msgid2, unsigned long int n, int category) +{ return (char *) ((n == 1) ? msgid1 : msgid2); } + +static __inline__ char* textdomain(const char* domainname) +{ + static const char default_str[] = "messages"; + if (domainname && *domainname && strcmp(domainname, default_str)) { + errno = EINVAL; + return NULL; + } + return (char*) default_str; +} + +static __inline__ char* bindtextdomain(const char* domainname, const char* dirname) +{ + static const char dir[] = "/"; + if (!domainname || !*domainname || (dirname && ((dirname[0] != '/') || dirname[1]))) { + errno = EINVAL; + return NULL; + } + return (char*) dir; +} + +static __inline__ char* bind_textdomain_codeset(const char* domainname, const char* codeset) +{ + if (!domainname || !*domainname || (codeset && strcasecmp(codeset, "UTF-8"))) { + errno = EINVAL; + } + return NULL; +} + +#endif diff --git a/ndk-patches/linux-fcntl.h.patch b/ndk-patches/linux-fcntl.h.patch new file mode 100644 index 000000000..727c39832 --- /dev/null +++ b/ndk-patches/linux-fcntl.h.patch @@ -0,0 +1,11 @@ +--- ./usr/include/linux/fcntl.h ++++ ./usr/include/linux/fcntl.h +@@ -54,7 +54,7 @@ + #define DN_MULTISHOT 0x80000000 + #define AT_FDCWD - 100 + #define AT_SYMLINK_NOFOLLOW 0x100 +-#define AT_EACCESS 0x200 ++#define AT_EACCESS 0 + #define AT_REMOVEDIR 0x200 + #define AT_SYMLINK_FOLLOW 0x400 + #define AT_NO_AUTOMOUNT 0x800 diff --git a/ndk-patches/paths.h.patch b/ndk-patches/paths.h.patch new file mode 100644 index 000000000..b5c2684da --- /dev/null +++ b/ndk-patches/paths.h.patch @@ -0,0 +1,29 @@ +--- ./usr/include/paths.h.orig 2021-08-16 11:55:04.492150066 +0200 ++++ ./usr/include/paths.h 2021-08-16 11:55:42.498804733 +0200 +@@ -40,14 +40,14 @@ + + #ifndef _PATH_BSHELL + /** Path to the default system shell. Historically the 'B' was to specify the Bourne shell. */ +-#define _PATH_BSHELL "/system/bin/sh" ++#define _PATH_BSHELL "@TERMUX_PREFIX@/bin/sh" + #endif + + /** Path to the system console. */ + #define _PATH_CONSOLE "/dev/console" + + /** Default shell search path. */ +-#define _PATH_DEFPATH "/product/bin:/apex/com.android.runtime/bin:/apex/com.android.art/bin:/system_ext/bin:/system/bin:/system/xbin:/odm/bin:/vendor/bin:/vendor/xbin" ++#define _PATH_DEFPATH "@TERMUX_PREFIX@/bin" + + /** Path to the directory containing device files. */ + #define _PATH_DEV "/dev/" +@@ -63,3 +63,9 @@ + + /** Path to the calling process' tty. */ + #define _PATH_TTY "/dev/tty" ++ ++#define _PATH_STDPATH _PATH_DEFPATH ++#define _PATH_TMP "@TERMUX_PREFIX@/tmp/" ++#define _PATH_VARDB "@TERMUX_PREFIX@/var/db/" ++#define _PATH_VARRUN "@TERMUX_PREFIX@/var/run/" ++#define _PATH_VARTMP "@TERMUX_PREFIX@/var/tmp/" diff --git a/ndk-patches/pwd.h.patch b/ndk-patches/pwd.h.patch new file mode 100644 index 000000000..c9d9f7ff8 --- /dev/null +++ b/ndk-patches/pwd.h.patch @@ -0,0 +1,63 @@ +--- ./usr/include/pwd.h.orig 2020-01-17 23:55:20.029173926 +0000 ++++ ./usr/include/pwd.h 2020-01-18 00:04:18.758398251 +0000 +@@ -89,13 +89,59 @@ + struct passwd* getpwent(void) __INTRODUCED_IN(26); + + void setpwent(void) __INTRODUCED_IN(26); +-void endpwent(void) __INTRODUCED_IN(26); + #endif /* __ANDROID_API__ >= 26 */ + + + int getpwnam_r(const char* __name, struct passwd* __pwd, char* __buf, size_t __n, struct passwd** __result); + int getpwuid_r(uid_t __uid, struct passwd* __pwd, char* __buf, size_t __n, struct passwd** __result); + ++int access(const char* __path, int __mode); ++ ++static void android_setup_pwd(struct passwd* pw) { ++ char const* result = "@TERMUX_PREFIX@/bin/login"; ++ if (result == NULL || access(result, /*X_OK*/1) == -1) { ++ pw->pw_shell = "@TERMUX_PREFIX@/bin/bash"; ++ } else { ++ pw->pw_shell = (char*) result; ++ } ++ pw->pw_dir = "@TERMUX_HOME@"; ++ pw->pw_passwd = "*"; ++#ifdef __LP64__ ++ pw->pw_gecos = ""; /* Avoid NULL field. */ ++#endif ++} ++ ++static struct passwd* android_polyfill_getpwuid(uid_t t) { ++ struct passwd* pw = getpwuid(t); ++ if (pw == NULL) return NULL; ++ android_setup_pwd(pw); ++ return pw; ++} ++ ++static struct passwd* android_polyfill_getpwnam(const char* name) { ++ struct passwd* pw = getpwnam(name); ++ if (pw == NULL) return NULL; ++ android_setup_pwd(pw); ++ return pw; ++} ++ ++static int android_polyfill_getpwuid_r(uid_t uid, ++ struct passwd *pwd, ++ char *buffer, ++ size_t bufsize, ++ struct passwd **result) { ++ int ret = getpwuid_r(uid, pwd, buffer, bufsize, result); ++ if (ret != 0) return ret; ++ android_setup_pwd(pwd); ++ return 0; ++} ++ ++#define getpwnam android_polyfill_getpwnam ++#define getpwuid android_polyfill_getpwuid ++#define getpwuid_r android_polyfill_getpwuid_r ++static void endpwent(void) { /* Do nothing. */ } ++ ++ + __END_DECLS + + #endif diff --git a/ndk-patches/redefine-TCSAFLUSH.patch b/ndk-patches/redefine-TCSAFLUSH.patch new file mode 100644 index 000000000..c063a8958 --- /dev/null +++ b/ndk-patches/redefine-TCSAFLUSH.patch @@ -0,0 +1,21 @@ +diff -u -r /home/builder/lib/android-ndk/sysroot/usr/include/asm-generic/termbits.h ./usr/include/asm-generic/termbits.h +--- /home/builder/lib/android-ndk/sysroot/usr/include/asm-generic/termbits.h 2018-09-10 17:37:50.000000000 +0000 ++++ ./usr/include/asm-generic/termbits.h 2019-01-16 04:54:01.117253378 +0000 +@@ -190,5 +190,6 @@ + #define TCIOFLUSH 2 + #define TCSANOW 0 + #define TCSADRAIN 1 +-#define TCSAFLUSH 2 ++/* TCSAFLUSH is patched to be TCSANOW in Termux to work around Android SELinux rule */ ++#define TCSAFLUSH 0 + #endif +--- ./usr/include/bits/termios_inlines.h.orig 2021-08-16 17:05:16.001067630 +0200 ++++ ./usr/include/bits/termios_inlines.h 2021-08-16 17:05:05.851074187 +0200 +@@ -117,7 +117,6 @@ + switch (optional_actions) { + case TCSANOW: cmd = TCSETS; break; + case TCSADRAIN: cmd = TCSETSW; break; +- case TCSAFLUSH: cmd = TCSETSF; break; + default: errno = EINVAL; return -1; + } + return ioctl(fd, cmd, s); diff --git a/ndk-patches/semaphore.h.patch b/ndk-patches/semaphore.h.patch new file mode 100644 index 000000000..095548817 --- /dev/null +++ b/ndk-patches/semaphore.h.patch @@ -0,0 +1,18 @@ +--- ./usr/include/semaphore.h.orig ++++ ./usr/include/semaphore.h +@@ -71,9 +71,14 @@ + int sem_trywait(sem_t* __sem); + int sem_wait(sem_t* __sem); + +-/* These aren't actually implemented. */ ++#undef sem_open ++#define sem_open libandroid_sem_open + sem_t* sem_open(const char* __name, int _flags, ...); ++#undef sem_close ++#define sem_close libandroid_sem_close + int sem_close(sem_t* __sem); ++#undef sem_unlink ++#define sem_unlink libandroid_sem_unlink + int sem_unlink(const char* __name); + + __END_DECLS diff --git a/ndk-patches/stdio.h.patch b/ndk-patches/stdio.h.patch new file mode 100644 index 000000000..ee509b8d8 --- /dev/null +++ b/ndk-patches/stdio.h.patch @@ -0,0 +1,80 @@ +--- ./usr/include/stdio.h.orig 2021-08-16 11:48:44.308954400 +0200 ++++ ./usr/include/stdio.h 2021-08-16 11:50:00.438924014 +0200 +@@ -44,6 +44,9 @@ + #include + #include + ++#include /* For strcpy(3) used by ctermid() */ ++#include /* For O_RDWR and other O_* constants */ ++ + #include + + #if __ANDROID_API__ < 24 +@@ -165,7 +166,7 @@ + __printflike(2, 0) __warnattr_strict("vsprintf is often misused; please use vsnprintf"); + char* tmpnam(char* __s) + __warnattr("tmpnam is unsafe, use mkstemp or tmpfile instead"); +-#define P_tmpdir "/tmp/" /* deprecated */ ++#define P_tmpdir "@TERMUX_PREFIX@/tmp/" /* deprecated */ + char* tempnam(const char* __dir, const char* __prefix) + __warnattr("tempnam is unsafe, use mkstemp or tmpfile instead"); + +@@ -289,8 +290,6 @@ + FILE* freopen64(const char* __path, const char* __mode, FILE* __fp) __INTRODUCED_IN(24); + #endif /* __ANDROID_API__ >= 24 */ + +-FILE* tmpfile(void); +- + #if __ANDROID_API__ >= 24 + FILE* tmpfile64(void) __INTRODUCED_IN(24); + #endif /* __ANDROID_API__ >= 24 */ +@@ -304,10 +303,15 @@ + + #define L_ctermid 1024 /* size for ctermid() */ + +-#if __ANDROID_API__ >= 26 +-char* ctermid(char* __buf) __INTRODUCED_IN(26); +-#endif /* __ANDROID_API__ >= 26 */ ++/* Needed by gnulibs freading(). */ ++#define __sferror(p) (((p)->_flags & __SERR) != 0) + ++/* Used by perl, fish, and others. */ ++static __inline__ char* ctermid(char* s) { ++ if (s == 0) return (char*) "/dev/tty"; ++ strcpy(s, "/dev/tty"); ++ return s; ++} + + FILE* fdopen(int __fd, const char* __mode); + int fileno(FILE* __fp); +@@ -376,6 +380,30 @@ + #include + #endif + ++int open(const char*, int, ...); ++extern pid_t getpid(); ++extern int unlink(const char*); ++void free(void* p); ++uint32_t arc4random(void); ++static __inline__ FILE* tmpfile() { ++ int p = getpid(); ++ char* path; ++ int i; ++ for (i = 0; i < 100; i++) { ++ unsigned int r = arc4random(); ++ if (asprintf(&path, "@TERMUX_PREFIX@/tmp/tmpfile.%d-%u", p, r) == -1) return NULL; ++ int fd = open(path, O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE, 0600); ++ if (fd >= 0) { ++ FILE* result = fdopen(fd, "w+"); ++ unlink(path); ++ free(path); ++ return result; ++ } ++ free(path); ++ } ++ return NULL; ++} ++ + __END_DECLS + + #endif diff --git a/ndk-patches/stdlib.h.patch b/ndk-patches/stdlib.h.patch new file mode 100644 index 000000000..bb16db856 --- /dev/null +++ b/ndk-patches/stdlib.h.patch @@ -0,0 +1,20 @@ +--- ./usr/include/stdlib.h.orig 2021-08-16 11:50:47.432239182 +0200 ++++ ./usr/include/stdlib.h 2021-08-16 11:51:31.102222894 +0200 +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -224,8 +225,7 @@ + size_t wcstombs(char* __dst, const wchar_t* __src, size_t __n); + + #if __ANDROID_API__ >= 21 +-size_t __ctype_get_mb_cur_max(void) __INTRODUCED_IN(21); +-#define MB_CUR_MAX __ctype_get_mb_cur_max() ++#define MB_CUR_MAX 4 + #else + /* + * Pre-L we didn't have any locale support and so we were always the POSIX diff --git a/ndk-patches/sys-cdefs.h.patch b/ndk-patches/sys-cdefs.h.patch new file mode 100644 index 000000000..35508ca44 --- /dev/null +++ b/ndk-patches/sys-cdefs.h.patch @@ -0,0 +1,9 @@ +--- ./usr/include/sys/cdefs.h.orig 2021-08-16 11:52:08.128876161 +0200 ++++ ./usr/include/sys/cdefs.h 2021-08-16 11:52:08.555542676 +0200 +@@ -372,3 +372,6 @@ + #if __has_include() + #include + #endif ++#define __TERMUX__ 1 ++#define __TERMUX_PREFIX__ "@TERMUX_PREFIX@" ++ diff --git a/ndk-patches/syslog.patch b/ndk-patches/syslog.patch new file mode 100644 index 000000000..f29784aed --- /dev/null +++ b/ndk-patches/syslog.patch @@ -0,0 +1,26 @@ +diff -uNr sysroot.orig/usr/include/syslog.h sysroot/usr/include/syslog.h +--- sysroot.orig/usr/include/syslog.h 2019-02-12 16:12:24.000000000 +0000 ++++ sysroot/usr/include/syslog.h 2019-03-20 13:19:44.315965728 +0000 +@@ -158,4 +158,22 @@ + */ + void vsyslog(int __priority, const char* __fmt, va_list __args) __printflike(2, 0); + ++static __inline__ void android_polyfill_syslog_r(int syslog_priority, void* d, const char* format, ...) ++{ ++ (void) d; ++ va_list myargs; ++ va_start(myargs, format); ++ vsyslog(syslog_priority, format, myargs); ++ va_end(myargs); ++} ++ ++static __inline__ void android_polyfill_vsyslog_r(int syslog_priority, void* d, const char* fmt, va_list ap) ++{ ++ (void) d; ++ vsyslog(syslog_priority, fmt, ap); ++} ++ ++#define syslog_r android_polyfill_syslog_r ++#define vsyslog_r android_polyfill_vsyslog_r ++ + __END_DECLS diff --git a/ndk-patches/unistd.h.patch b/ndk-patches/unistd.h.patch new file mode 100644 index 000000000..37ea0a2fe --- /dev/null +++ b/ndk-patches/unistd.h.patch @@ -0,0 +1,77 @@ +--- ./usr/include/unistd.h.orig 2021-08-16 11:52:08.095542840 +0200 ++++ ./usr/include/unistd.h 2021-08-16 11:52:08.565542673 +0200 +@@ -375,6 +375,74 @@ + #undef _UNISTD_H_ + #endif + ++#if !defined GETPASS_H && !defined getpass && !defined HAVE_GETPASS && !defined HAS_GETPASS && !defined NO_INLINE_GETPASS ++#define GETPASS_H 1 ++#define HAVE_GETPASS 1 ++#define HAS_GETPASS 1 ++#define PASSWORDLEN 512 ++ ++static __inline__ char* getpass(const char* prompt) { ++ // termios struct as in asm-generic/termbits.h ++ struct _termios { ++ unsigned int c_iflag; /* input mode flags */ ++ unsigned int c_oflag; /* output mode flags */ ++ unsigned int c_cflag; /* control mode flags */ ++ unsigned int c_lflag; /* local mode flags */ ++ unsigned char c_line; /* line discipline */ ++ unsigned char c_cc[19/* NCCS */]; /* control characters */ ++ }; ++ ++ struct _termios term_old, term_new; ++ static char password[513] = { 0 }; /* 512 1-byte charactes and '0' */ ++ int len = 0, tty_changed = 0; ++ ++ // print prompt ++ while (*prompt) { ++ write(1, prompt, 1); ++ prompt++; ++ } ++ ++ // try to disable echoing on terminal ++ if (ioctl(0, 0x5401 /* TCGETS */, &term_old) == 0) { ++ term_new = term_old; ++ term_new.c_lflag &= ~0000010;/* ~ECHO */ ++ ++ if (ioctl(0, 0x5402+0 /* TCSETS+TCSANOW */, &term_new) == 0) { ++ tty_changed = 1; ++ } else { ++ tty_changed = 0; ++ } ++ } ++ ++ // read password ++ char chr; ++ while (read(0, &chr, sizeof(char)) > 0) { ++ if (chr == '\r' || chr == '\n' || chr == 0) { ++ break; ++ } ++ ++ if (len == sizeof(password)-1) { ++ // we should consume all entered characters even ++ // if maximal input length reached ++ continue; ++ } else { ++ password[len++] = chr; ++ } ++ } ++ password[len] = 0; ++ ++ // restore terminal to previous state if needed ++ if (tty_changed) { ++ ioctl(0, 0x5402+0 /* TCSETS+TCSANOW */, &term_old); ++ } ++ ++ // force new line ++ write(1, "\n", 1); ++ ++ return password; ++} ++#endif ++ + __END_DECLS + + #include diff --git a/ndk-patches/utmp.h.patch b/ndk-patches/utmp.h.patch new file mode 100644 index 000000000..51932dd25 --- /dev/null +++ b/ndk-patches/utmp.h.patch @@ -0,0 +1,15 @@ +--- ./usr/include/utmp.h.orig 2021-08-16 11:52:08.095542840 +0200 ++++ ./usr/include/utmp.h 2021-08-16 11:52:08.565542673 +0200 +@@ -37,9 +37,9 @@ + #include + #include + +-#define _PATH_UTMP "/var/run/utmp" +-#define _PATH_WTMP "/var/log/wtmp" +-#define _PATH_LASTLOG "/var/log/lastlog" ++#define _PATH_UTMP "@TERMUX_PREFIX@/var/run/utmp" ++#define _PATH_WTMP "@TERMUX_PREFIX@/var/log/wtmp" ++#define _PATH_LASTLOG "@TERMUX_PREFIX@/var/log/lastlog" + + #ifdef __LP64__ + #define UT_NAMESIZE 32 diff --git a/sample/build.sh b/sample/build.sh new file mode 100644 index 000000000..5d616ee34 --- /dev/null +++ b/sample/build.sh @@ -0,0 +1,13 @@ +# Skeleton build.sh script for new package. +# For reference about available fields, check the Termux Developer's Wiki page: +# https://github.com/termux/termux-packages/wiki/Creating-new-package + +TERMUX_PKG_HOMEPAGE= +TERMUX_PKG_DESCRIPTION="" +TERMUX_PKG_LICENSE="" +TERMUX_PKG_MAINTAINER="@termux" +TERMUX_PKG_VERSION= +TERMUX_PKG_SRCURL= +TERMUX_PKG_SHA256= +#TERMUX_PKG_DEPENDS="" +#TERMUX_PKG_BUILD_IN_SRC=true diff --git a/sample/sample-sub.subpackage.sh b/sample/sample-sub.subpackage.sh new file mode 100644 index 000000000..11395dffa --- /dev/null +++ b/sample/sample-sub.subpackage.sh @@ -0,0 +1,8 @@ +# Skeleton *.subpackage.sh script for new package. +# Delete this file if package shouldn't be splitted, otherwise rename and fill +# necessary fields. +# More information available on the Termux Developer's Wiki page: +# https://github.com/termux/termux-packages/wiki/Creating-new-package#writing-a-subpackage-script + +TERMUX_SUBPKG_DESCRIPTION="" +TERMUX_SUBPKG_INCLUDE="" diff --git a/scripts/Dockerfile b/scripts/Dockerfile new file mode 100644 index 000000000..d8d74f824 --- /dev/null +++ b/scripts/Dockerfile @@ -0,0 +1,35 @@ +# Build with: +# docker build -t termux/package-builder . +# Push to docker hub with: +# docker push termux/package-builder +# This is done after changing this file or any of the +# scripts/setup-{ubuntu,android-sdk}.sh setup scripts. +FROM ubuntu:21.10 + +# Fix locale to avoid warnings: +ENV LANG en_US.UTF-8 + +# Needed for setup: +COPY ./setup-ubuntu.sh ./setup-android-sdk.sh ./properties.sh /tmp/ +RUN mkdir /tmp/build +COPY ./build/termux_download.sh /tmp/build/ + +# Setup needed packages and the Android SDK and NDK: +RUN apt-get update && \ + apt-get -yq upgrade && \ + apt-get install -yq sudo lsb-release software-properties-common && \ + adduser --disabled-password --shell /bin/bash --gecos "" builder && \ + echo "builder ALL=(root) NOPASSWD:ALL" > /etc/sudoers.d/builder && \ + chmod 0440 /etc/sudoers.d/builder && \ + su - builder -c /tmp/setup-ubuntu.sh && \ + su - builder -c /tmp/setup-android-sdk.sh && \ + # Removed unused parts to make a smaller Docker image: + apt-get remove -yq --autoremove lsb-release software-properties-common && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +# Switch User +USER builder:builder + +# We expect this to be mounted with '-v $PWD:/home/builder/termux-packages': +WORKDIR /home/builder/termux-packages diff --git a/scripts/Vagrantfile b/scripts/Vagrantfile new file mode 100644 index 000000000..8d173c7c8 --- /dev/null +++ b/scripts/Vagrantfile @@ -0,0 +1,34 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +Vagrant.configure("2") do |config| + + config.vm.box = "ubuntu/focal64" + + # use vagrant-disksize plugin to resize partition - https://github.com/sprotheroe/vagrant-disksize + config.disksize.size = '50GB' + + config.vm.provider "virtualbox" do |vb| + # Customize the amount of memory on the VM + vb.memory = "4096" + end + + # Share the root of the repo + config.vm.synced_folder "../", "/home/vagrant/termux-packages" + # Disable the default /vagrant share directory, as it shares the directory with the Vagrantfile in it, not the repo root + config.vm.synced_folder ".", "/vagrant", disabled: true + + # Filesystem needs to be resized + config.vm.provision "shell", inline: "resize2fs /dev/sda1", privileged: true + + # Run environment setup scripts + config.vm.provision "shell", inline: "cd /home/vagrant/termux-packages && ./scripts/setup-ubuntu.sh", privileged: false + config.vm.provision "shell", inline: "cd /home/vagrant/termux-packages && ./scripts/setup-android-sdk.sh", privileged: false + + # Fix permissions on the /data directory in order to allow the "vagrant" user to write to it + config.vm.provision "shell", + inline: "chown -R vagrant /data", privileged: true + + # Tell the user how to use the VM + config.vm.post_up_message = "Box has been provisioned! Use 'vagrant ssh' to enter the box. The repository root is available under '~/termux-packages'." +end diff --git a/scripts/aptly_api.sh b/scripts/aptly_api.sh new file mode 100644 index 000000000..a91e0d2e3 --- /dev/null +++ b/scripts/aptly_api.sh @@ -0,0 +1,125 @@ +# These options and functions are sourced from +# .github/workflows/packages.yml and used for uploading packages to +# our repos + +CURL_COMMON_OPTIONS=( + --silent + --retry 2 + --retry-delay 3 + --user-agent 'Termux-Packages/1.0\ (https://github.com/termux/termux-packages)' + --user "${APTLY_API_AUTH}" + --write-out "|%{http_code}" +) + +CURL_ADDITIONAL_OPTIONS=() + +# Function for deleting temporary directory with uploaded files from +# the server. +aptly_delete_dir() { + echo "[$(date +%H:%M:%S)] Deleting uploads temporary directory..." + + curl_response=$( + curl \ + "${CURL_COMMON_OPTIONS[@]}" "${CURL_ADDITIONAL_OPTIONS[@]}" \ + --request DELETE \ + ${REPOSITORY_URL}/files/${REPOSITORY_NAME}-${GITHUB_SHA} + ) + + http_status_code=$(echo "$curl_response" | cut -d'|' -f2 | grep -oP '\d{3}$') + + if [ "$http_status_code" != "200" ]; then + echo "[$(date +%H:%M:%S)] Warning: server returned $http_status_code code while deleting temporary directory." + fi +} + +aptly_upload_file() { + local filename="$1" + curl_response=$(curl \ + "${CURL_COMMON_OPTIONS[@]}" "${CURL_ADDITIONAL_OPTIONS[@]}" \ + --request POST \ + --form file=@${filename} \ + ${REPOSITORY_URL}/files/${REPOSITORY_NAME}-${GITHUB_SHA} || true + ) + http_status_code=$(echo "$curl_response" | cut -d'|' -f2 | grep -oP '\d{3}$') + + if [ "$http_status_code" = "200" ]; then + echo "[$(date +%H:%M:%S)] Uploaded: $(echo "$curl_response" | cut -d'|' -f1 | jq -r '.[]' | cut -d'/' -f2)" + elif [ "$http_status_code" = "000" ]; then + echo "[$(date +%H:%M:%S)]: Failed to upload '$filename'. Server/proxy dropped connection during upload." + echo "[$(date +%H:%M:%S)]: Aborting any further uploads to this repo." + aptly_delete_dir + return 1 + else + # Manually cleaning up the temporary directory to reclaim disk space. + # Don't rely on scheduled server-side scripts. + echo "[$(date +%H:%M:%S)] Error: failed to upload '$filename'. Server returned $http_status_code code." + echo "[$(date +%H:%M:%S)] Aborting any further uploads to this repo." + aptly_delete_dir + return 1 + fi + return 0 +} + +aptly_add_to_repo() { + echo "[$(date +%H:%M:%S)] Adding packages to repository '$REPOSITORY_NAME'..." + curl_response=$( + curl \ + "${CURL_COMMON_OPTIONS[@]}" "${CURL_ADDITIONAL_OPTIONS[@]}" \ + --max-time 300 \ + --request POST \ + ${REPOSITORY_URL}/repos/${REPOSITORY_NAME}/file/${REPOSITORY_NAME}-${GITHUB_SHA} || true + ) + http_status_code=$(echo "$curl_response" | cut -d'|' -f2 | grep -oP '\d{3}$') + + if [ "$http_status_code" = "200" ]; then + warnings=$(echo "$curl_response" | cut -d'|' -f1 | jq '.Report.Warnings' | jq -r '.[]') + if [ -n "$warnings" ]; then + echo "[$(date +%H:%M:%S)] APTLY WARNINGS (NON-CRITICAL):" + echo + echo "$warnings" + echo + return 1 + fi + elif [ "$http_status_code" == "000" ]; then + echo "[$(date +%H:%M:%S)] Warning: server/proxy dropped connection. Assuming that the host is adding packages inspite of lost connection." + echo "[$(date +%H:%M:%S)] Warning: Waiting for host to add packages. Sleeping for 180s. Assuming that packages will be added till then." + sleep 180 + return 0 + else + echo "[$(date +%H:%M:%S)] Error: got http_status_code == '$http_status_code'." + echo "[$(date +%H:%M:%S)] Error: the unexpected happened. Ask any maintainer to check the aptly log" + return 1 + fi + return 0 +} + +aptly_publish_repo() { + echo "[$(date +%H:%M:%S)] Publishing repository changes..." + curl_response=$( + curl \ + "${CURL_COMMON_OPTIONS[@]}" "${CURL_ADDITIONAL_OPTIONS[@]}" \ + --max-time 300 \ + --header 'Content-Type: application/json' \ + --request PUT \ + --data "{\"Signing\": {\"Passphrase\": \"${GPG_PASSPHRASE}\"}}" \ + ${REPOSITORY_URL}/publish/${REPOSITORY_NAME}/${REPOSITORY_DISTRIBUTION} || true + ) + http_status_code=$(echo "$curl_response" | cut -d'|' -f2 | grep -oP '\d{3}$') + + if [ "$http_status_code" = "200" ]; then + echo "[$(date +%H:%M:%S)] Repository has been updated successfully." + elif [ "$http_status_code" = "000" ]; then + echo "[$(date +%H:%M:%S)] Warning: server/proxy has dropped connection." + # Ignore - nothing can be done with that unless we change proxy. + # return 1 + elif [ "$http_status_code" = "504" ]; then + echo "[$(date +%H:%M:%S)] Warning: request processing time was too long, connection dropped." + # Ignore - nothing can be done with that unless we change repository + # management tool or reduce repository size. + # return 1 + else + echo "[$(date +%H:%M:%S)] Error: got http_status_code == '$http_status_code'" + return 1 + fi + return 0 +} diff --git a/scripts/bin/add-to-path.sh b/scripts/bin/add-to-path.sh new file mode 100755 index 000000000..f185b0be9 --- /dev/null +++ b/scripts/bin/add-to-path.sh @@ -0,0 +1,12 @@ +# Source this script in order to make the content of bin +# directory available in $PATH. Use only under Bash! + +if [ -z "${BASH}" ]; then + echo "Cannot source because your shell is not Bash!" +else + TERMUX_BINPATH=$(realpath "$(dirname "${BASH_SOURCE}")") + PATH="${TERMUX_BINPATH}:${PATH}" + export PATH + echo "Scripts from '$TERMUX_BINPATH' are now available in your \$PATH." + unset TERMUX_BINPATH +fi diff --git a/scripts/bin/apt-compare-versions b/scripts/bin/apt-compare-versions new file mode 120000 index 000000000..00f20e6cf --- /dev/null +++ b/scripts/bin/apt-compare-versions @@ -0,0 +1 @@ +../updates/utils/termux_pkg_is_update_needed.sh \ No newline at end of file diff --git a/scripts/bin/check-auto-update b/scripts/bin/check-auto-update new file mode 100755 index 000000000..f135354a6 --- /dev/null +++ b/scripts/bin/check-auto-update @@ -0,0 +1,276 @@ +#!/bin/bash + +# This script is used to check if given package can be auto-updated and optionally enable if it can be. +# NOTE: You should not trust this script if package uses commit hashes for versioning(eg. 'tsu') or +# TERMUX_PKG_VERSION is defined by us and not upstream(i.e we use some arbitrary version. For eg. when +# getting source files based on commit hash). + +# The MIT License (MIT) + +# Copyright (c) 2022 Aditya Alok + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +set -e + +TERMUX_SCRIPTDIR="$(realpath "$(dirname "$(readlink -f "$0")")/../..")" + +_RESET_COLOR="\033[0m" +_BLUE="\033[1;34m" +_GREEN="\033[0;32m" +_RED="\033[0;31m" +_YELLOW="\033[0;33m" +_TEAL="\033[0;36m" + +usage() { + echo + echo -e "${_BLUE}Usage:${_RESET_COLOR} $(basename "$0")" \ + "${_GREEN}[-h|--help]" \ + "[-s|--silent]" \ + "[--enable]" \ + "PACKAGE_DIR" + echo + echo -e "${_TEAL}Check if packages can be auto-updated and optionally enable if so." + echo + echo -e "${_RED}NOTE: ${_YELLOW}You should not trust this script if\n" \ + "\t${_BLUE}- ${_YELLOW}package uses commit hashes for versioning (eg. 'tsu') or\n" \ + "\t${_BLUE}- ${_GREEN}TERMUX_PKG_VERSION ${_YELLOW}is defined by us and not upstream, i.e we use some arbitrary version.\n" \ + "\t For eg. when only getting source files based on commit hash." + echo + echo -e "${_BLUE}Options:" + echo -e "${_GREEN}-h --help${_TEAL} Show this help message." + echo -e "${_GREEN}--enable${_TEAL} Enable auto-update for package if check was successful." \ + "(writes ${_YELLOW}TERMUX_PKG_AUTO_UPDATE=true${_TEAL} to build.sh)" + echo -e "${_GREEN}-s --silent${_TEAL} Do not print anything to stdout." + echo + echo -e "${_BLUE}Example:${_RESET_COLOR} $(basename "$0") x11-packages/xorg-server" + echo +} + +color_print() { + [[ "${SILENT}" == "true" ]] && return 0 + echo -e "$1${_RESET_COLOR}" +} + +warn() { + color_print "${_BLUE}[${_YELLOW}*${_BLUE}]${_YELLOW} $*" >&2 +} + +error() { + local exit="return" + [[ "${1}" == "--exit" ]] && exit="exit" && shift + color_print "${_BLUE}[${_RED}!${_BLUE}]${_RED} $*" >&2 + ${exit} 1 +} + +info() { + color_print "${_BLUE}[${_GREEN}+${_BLUE}]${_TEAL} $*" +} + +_check_stderr() { + local stderr="$1" + + local http_code + http_code="$(grep "HTTP code:" <<<"${stderr}" | cut -d ':' -f2 | tr -d ' ')" + + if [[ -n "${http_code}" ]]; then + [[ ${http_code} == 000 ]] && error --exit "Could not connect to server. Please check your connection." + warn "Failed to get tag. [HTTP code: $http_code]" + return "$http_code" + elif grep -qE "ERROR: No '(latest-release-tag|newest-tag)'" <<<"${stderr}"; then + return 2 + elif grep -q "ERROR: GITHUB_TOKEN" <<<"$stderr"; then + error --exit "GITHUB_TOKEN is not set." # exit script on this error. + else + warn "$stderr" + return 1 + fi +} + +_check() { + local from_where="$1" # Which api service to use? + shift + local stderr + stderr="$( + set -euo pipefail + # shellcheck source=/dev/null + . "${TERMUX_SCRIPTDIR}/scripts/updates/api/termux_${from_where}_api_get_tag.sh" + . "${TERMUX_SCRIPTDIR}/scripts/updates/utils/termux_error_exit.sh" + termux_"${from_where}"_api_get_tag "$@" 2>&1 >/dev/null + )" || _check_stderr "${stderr}" +} + +check() { + local from_where="$1" # Can be either 'github' or 'gitlab'. + local url="$2" + local return_code=0 + + if [[ ! $src_url =~ ^https?://${from_where}.com ]]; then + warn "Not a ${from_where} url: ${src_url}" + return 1 + fi + + _check "$from_where" "$url" || return_code="$?" + + if [[ "${url: -4}" != ".git" ]] && [[ "$return_code" == "2" ]]; then + warn "No 'latest-release-tag' found. Checking for 'newest-tag'..." + return_code=3 # Set return code to 3 to indicate that TERMUX_PKG_UPDATE_TAG_TYPE='newest-tag' + # should also be written to build.sh if we find 'newest-tag' in next line. + _check "$from_where" "$url" "newest-tag" || return_code="$?" + fi + + return "$return_code" +} + +declare -a UNIQUE_PACKAGES +# NOTE: This function ignores Termux own packages like 'termux-api','termux-exec', etc. +# It should be manually checked. +repology() { + local pkg_name="$1" + if [[ -z "${UNIQUE_PACKAGES[*]}" ]]; then + # NOTE: mapfile requires bash 4+ + mapfile -t UNIQUE_PACKAGES < <( + curl --silent --location --retry 5 --retry-delay 5 --retry-max-time 60 \ + "https://repology.org/api/v1/projects/?inrepo=termux&&repos=1" | + jq -r 'keys[]' + ) + + [[ -z "${UNIQUE_PACKAGES[*]}" ]] && error --exit "Failed to get unique packages from repology.org" + fi + # shellcheck disable=SC2076 + if [[ ! " ${UNIQUE_PACKAGES[*]} " =~ " ${pkg_name} " ]]; then + return 0 # Package is not unique, can be updated. + else + warn "Package '$pkg_name' is unique to Termux, cannot be auto-updated." + return 1 # Package is unique, cannot be updated. + fi +} + +write_to_first_empty_line() { + local -r file="$1" + local -r line="$2" + # Find first empty line from top of file: + local -r first_empty_line=$(sed -n '/^$/=' "$file" | head -n 1) + if [[ -n "$first_empty_line" ]]; then + sed -i "${first_empty_line}i$line" "$file" + else + echo "$line" >>"$file" + fi +} + +test_pkg() { + local pkg_dir="$1" + local pkg_name + pkg_name="$(basename "${pkg_dir}")" + + if [[ ! -f "${pkg_dir}/build.sh" ]]; then + error --exit "Package '$pkg_name' does not exist." + fi + + local vars + vars="$( + set +eu + # shellcheck source=/dev/null + . "$pkg_dir/build.sh" >/dev/null + echo "src_url=\"${TERMUX_PKG_SRCURL}\";" + echo "auto_update=\"${TERMUX_PKG_AUTO_UPDATE}\";" + )" + local src_url="" + local auto_update="" + eval "$vars" + + color_print "${_BLUE}==>${_YELLOW} $pkg_name" + + # Check if auto_update is not empty, then package has been already checked. + if [[ -n "${auto_update}" ]]; then + warn "Auto-update is already set to ${_BLUE}'${auto_update}'${_YELLOW} in build.sh." + return 0 + elif [[ -z "${src_url}" ]]; then + error "Could not find TERMUX_PKG_SRCURL." + fi + + local checks=( + "github" + "gitlab" + "repology" + ) + local can_be_updated=false + local tag_type="" + local update_method="" + for check in "${checks[@]}"; do + info "Checking if package can be updated from $check..." + local return_code=0 + + if [[ "$check" != "repology" ]]; then + check "$check" "$src_url" || return_code="$?" + else + repology "$pkg_name" || return_code="$?" + update_method="repology" + fi + + if [[ "$return_code" == "0" ]]; then + can_be_updated=true + break + elif [[ "$return_code" == "3" ]]; then + can_be_updated=true + tag_type="newest-tag" + break + fi + done + + if [[ "${can_be_updated}" == "true" ]]; then + info "Package can be auto-updated." + if [[ "${ENABLE}" == "--enable" ]]; then + info "Enabling auto-update..." + write_to_first_empty_line "$pkg_dir/build.sh" "TERMUX_PKG_AUTO_UPDATE=true" + if [[ -n "${tag_type}" ]]; then + write_to_first_empty_line "$pkg_dir/build.sh" "TERMUX_PKG_UPDATE_TAG_TYPE=\"${tag_type}\"" + fi + if [[ -n "${update_method}" ]]; then + write_to_first_empty_line "$pkg_dir/build.sh" "TERMUX_PKG_UPDATE_METHOD=${update_method}" + fi + info "Done." + fi + else + error "Package cannot be auto-updated." + fi +} + +if [[ $# -lt 1 ]] || [[ $# -gt 3 ]]; then + error --exit "Invalid number of arguments. See --help for usage." +fi + +while [[ $# -gt 0 ]]; do + case "$1" in + --enable) + ENABLE="$1" + ;; + -s | --silent) + SILENT=true + ;; + -h | --help) + usage + ;; + *) + test_pkg "$1" + [[ "${SILENT}" == "true" ]] || echo + ;; + esac + shift +done diff --git a/scripts/bin/check-pie.sh b/scripts/bin/check-pie.sh new file mode 100755 index 000000000..3eff38d42 --- /dev/null +++ b/scripts/bin/check-pie.sh @@ -0,0 +1,12 @@ +#!/bin/sh +# check-pie.sh - script to detect non-PIE binaries (which does not work on Android) + +. $(dirname "$(realpath "$0")")/properties.sh + +cd ${TERMUX_PREFIX}/bin + +for file in *; do + if readelf -h $file 2>/dev/null | grep -q 'Type:[[:space:]]*EXEC'; then + echo $file + fi +done diff --git a/scripts/bin/ldd b/scripts/bin/ldd new file mode 100755 index 000000000..70f30cf84 --- /dev/null +++ b/scripts/bin/ldd @@ -0,0 +1,3 @@ +#!/bin/sh + +objdump -x $@ | grep NEEDED | cut -c 24- | sort diff --git a/scripts/bin/revbump b/scripts/bin/revbump new file mode 100755 index 000000000..9eb39cb09 --- /dev/null +++ b/scripts/bin/revbump @@ -0,0 +1,91 @@ +#!/usr/bin/env bash +## +## Script for bumping package revision. +## +## Licensed under the Apache License, Version 2.0 (the "License"); +## you may not use this file except in compliance with the License. +## You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## + +if [ "${#}" = "0" ]; then + echo + echo "Usage: revbump [package name] ..." + echo + echo "Add or increment TERMUX_PKG_REVISION of package." + echo + exit 1 +fi + +REPO_ROOT=$(realpath "$(dirname "$0")/../../") +IS_GIT_REPOSITORY=false + +if git status >/dev/null 2>&1; then + IS_GIT_REPOSITORY=true +fi + +for package in "${@}"; do + package="${package%%/}" + buildsh_path= + for repo in $(jq --raw-output 'keys | .[]' ${REPO_ROOT}/repo.json); do + _buildsh_path="${REPO_ROOT}/${repo}/${package}/build.sh" + echo $_buildsh_path + + if [ -f "${_buildsh_path}" ]; then + buildsh_path=$_buildsh_path + break + fi + done + + if [ -z "$buildsh_path" ]; then + echo "${package}: skipping as no build.sh found" + continue + fi + + if grep -qP '^TERMUX_PKG_REVISION=(\d+)$' "${buildsh_path}"; then + # Increment revision. + current_rev=$(. "${buildsh_path}" 2>/dev/null; echo "${TERMUX_PKG_REVISION}") + incremented_rev=$((current_rev + 1)) + + # Replace revision value in build.sh. + if ! ${IS_GIT_REPOSITORY}; then + echo "${package}: bumping to ${incremented_rev}" + fi + sed -i -E "s/^(TERMUX_PKG_REVISION=)(.*)$/\1${incremented_rev}/g" "${buildsh_path}" + else + # Add base (1) revision right after TERMUX_PKG_VERSION. + if ! ${IS_GIT_REPOSITORY}; then + echo "${package}: setting revision to 1" + fi + sed -i -E "/TERMUX_PKG_VERSION=(.*)/a TERMUX_PKG_REVISION=1" "${buildsh_path}" + fi + + # If we are on Git repository, prompt for committing changes. + if ${IS_GIT_REPOSITORY}; then + echo + echo "You are about to commit these changes:" + echo + echo "--------------------" + git --no-pager diff --patch "${buildsh_path}" + echo "--------------------" + echo + echo "${package}: bump revision" + echo + read -re -p "Do you want to commit these changes ? (y/n) " CHOICE + echo + if [[ ${CHOICE} =~ (Y|y) ]]; then + git add "${buildsh_path}" + git commit -m "${package}: bump revision" + else + echo "Not committing to Git!" + fi + echo + fi +done diff --git a/scripts/bin/update-checksum b/scripts/bin/update-checksum new file mode 100755 index 000000000..29df3edf5 --- /dev/null +++ b/scripts/bin/update-checksum @@ -0,0 +1,110 @@ +#!/usr/bin/env bash +## +## Package update helper script which sets new SHA-256 for source bundle. +## +## Licensed under the Apache License, Version 2.0 (the "License"); +## you may not use this file except in compliance with the License. +## You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## + +set -e + +if [ "${#}" = "0" ]; then + echo + echo "Usage: update-sha256 [package name] ..." + echo + echo "Update TERMUX_PKG_SHA256 of package and optionally commit changes." + echo + exit 1 +fi + +REPO_ROOT=$(realpath "$(dirname "$0")/../../") +IS_GIT_REPOSITORY=false + +if git status >/dev/null 2>&1; then + IS_GIT_REPOSITORY=true +fi + +for package in "${@}"; do + buildsh_path= + if [ -d "${package}" ] && [ -f "${package}/build.sh" ]; then + buildsh_path="${package}/build.sh" + package=$(basename ${package}) + else + for repo_path in $(jq --raw-output 'keys | .[]' $REPO_ROOT/repo.json); do + if [ -d "${repo_path}/${package}" ] && [ -f "${repo_path}/${package}/build.sh" ]; then + buildsh_path="${repo_path}/${package}/build.sh" + package=$(basename ${package}) + fi + done + fi + + if [ ! -f "${buildsh_path}" ]; then + echo "${package}: skipping as no build.sh found" + continue + fi + + # Calculate new checksum in subshell. + echo + new_checksum=$( + source "${buildsh_path}" 2>/dev/null + + dl_tmpdir=$(mktemp -d "${TMPDIR-/tmp}/termux.src.dl.XXXXXXXX") + + if [ -n "${dl_tmpdir}" ] && [ -d "${dl_tmpdir}" ]; then + if ! curl --fail --location --retry 3 --output "${dl_tmpdir}/source-bundle" \ + "${TERMUX_PKG_SRCURL[0]}"; then + rm -rf "${dl_tmpdir}" + fi + + if [ -f "${dl_tmpdir}/source-bundle" ]; then + sha256sum "${dl_tmpdir}/source-bundle" | awk '{ print $1 }' + fi + + rm -rf "${dl_tmpdir}" + fi + ) + + if [ -n "${new_checksum}" ]; then + # Replace old SHA-256. + # Note that this will not work properly if SHA-256 is an array. + sed -i "s/^\(TERMUX_PKG_SHA256=\)\(.*\)\$/\1${new_checksum}/g" "${buildsh_path}" + + # Delete revision as it shouldn't be present if package was updated. + sed -i "/TERMUX_PKG_REVISION=/d" "${buildsh_path}" + + # If we are on Git repository, prompt for committing changes. + if ${IS_GIT_REPOSITORY}; then + echo + echo "You are about to commit these changes:" + echo + echo "--------------------" + git --no-pager diff --patch "${buildsh_path}" + echo "--------------------" + echo + echo "${package}: update to $(. "${buildsh_path}"; echo "${TERMUX_PKG_VERSION}" | cut -d: -f2-)" + echo + read -re -p "Do you want to commit changes ? (y/n) " CHOICE + echo + if [[ ${CHOICE} =~ (Y|y) ]]; then + git add "${buildsh_path}" + git commit -m "${package}: update to $(. "${buildsh_path}"; echo "${TERMUX_PKG_VERSION}" | cut -d: -f2-)" + else + echo "Not committing to Git!" + fi + echo + fi + else + echo + echo "${package}: failed to calculate the new checksum" + exit 1 + fi +done diff --git a/scripts/bin/update-packages b/scripts/bin/update-packages new file mode 100755 index 000000000..21d74fda9 --- /dev/null +++ b/scripts/bin/update-packages @@ -0,0 +1,313 @@ +#!/usr/bin/env bash + +set -u + +# Following variables should be set in environment outside of this script. +# Build updated packages. +: "${BUILD_PACKAGES:=false}" +# Commit changes to Git. +: "${GIT_COMMIT_PACKAGES:=false}" +# Push changes to remote. +: "${GIT_PUSH_PACKAGES:=false}" + +export TERMUX_PKG_UPDATE_METHOD="" # Which method to use for updating? (repology, github or gitlab) +export TERMUX_PKG_UPDATE_TAG_TYPE="" # Whether to use latest-release-tag or newest-tag. +export TERMUX_GITLAB_API_HOST="gitlab.com" # Default host for gitlab-ci. +export TERMUX_PKG_AUTO_UPDATE=false # Whether to auto-update or not. Disabled by default. +export TERMUX_PKG_UPDATE_VERSION_REGEXP="" # Regexp to extract version. +export TERMUX_REPOLOGY_DATA_FILE +TERMUX_REPOLOGY_DATA_FILE="$(mktemp -t termux-repology.XXXXXX)" # File to store repology data. + +export TERMUX_SCRIPTDIR +TERMUX_SCRIPTDIR=$(realpath "$(dirname "$0")/../..") # Root of repository. + +export TERMUX_PACKAGES_DIRECTORIES +TERMUX_PACKAGES_DIRECTORIES=$(jq --raw-output 'keys | .[]' "${TERMUX_SCRIPTDIR}"/repo.json) + +# Define few more variables used by scripts. +# shellcheck source=scripts/properties.sh +. "${TERMUX_SCRIPTDIR}/scripts/properties.sh" + +# Utility function to write error message to stderr. +# shellcheck source=scripts/updates/utils/termux_error_exit.sh +. "${TERMUX_SCRIPTDIR}"/scripts/updates/utils/termux_error_exit.sh + +# Utility function to write updated version to build.sh. +# shellcheck source=scripts/updates/utils/termux_pkg_upgrade_version.sh +. "${TERMUX_SCRIPTDIR}"/scripts/updates/utils/termux_pkg_upgrade_version.sh + +# Utility function to check if package needs to be updated, based on version comparison. +# shellcheck source=scripts/updates/utils/termux_pkg_is_update_needed.sh +. "${TERMUX_SCRIPTDIR}"/scripts/updates/utils/termux_pkg_is_update_needed.sh + +# Wrapper around github api to get latest release or newest tag. +# shellcheck source=scripts/updates/api/termux_github_api_get_tag.sh +. "${TERMUX_SCRIPTDIR}"/scripts/updates/api/termux_github_api_get_tag.sh + +# Wrapper around gitlab api to get latest release or newest tag. +# shellcheck source=scripts/updates/api/termux_gitlab_api_get_tag.sh +. "${TERMUX_SCRIPTDIR}"/scripts/updates/api/termux_gitlab_api_get_tag.sh + +# Function to get latest version of a package as per repology. +# shellcheck source=scripts/updates/api/termux_repology_api_get_latest_version.sh +. "${TERMUX_SCRIPTDIR}"/scripts/updates/api/termux_repology_api_get_latest_version.sh + +# Default auto update script for packages hosted on github.com. Should not be overrided by build.sh. +# To use custom algorithm, one should override termux_pkg_auto_update(). +# shellcheck source=scripts/updates/internal/termux_github_auto_update.sh +. "${TERMUX_SCRIPTDIR}"/scripts/updates/internal/termux_github_auto_update.sh + +# Default auto update script for packages hosted on hosts using gitlab-ci. Should not be overrided by build.sh. +# To use custom algorithm, one should override termux_pkg_auto_update(). +# shellcheck source=scripts/updates/internal/termux_gitlab_auto_update.sh +. "${TERMUX_SCRIPTDIR}"/scripts/updates/internal/termux_gitlab_auto_update.sh + +# Default auto update script for rest packages. Should not be overrided by build.sh. +# To use custom algorithm, one should override termux_pkg_auto_update(). +# shellcheck source=scripts/updates/internal/termux_repology_auto_update.sh +. "${TERMUX_SCRIPTDIR}"/scripts/updates/internal/termux_repology_auto_update.sh + +# Main script to: +# - by default, decide which update method to use, +# - but can be overrided by build.sh to use custom update method. +# - For example: see neovim-nightly's build.sh. +# shellcheck source=scripts/updates/termux_pkg_auto_update.sh +. "${TERMUX_SCRIPTDIR}"/scripts/updates/termux_pkg_auto_update.sh + +_update() { + export TERMUX_PKG_NAME + TERMUX_PKG_NAME="$(basename "$1")" + export TERMUX_PKG_BUILDER_DIR + TERMUX_PKG_BUILDER_DIR="$(realpath "$1")" # Directory containing build.sh. + + IFS="," read -r -a BLACKLISTED_ARCH <<<"${TERMUX_PKG_BLACKLISTED_ARCHES:-}" + export TERMUX_ARCH="" # Arch to test updates. + for arch in aarch64 arm i686 x86_64; do + # shellcheck disable=SC2076 + if [[ ! " ${BLACKLISTED_ARCH[*]} " =~ " ${arch} " ]]; then + TERMUX_ARCH="${arch}" + break + fi + done + # Set +e +u to avoid: + # - ending on errors such as $(which prog), where prog is not installed. + # - error on unbound variable. (All global variables used should be covered by properties.sh and above.) + set +e +u + # shellcheck source=/dev/null + . "${TERMUX_PKG_BUILDER_DIR}"/build.sh 2>/dev/null + set -e -u + + echo # Newline. + echo "INFO: Updating ${TERMUX_PKG_NAME} [Current version: ${TERMUX_PKG_VERSION}]" + termux_pkg_auto_update +} + +declare -A _FAILED_UPDATES=() +declare -a _ALREADY_SEEN=() # Array of packages successfully updated or skipped. + +_run_update() { + local pkg_dir="$1" + # Run each package update in separate process since we include their environment variables. + local output="" + { + output=$( + set -euo pipefail + _update "${pkg_dir}" 2>&1 | tee /dev/fd/3 # fd 3 is used to output to stdout as well. + exit "${PIPESTATUS[0]}" # Return exit code of _update. + ) + } 3>&1 + # shellcheck disable=SC2181 + if [[ $? -ne 0 ]]; then + _FAILED_UPDATES["$(basename "${pkg_dir}")"]="${output}" + else + _ALREADY_SEEN+=("$(basename "${pkg_dir}")") + fi +} + +declare -a _CACHED_ISSUE_TITLES=() +# Check if an issue with same title already exists and is open. +_gh_check_issue_exists() { + local pkg_name="$1" + if [[ -z "${_CACHED_ISSUE_TITLES[*]}" ]]; then + while read -r title; do + _CACHED_ISSUE_TITLES+=("'${title}'") # An extra quote ('') is added to avoid false positive matches. + done <<<"$( + gh issue list \ + --label "auto update failing" --label "bot" \ + --state open \ + --search "Auto update failing for in:title type:issue" \ + --json title | jq -r '.[] | .title' + )" + fi + # shellcheck disable=SC2076 # We want literal match here, not regex based. + if [[ "${_CACHED_ISSUE_TITLES[*]}" =~ "'Auto update failing for ${pkg_name}'" ]]; then + return 0 + fi + return 1 +} + +_should_update() { + local pkg_dir="$1" + + if [[ ! -f "${pkg_dir}/build.sh" ]]; then + # Fail if detected a non-package directory. + termux_error_exit "ERROR: directory '${pkg_dir}' is not a package." + fi + + # shellcheck disable=SC2076 + if ! grep -q '^TERMUX_PKG_AUTO_UPDATE=true$' "${pkg_dir}/build.sh" || + [[ " ${_ALREADY_SEEN[*]} ${!_FAILED_UPDATES[*]} " =~ " $(basename "${pkg_dir}") " ]]; then + return 1 # Skip. + fi + if [[ "${GITHUB_ACTIONS:-}" == "true" ]] && _gh_check_issue_exists "$(basename "${pkg_dir}")"; then + echo "INFO: Skipping '$(basename "${pkg_dir}")', an update issue for it hasn't been resolved yet." + return 1 + fi + + return 0 +} + +shopt -s extglob +_update_dependencies() { + local pkg_dir="$1" + + if ! grep -qE "^(TERMUX_PKG_DEPENDS|TERMUX_PKG_BUILD_DEPENDS|TERMUX_SUBPKG_DEPENDS)=" \ + "${pkg_dir}"/+(build|*.subpackage).sh; then + return 0 + fi + # shellcheck disable=SC2086 # Allow splitting of TERMUX_PACKAGES_DIRECTORIES. + while read -r dep dep_dir; do + if [[ -z $dep ]]; then + continue + elif [[ "${dep}" == "ERROR" ]]; then + termux_error_exit "ERROR: Obtaining update order failed for $(basename "${pkg_dir}")" + fi + _should_update "${dep_dir}" && _run_update "${dep_dir}" + done <<<"$("${TERMUX_SCRIPTDIR}"/scripts/buildorder.py "${pkg_dir}" $TERMUX_PACKAGES_DIRECTORIES || echo "ERROR")" +} + +echo "INFO: Running update for: $*" + +if [[ "$1" == "@all" ]]; then + for repo_dir in $(jq --raw-output 'keys | .[]' "${TERMUX_SCRIPTDIR}/repo.json"); do + for pkg_dir in "${repo_dir}"/*; do + ! _should_update "${pkg_dir}" && continue # Skip if not needed. + # Update all its dependencies first. + _update_dependencies "${pkg_dir}" + # NOTE: I am not cheacking whether dependencies were updated successfully or not. + # There is no way I could know whether this package will build with current + # available verions of its dependencies or needs new ones. + # So, whatever the case may be. We just need packages to be updated in order + # and not care about anything else in between. If something fails to update, + # it will be reported by failure handling code, so no worries. + _run_update "${pkg_dir}" + done + done +else + for pkg in "$@"; do + if [ ! -d "${pkg}" ]; then # If only package name is given, try to find it's directory. + for repo_dir in $(jq --raw-output 'keys | .[]' "${TERMUX_SCRIPTDIR}/repo.json"); do + if [ -d "${repo_dir}/${pkg}" ]; then + pkg="${repo_dir}/${pkg}" + break + fi + done + fi + # Here `pkg` is a directory. + ! _should_update "${pkg}" && continue + _update_dependencies "${pkg}" + _run_update "${pkg}" + done +fi + +################################################FAILURE HANDLING################################################# + +_gh_create_new_issue() { + local pkg_name="$1" + + local max_body_length=65536 # Max length of the body for one request. + local assignee="${GITHUB_ACTOR:-}" + local issue_number + local body + + if [[ "${assignee:-termuxbot2}" == "termuxbot2" ]]; then + assignee="MrAdityaAlok" # Assign myself if termuxbot2 is the actor. + fi + + body="$( + cat <<-EOF + Hi, I'm Termux 🤖. + + I'm here to help you update your Termux packages. + + I've tried to update the ${pkg_name} package, but it failed. + + Here's the output of the update script: +
+ Show log +
${_FAILED_UPDATES["${pkg_name}"]}
+
+ +
+ + Above error occured when I last tried to update at $(date -u +"%Y-%m-%d %H:%M:%S UTC").
+ Run ID: ${GITHUB_RUN_ID}

+ Note: Automatic updates will be disabled until this issue is resolved.
+
+ EOF + )" + issue_number=$( + gh issue create \ + --title "Auto update failing for ${pkg_name}" \ + --body "${body:0:${max_body_length}}" \ + --label "auto update failing" --label "bot" \ + --assignee ${assignee} | + grep -oE "[0-9]+" # Last component of the URL returned is the issue number. + ) + if [ -z "${issue_number}" ]; then + echo "ERROR: Failed to create issue." + return 1 + fi + + echo "INFO: Created issue ${issue_number} for ${pkg_name}." + + if [[ -n "${body:${max_body_length}}" ]]; then + # The body was too long, so we need to append the rest. + while true; do + body="${body:${max_body_length}}" + if [[ -z "${body}" ]]; then + break + fi + sleep 5 # Otherwise we might get rate limited. + gh issue edit "$issue_number" \ + --body-file - <<<"$( + gh issue view "$issue_number" \ + --json body \ + --jq '.body' + )${body:0:${max_body_length}}" >/dev/null + # NOTE: we use --body-file instead of --body to avoid shell error 'argument list too long'. + done + fi +} + +_handle_failure() { + echo # Newline. + if [[ "${GITHUB_ACTIONS:-}" == "true" ]]; then + echo "INFO: Creating issue for failed updates...(if any)" + for pkg_name in "${!_FAILED_UPDATES[@]}"; do + _gh_create_new_issue "${pkg_name}" + done + else + echo "==> Failed updates:" + local count=0 + for pkg_name in "${!_FAILED_UPDATES[@]}"; do + count=$((count + 1)) + echo "${count}. ${pkg_name}" + done + exit 1 + fi +} + +if [[ ${#_FAILED_UPDATES[@]} -gt 0 ]]; then + _handle_failure +fi diff --git a/scripts/build-bootstraps.sh b/scripts/build-bootstraps.sh new file mode 100755 index 000000000..7c5c5ca5e --- /dev/null +++ b/scripts/build-bootstraps.sh @@ -0,0 +1,466 @@ +#!/usr/bin/env bash +# shellcheck disable=SC2039,SC2059 + +# Title: build-bootstrap.sh +# Description: A script to build bootstrap archives for the termux-app +# from local package sources instead of debs published in +# apt repo like done by generate-bootstrap.sh. It allows +# bootstrap archives to be easily built for (forked) termux +# apps without having to publish an apt repo first. +# Usage: run "build-bootstrap.sh --help" +version=0.1.0 + +set -e + +. $(dirname "$(realpath "$0")")/properties.sh + +BOOTSTRAP_TMPDIR=$(mktemp -d "${TMPDIR:-/tmp}/bootstrap-tmp.XXXXXXXX") + +# By default, bootstrap archives are compatible with Android >=7.0 +# and <10. +BOOTSTRAP_ANDROID10_COMPATIBLE=false + +# By default, bootstrap archives will be built for all architectures +# supported by Termux application. +# Override with option '--architectures'. +TERMUX_DEFAULT_ARCHITECTURES=("aarch64" "arm" "i686" "x86_64") +TERMUX_ARCHITECTURES=("${TERMUX_DEFAULT_ARCHITECTURES[@]}") + +TERMUX_PACKAGES_DIRECTORY="/home/builder/termux-packages" +TERMUX_BUILT_DEBS_DIRECTORY="$TERMUX_PACKAGES_DIRECTORY/output" +TERMUX_BUILT_PACKAGES_DIRECTORY="/data/data/.built-packages" + +IGNORE_BUILD_SCRIPT_NOT_FOUND_ERROR=1 +FORCE_BUILD_PACKAGES=0 + +# A list of packages to build +declare -a PACKAGES=() + +# A list of non-essential packages to build. +# By default it is empty, but can be filled with option '--add'. +declare -a ADDITIONAL_PACKAGES=() + +# A list of already extracted packages +declare -a EXTRACTED_PACKAGES=() + +# A list of options to pass to build-package.sh +declare -a BUILD_PACKAGE_OPTIONS=() + +# Check for some important utilities that may not be available for +# some reason. +for cmd in ar awk curl grep gzip find sed tar xargs xz zip; do + if [ -z "$(command -v $cmd)" ]; then + echo "[!] Utility '$cmd' is not available in PATH." + exit 1 + fi +done + +# Build deb files for package and its dependencies deb from source for arch +build_package() { + + local return_value + + local package_arch="$1" + local package_name="$2" + + local build_output + + # Build package from source + # stderr will be redirected to stdout and both will be captured into variable and printed on screen + cd "$TERMUX_PACKAGES_DIRECTORY" + echo $'\n\n\n'"[*] Building '$package_name'..." + exec 99>&1 + build_output="$("$TERMUX_PACKAGES_DIRECTORY"/build-package.sh "${BUILD_PACKAGE_OPTIONS[@]}" -a "$package_arch" "$package_name" 2>&1 | tee >(cat - >&99); exit ${PIPESTATUS[0]})"; + return_value=$? + echo "[*] Building '$package_name' exited with exit code $return_value" + exec 99>&- + if [ $return_value -ne 0 ]; then + echo "Failed to build package '$package_name' for arch '$package_arch'" 1>&2 + + # Dependency packages may not have a build.sh, so we ignore the error. + # A better way should be implemented to validate if its actually a dependency + # and not a required package itself, by removing dependencies from PACKAGES array. + if [[ $IGNORE_BUILD_SCRIPT_NOT_FOUND_ERROR == "1" ]] && [[ "$build_output" == *"No build.sh script at package dir"* ]]; then + echo "Ignoring error 'No build.sh script at package dir'" 1>&2 + return 0 + fi + fi + + return $return_value + +} + +# Extract *.deb files to the bootstrap root. +extract_debs() { + + local current_package_name + local data_archive + local control_archive + local package_tmpdir + local deb + local file + + cd "$TERMUX_BUILT_DEBS_DIRECTORY" + + if [ -z "$(ls -A)" ]; then + echo $'\n\n\n'"No debs found" + return 1 + else + echo $'\n\n\n'"Deb Files:" + echo "\"" + ls + echo "\"" + fi + + for deb in *.deb; do + + current_package_name="$(echo "$deb" | sed -E 's/^([^_]+).*/\1/' )" + echo "current_package_name: '$current_package_name'" + + if [[ "$current_package_name" == *"-static" ]]; then + echo "[*] Skipping static package '$deb'..." + continue + fi + + if [[ " ${EXTRACTED_PACKAGES[*]} " == *" $current_package_name "* ]]; then + echo "[*] Skipping already extracted package '$current_package_name'..." + continue + fi + + EXTRACTED_PACKAGES+=("$current_package_name") + + package_tmpdir="${BOOTSTRAP_PKGDIR}/${current_package_name}" + mkdir -p "$package_tmpdir" + rm -rf "$package_tmpdir"/* + + echo "[*] Extracting '$deb'..." + (cd "$package_tmpdir" + ar x "$TERMUX_BUILT_DEBS_DIRECTORY/$deb" + + # data.tar may have extension different from .xz + if [ -f "./data.tar.xz" ]; then + data_archive="data.tar.xz" + elif [ -f "./data.tar.gz" ]; then + data_archive="data.tar.gz" + else + echo "No data.tar.* found in '$deb'." + return 1 + fi + + # Do same for control.tar. + if [ -f "./control.tar.xz" ]; then + control_archive="control.tar.xz" + elif [ -f "./control.tar.gz" ]; then + control_archive="control.tar.gz" + else + echo "No control.tar.* found in '$deb'." + return 1 + fi + + # Extract files. + tar xf "$data_archive" -C "$BOOTSTRAP_ROOTFS" + + if ! ${BOOTSTRAP_ANDROID10_COMPATIBLE}; then + # Register extracted files. + tar tf "$data_archive" | sed -E -e 's@^\./@/@' -e 's@^/$@/.@' -e 's@^([^./])@/\1@' > "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/var/lib/dpkg/info/${current_package_name}.list" + + # Generate checksums (md5). + tar xf "$data_archive" + find data -type f -print0 | xargs -0 -r md5sum | sed 's@^\.$@@g' > "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/var/lib/dpkg/info/${current_package_name}.md5sums" + + # Extract metadata. + tar xf "$control_archive" + { + cat control + echo "Status: install ok installed" + echo + } >> "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/var/lib/dpkg/status" + + # Additional data: conffiles & scripts + for file in conffiles postinst postrm preinst prerm; do + if [ -f "${PWD}/${file}" ]; then + cp "$file" "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/var/lib/dpkg/info/${current_package_name}.${file}" + fi + done + fi + ) + done + +} + +# Final stage: generate bootstrap archive and place it to current +# working directory. +# Information about symlinks is stored in file SYMLINKS.txt. +create_bootstrap_archive() { + + echo $'\n\n\n'"[*] Creating 'bootstrap-${1}.zip'..." + (cd "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}" + # Do not store symlinks in bootstrap archive. + # Instead, put all information to SYMLINKS.txt + while read -r -d '' link; do + echo "$(readlink "$link")←${link}" >> SYMLINKS.txt + rm -f "$link" + done < <(find . -type l -print0) + + zip -r9 "${BOOTSTRAP_TMPDIR}/bootstrap-${1}.zip" ./* + ) + + mv -f "${BOOTSTRAP_TMPDIR}/bootstrap-${1}.zip" "$TERMUX_PACKAGES_DIRECTORY/" + + echo "[*] Finished successfully (${1})." + +} + +set_build_bootstrap_traps() { + + #set traps for the build_bootstrap_trap itself + trap 'build_bootstrap_trap' EXIT + trap 'build_bootstrap_trap TERM' TERM + trap 'build_bootstrap_trap INT' INT + trap 'build_bootstrap_trap HUP' HUP + trap 'build_bootstrap_trap QUIT' QUIT + + return 0 + +} + +build_bootstrap_trap() { + + local build_bootstrap_trap_exit_code=$? + trap - EXIT + + [ -h "$TERMUX_BUILT_PACKAGES_DIRECTORY" ] && rm -f "$TERMUX_BUILT_PACKAGES_DIRECTORY" + [ -d "$BOOTSTRAP_TMPDIR" ] && rm -rf "$BOOTSTRAP_TMPDIR" + + [ -n "$1" ] && trap - "$1"; exit $build_bootstrap_trap_exit_code + +} + +show_usage() { + + cat <<'HELP_EOF' + +build-bootstraps.sh is a script to build bootstrap archives for the +termux-app from local package sources instead of debs published in +apt repo like done by generate-bootstrap.sh. It allows bootstrap archives +to be easily built for (forked) termux apps without having to publish +an apt repo first. + + +Usage: + build-bootstraps.sh [command_options] + + +Available command_options: + [ -h | --help ] Display this help screen + [ -f ] Force build even if packages have already been built. + [ --android10 ] + Generate bootstrap archives for Android 10+ for + apk packaging system. + [ -a | --add ] + Additional packages to include into bootstrap archive. + Multiple packages should be passed as comma-separated list. + [ --architectures ] + Override default list of architectures for which bootstrap + archives will be created. Multiple architectures should be + passed as comma-separated list. + + +The package name/prefix that the bootstrap is built for is defined by +TERMUX_APP_PACKAGE in 'scrips/properties.sh'. It defaults to 'com.termux'. +If package name is changed, make sure to run +`./scripts/run-docker.sh ./clean.sh` or pass '-f' to force rebuild of packages. + +### Examples + +Build default bootstrap archives for all supported archs: +./scripts/run-docker.sh ./scripts/build-bootstraps.sh &> build.log + +Build default bootstrap archive for aarch64 arch only: +./scripts/run-docker.sh ./scripts/build-bootstraps.sh --architectures aarch64 &> build.log + +Build bootstrap archive with additionall openssh package for aarch64 arch only: +./scripts/run-docker.sh ./scripts/build-bootstraps.sh --architectures aarch64 --add openssh &> build.log +HELP_EOF + +echo $'\n'"TERMUX_APP_PACKAGE: \"$TERMUX_APP_PACKAGE\"" +echo "TERMUX_PREFIX: \"${TERMUX_PREFIX[*]}\"" +echo "TERMUX_ARCHITECTURES: \"${TERMUX_ARCHITECTURES[*]}\"" + +} + +main() { + + local return_value + + while (($# > 0)); do + case "$1" in + -h|--help) + show_usage + return 0 + ;; + --android10) + BOOTSTRAP_ANDROID10_COMPATIBLE=true + ;; + -a|--add) + if [ $# -gt 1 ] && [ -n "$2" ] && [[ $2 != -* ]]; then + for pkg in $(echo "$2" | tr ',' ' '); do + ADDITIONAL_PACKAGES+=("$pkg") + done + unset pkg + shift 1 + else + echo "[!] Option '--add' requires an argument." 1>&2 + show_usage + return 1 + fi + ;; + --architectures) + if [ $# -gt 1 ] && [ -n "$2" ] && [[ $2 != -* ]]; then + TERMUX_ARCHITECTURES=() + for arch in $(echo "$2" | tr ',' ' '); do + TERMUX_ARCHITECTURES+=("$arch") + done + unset arch + shift 1 + else + echo "[!] Option '--architectures' requires an argument." 1>&2 + show_usage + return 1 + fi + ;; + -f) + BUILD_PACKAGE_OPTIONS+=("-f") + FORCE_BUILD_PACKAGES=1 + ;; + *) + echo "[!] Got unknown option '$1'" 1>&2 + show_usage + return 1 + ;; + esac + shift 1 + done + + set_build_bootstrap_traps + + for package_arch in "${TERMUX_ARCHITECTURES[@]}"; do + if [[ " ${TERMUX_DEFAULT_ARCHITECTURES[*]} " != *" $package_arch "* ]]; then + echo "Unsupported architecture '$package_arch' for in architectures list: '${TERMUX_ARCHITECTURES[*]}'" 1>&2 + echo "Supported architectures: '${TERMUX_DEFAULT_ARCHITECTURES[*]}'" 1>&2 + return 1 + fi + done + + for package_arch in "${TERMUX_ARCHITECTURES[@]}"; do + + # The termux_step_finish_build stores package version in .built-packages directory, but + # its not arch independent. So instead we create an arch specific one and symlink it + # to the .built-packages directory so that users can easily switch arches without having + # to rebuild packages + TERMUX_BUILT_PACKAGES_DIRECTORY_FOR_ARCH="$TERMUX_BUILT_PACKAGES_DIRECTORY-$package_arch" + mkdir -p "$TERMUX_BUILT_PACKAGES_DIRECTORY_FOR_ARCH" + + if [ -f "$TERMUX_BUILT_PACKAGES_DIRECTORY" ] || [ -d "$TERMUX_BUILT_PACKAGES_DIRECTORY" ]; then + rm -rf "$TERMUX_BUILT_PACKAGES_DIRECTORY" + fi + + ln -sf "$TERMUX_BUILT_PACKAGES_DIRECTORY_FOR_ARCH" "$TERMUX_BUILT_PACKAGES_DIRECTORY" + + if [[ $FORCE_BUILD_PACKAGES == "1" ]]; then + rm -f "$TERMUX_BUILT_PACKAGES_DIRECTORY_FOR_ARCH"/* + rm -f "$TERMUX_BUILT_DEBS_DIRECTORY"/* + fi + + + + BOOTSTRAP_ROOTFS="$BOOTSTRAP_TMPDIR/rootfs-${package_arch}" + BOOTSTRAP_PKGDIR="$BOOTSTRAP_TMPDIR/packages-${package_arch}" + + # Create initial directories for $TERMUX_PREFIX + if ! ${BOOTSTRAP_ANDROID10_COMPATIBLE}; then + mkdir -p "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/etc/apt/apt.conf.d" + mkdir -p "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/etc/apt/preferences.d" + mkdir -p "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/var/lib/dpkg/info" + mkdir -p "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/var/lib/dpkg/triggers" + mkdir -p "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/var/lib/dpkg/updates" + mkdir -p "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/var/log/apt" + touch "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/var/lib/dpkg/available" + touch "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/var/lib/dpkg/status" + fi + mkdir -p "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/tmp" + + + + PACKAGES=() + EXTRACTED_PACKAGES=() + + # Package manager. + if ! ${BOOTSTRAP_ANDROID10_COMPATIBLE}; then + PACKAGES+=("apt") + fi + + # Core utilities. + PACKAGES+=("bash") + PACKAGES+=("bzip2") + if ! ${BOOTSTRAP_ANDROID10_COMPATIBLE}; then + PACKAGES+=("command-not-found") + else + PACKAGES+=("proot") + fi + PACKAGES+=("coreutils") + PACKAGES+=("curl") + PACKAGES+=("dash") + PACKAGES+=("diffutils") + PACKAGES+=("findutils") + PACKAGES+=("gawk") + PACKAGES+=("grep") + PACKAGES+=("gzip") + PACKAGES+=("less") + PACKAGES+=("procps") + PACKAGES+=("psmisc") + PACKAGES+=("sed") + PACKAGES+=("tar") + PACKAGES+=("termux-exec") + PACKAGES+=("termux-keyring") + PACKAGES+=("termux-tools") + PACKAGES+=("util-linux") + PACKAGES+=("xz-utils") + + # Additional. + PACKAGES+=("ed") + PACKAGES+=("debianutils") + PACKAGES+=("dos2unix") + PACKAGES+=("inetutils") + PACKAGES+=("lsof") + PACKAGES+=("nano") + PACKAGES+=("net-tools") + PACKAGES+=("patch") + PACKAGES+=("unzip") + + # Handle additional packages. + for add_pkg in "${ADDITIONAL_PACKAGES[@]}"; do + if [[ " ${PACKAGES[*]} " != *" $add_pkg "* ]]; then + PACKAGES+=("$add_pkg") + fi + done + unset add_pkg + + # Build packages. + for package_name in "${PACKAGES[@]}"; do + set +e + build_package "$package_arch" "$package_name" || return $? + set -e + done + + # Extract all debs. + extract_debs || return $? + + # Create bootstrap archive. + create_bootstrap_archive "$package_arch" || return $? + + done + +} + +main "$@" diff --git a/scripts/build/configure/termux_step_configure.sh b/scripts/build/configure/termux_step_configure.sh new file mode 100644 index 000000000..1e1c1e4f9 --- /dev/null +++ b/scripts/build/configure/termux_step_configure.sh @@ -0,0 +1,35 @@ +termux_step_configure() { + [ "$TERMUX_PKG_METAPACKAGE" = "true" ] && return + + # This check should be above autotools check as haskell package too makes use of configure scripts which + # should be executed by its own build system. + if ls "${TERMUX_PKG_SRCDIR}"/*.cabal &>/dev/null; then + [ "$TERMUX_CONTINUE_BUILD" == "true" ] && return + termux_setup_ghc_cross_compiler + termux_step_configure_haskell_build + elif [ "$TERMUX_PKG_FORCE_CMAKE" = "false" ] && [ -f "$TERMUX_PKG_SRCDIR/configure" ]; then + if [ "$TERMUX_CONTINUE_BUILD" == "true" ]; then + return + fi + termux_step_configure_autotools + elif [ "$TERMUX_PKG_FORCE_CMAKE" = "true" ] || [ -f "$TERMUX_PKG_SRCDIR/CMakeLists.txt" ]; then + termux_setup_cmake + if [ "$TERMUX_CMAKE_BUILD" = Ninja ]; then + termux_setup_ninja + fi + + # Some packages, for example swift, uses cmake + # internally, but cannot be configured with our + # termux_step_configure_cmake function (CMakeLists.txt + # is not in src dir) + if [ -f "$TERMUX_PKG_SRCDIR/CMakeLists.txt" ] && + [ "$TERMUX_CONTINUE_BUILD" == "false" ]; then + termux_step_configure_cmake + fi + elif [ -f "$TERMUX_PKG_SRCDIR/meson.build" ]; then + if [ "$TERMUX_CONTINUE_BUILD" == "true" ]; then + return + fi + termux_step_configure_meson + fi +} diff --git a/scripts/build/configure/termux_step_configure_autotools.sh b/scripts/build/configure/termux_step_configure_autotools.sh new file mode 100644 index 000000000..dd4322d7e --- /dev/null +++ b/scripts/build/configure/termux_step_configure_autotools.sh @@ -0,0 +1,116 @@ +termux_step_configure_autotools() { + if [ ! -e "$TERMUX_PKG_SRCDIR/configure" ]; then return; fi + + local ENABLE_STATIC="--enable-static" + if [ "$TERMUX_PKG_EXTRA_CONFIGURE_ARGS" != "${TERMUX_PKG_EXTRA_CONFIGURE_ARGS/--disable-static/}" ]; then + ENABLE_STATIC="" + fi + + local DISABLE_NLS="--disable-nls" + if [ "$TERMUX_PKG_EXTRA_CONFIGURE_ARGS" != "${TERMUX_PKG_EXTRA_CONFIGURE_ARGS/--enable-nls/}" ]; then + # Do not --disable-nls if package explicitly enables it (for gettext itself) + DISABLE_NLS="" + fi + + local ENABLE_SHARED="--enable-shared" + if [ "$TERMUX_PKG_EXTRA_CONFIGURE_ARGS" != "${TERMUX_PKG_EXTRA_CONFIGURE_ARGS/--disable-shared/}" ]; then + ENABLE_SHARED="" + fi + + local HOST_FLAG="--host=$TERMUX_HOST_PLATFORM" + if [ "$TERMUX_PKG_EXTRA_CONFIGURE_ARGS" != "${TERMUX_PKG_EXTRA_CONFIGURE_ARGS/--host=/}" ]; then + HOST_FLAG="" + fi + + local LIBEXEC_FLAG="--libexecdir=$TERMUX_PREFIX/libexec" + if [ "$TERMUX_PKG_EXTRA_CONFIGURE_ARGS" != "${TERMUX_PKG_EXTRA_CONFIGURE_ARGS/--libexecdir=/}" ]; then + LIBEXEC_FLAG="" + fi + + local QUIET_BUILD= + if [ "$TERMUX_QUIET_BUILD" = true ]; then + QUIET_BUILD="--enable-silent-rules --silent --quiet" + fi + + if [ "$TERMUX_ON_DEVICE_BUILD" = "false" ]; then + # Some packages provides a $PKG-config script which some configure scripts pickup instead of pkg-config: + mkdir "$TERMUX_PKG_TMPDIR/config-scripts" + for f in $TERMUX_PREFIX/bin/*config; do + test -f "$f" && cp "$f" "$TERMUX_PKG_TMPDIR/config-scripts" + done + export PATH=$TERMUX_PKG_TMPDIR/config-scripts:$PATH + fi + + # Avoid gnulib wrapping of functions when cross compiling. See + # http://wiki.osdev.org/Cross-Porting_Software#Gnulib + # https://gitlab.com/sortix/sortix/wikis/Gnulib + # https://github.com/termux/termux-packages/issues/76 + local AVOID_GNULIB="" + AVOID_GNULIB+=" ac_cv_func_nl_langinfo=yes" + AVOID_GNULIB+=" ac_cv_func_calloc_0_nonnull=yes" + AVOID_GNULIB+=" ac_cv_func_chown_works=yes" + AVOID_GNULIB+=" ac_cv_func_getgroups_works=yes" + AVOID_GNULIB+=" ac_cv_func_malloc_0_nonnull=yes" + AVOID_GNULIB+=" ac_cv_func_posix_spawn=no" + AVOID_GNULIB+=" ac_cv_func_posix_spawnp=no" + AVOID_GNULIB+=" ac_cv_func_realloc_0_nonnull=yes" + AVOID_GNULIB+=" am_cv_func_working_getline=yes" + AVOID_GNULIB+=" gl_cv_func_dup2_works=yes" + AVOID_GNULIB+=" gl_cv_func_fcntl_f_dupfd_cloexec=yes" + AVOID_GNULIB+=" gl_cv_func_fcntl_f_dupfd_works=yes" + AVOID_GNULIB+=" gl_cv_func_fnmatch_posix=yes" + AVOID_GNULIB+=" gl_cv_func_getcwd_abort_bug=no" + AVOID_GNULIB+=" gl_cv_func_getcwd_null=yes" + AVOID_GNULIB+=" gl_cv_func_getcwd_path_max=yes" + AVOID_GNULIB+=" gl_cv_func_getcwd_posix_signature=yes" + AVOID_GNULIB+=" gl_cv_func_gettimeofday_clobber=no" + AVOID_GNULIB+=" gl_cv_func_gettimeofday_posix_signature=yes" + AVOID_GNULIB+=" gl_cv_func_link_works=yes" + AVOID_GNULIB+=" gl_cv_func_lstat_dereferences_slashed_symlink=yes" + AVOID_GNULIB+=" gl_cv_func_malloc_0_nonnull=yes" + AVOID_GNULIB+=" gl_cv_func_memchr_works=yes" + AVOID_GNULIB+=" gl_cv_func_mkdir_trailing_dot_works=yes" + AVOID_GNULIB+=" gl_cv_func_mkdir_trailing_slash_works=yes" + AVOID_GNULIB+=" gl_cv_func_mkfifo_works=yes" + AVOID_GNULIB+=" gl_cv_func_mknod_works=yes" + AVOID_GNULIB+=" gl_cv_func_realpath_works=yes" + AVOID_GNULIB+=" gl_cv_func_select_detects_ebadf=yes" + AVOID_GNULIB+=" gl_cv_func_snprintf_posix=yes" + AVOID_GNULIB+=" gl_cv_func_snprintf_retval_c99=yes" + AVOID_GNULIB+=" gl_cv_func_snprintf_truncation_c99=yes" + AVOID_GNULIB+=" gl_cv_func_stat_dir_slash=yes" + AVOID_GNULIB+=" gl_cv_func_stat_file_slash=yes" + AVOID_GNULIB+=" gl_cv_func_strerror_0_works=yes" + AVOID_GNULIB+=" gl_cv_func_strtold_works=yes" + AVOID_GNULIB+=" gl_cv_func_symlink_works=yes" + AVOID_GNULIB+=" gl_cv_func_tzset_clobber=no" + AVOID_GNULIB+=" gl_cv_func_unlink_honors_slashes=yes" + AVOID_GNULIB+=" gl_cv_func_unlink_honors_slashes=yes" + AVOID_GNULIB+=" gl_cv_func_vsnprintf_posix=yes" + AVOID_GNULIB+=" gl_cv_func_vsnprintf_zerosize_c99=yes" + AVOID_GNULIB+=" gl_cv_func_wcrtomb_works=yes" + AVOID_GNULIB+=" gl_cv_func_wcwidth_works=yes" + AVOID_GNULIB+=" gl_cv_func_working_getdelim=yes" + AVOID_GNULIB+=" gl_cv_func_working_mkstemp=yes" + AVOID_GNULIB+=" gl_cv_func_working_mktime=yes" + AVOID_GNULIB+=" gl_cv_func_working_strerror=yes" + AVOID_GNULIB+=" gl_cv_header_working_fcntl_h=yes" + AVOID_GNULIB+=" gl_cv_C_locale_sans_EILSEQ=yes" + + # NOTE: We do not want to quote AVOID_GNULIB as we want word expansion. + # shellcheck disable=SC2086 + env $AVOID_GNULIB "$TERMUX_PKG_SRCDIR/configure" \ + --disable-dependency-tracking \ + --prefix=$TERMUX_PREFIX \ + --libdir=$TERMUX_PREFIX/lib \ + --sbindir=$TERMUX_PREFIX/bin \ + --disable-rpath --disable-rpath-hack \ + $HOST_FLAG \ + $TERMUX_PKG_EXTRA_CONFIGURE_ARGS \ + $DISABLE_NLS \ + $ENABLE_SHARED \ + $ENABLE_STATIC \ + $LIBEXEC_FLAG \ + $QUIET_BUILD \ + || (cat config.log && false) +} diff --git a/scripts/build/configure/termux_step_configure_cmake.sh b/scripts/build/configure/termux_step_configure_cmake.sh new file mode 100644 index 000000000..03c56244e --- /dev/null +++ b/scripts/build/configure/termux_step_configure_cmake.sh @@ -0,0 +1,51 @@ +termux_step_configure_cmake() { + if [ "$TERMUX_CMAKE_BUILD" = Ninja ]; then + MAKE_PROGRAM_PATH=$(command -v ninja) + else + MAKE_PROGRAM_PATH=$(command -v make) + fi + BUILD_TYPE=Release + test "$TERMUX_DEBUG_BUILD" == "true" && BUILD_TYPE=Debug + CMAKE_PROC=$TERMUX_ARCH + test $CMAKE_PROC == "arm" && CMAKE_PROC='armv7-a' + + local CMAKE_ADDITIONAL_ARGS=() + if [ "$TERMUX_ON_DEVICE_BUILD" = "false" ]; then + CXXFLAGS+=" --target=$CCTERMUX_HOST_PLATFORM" + CFLAGS+=" --target=$CCTERMUX_HOST_PLATFORM" + LDFLAGS+=" --target=$CCTERMUX_HOST_PLATFORM" + + CMAKE_ADDITIONAL_ARGS+=("-DCMAKE_CROSSCOMPILING=True") + CMAKE_ADDITIONAL_ARGS+=("-DCMAKE_LINKER=$TERMUX_STANDALONE_TOOLCHAIN/bin/$LD $LDFLAGS") + CMAKE_ADDITIONAL_ARGS+=("-DCMAKE_SYSTEM_NAME=Android") + CMAKE_ADDITIONAL_ARGS+=("-DCMAKE_SYSTEM_VERSION=$TERMUX_PKG_API_LEVEL") + CMAKE_ADDITIONAL_ARGS+=("-DCMAKE_SYSTEM_PROCESSOR=$CMAKE_PROC") + CMAKE_ADDITIONAL_ARGS+=("-DCMAKE_ANDROID_STANDALONE_TOOLCHAIN=$TERMUX_STANDALONE_TOOLCHAIN") + else + CMAKE_ADDITIONAL_ARGS+=("-DCMAKE_LINKER=$(command -v $LD) $LDFLAGS") + fi + + # XXX: CMAKE_{AR,RANLIB} needed for at least jsoncpp build to not + # pick up cross compiled binutils tool in $TERMUX_PREFIX/bin: + cmake -G "$TERMUX_CMAKE_BUILD" "$TERMUX_PKG_SRCDIR" \ + -DCMAKE_AR="$(command -v $AR)" \ + -DCMAKE_UNAME="$(command -v uname)" \ + -DCMAKE_RANLIB="$(command -v $RANLIB)" \ + -DCMAKE_STRIP="$(command -v $STRIP)" \ + -DCMAKE_BUILD_TYPE=$BUILD_TYPE \ + -DCMAKE_C_FLAGS="$CFLAGS $CPPFLAGS" \ + -DCMAKE_CXX_FLAGS="$CXXFLAGS $CPPFLAGS" \ + -DCMAKE_FIND_ROOT_PATH=$TERMUX_PREFIX \ + -DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER \ + -DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY \ + -DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=ONLY \ + -DCMAKE_INSTALL_PREFIX=$TERMUX_PREFIX \ + -DCMAKE_INSTALL_LIBDIR=lib \ + -DCMAKE_MAKE_PROGRAM=$MAKE_PROGRAM_PATH \ + -DCMAKE_SKIP_INSTALL_RPATH=ON \ + -DCMAKE_USE_SYSTEM_LIBRARIES=True \ + -DDOXYGEN_EXECUTABLE= \ + -DBUILD_TESTING=OFF \ + "${CMAKE_ADDITIONAL_ARGS[@]}" \ + $TERMUX_PKG_EXTRA_CONFIGURE_ARGS +} diff --git a/scripts/build/configure/termux_step_configure_haskell_build.sh b/scripts/build/configure/termux_step_configure_haskell_build.sh new file mode 100644 index 000000000..13a155888 --- /dev/null +++ b/scripts/build/configure/termux_step_configure_haskell_build.sh @@ -0,0 +1,144 @@ +# shellcheck shell=bash +termux_step_configure_haskell_build() { + termux_setup_jailbreak_cabal + printf "%s" "Jailbreaking Cabal file..." + if jailbreak-cabal "${TERMUX_PKG_SRCDIR}"/*.cabal; then + echo "done." + else + termux_error_exit "failed." + fi + + ENABLE_SHARED="--enable-shared" + if [[ "${TERMUX_PKG_EXTRA_CONFIGURE_ARGS}" != "${TERMUX_PKG_EXTRA_CONFIGURE_ARGS/--disable-shared/}" ]]; then + ENABLE_SHARED="" + fi + + DYNAMIC_EXECUTABLE=" + --ghc-options=-dynamic + --enable-executable-dynamic + --disable-library-vanilla + " + if [[ "${TERMUX_PKG_EXTRA_CONFIGURE_ARGS}" != "${TERMUX_PKG_EXTRA_CONFIGURE_ARGS/--disable-executable-dynamic/}" ]]; then + DYNAMIC_EXECUTABLE="" + fi + + HOST_FLAG="--host=${TERMUX_HOST_PLATFORM}" + if [[ "${TERMUX_PKG_EXTRA_CONFIGURE_ARGS}" != "${TERMUX_PKG_EXTRA_CONFIGURE_ARGS/--host=/}" ]]; then + HOST_FLAG="" + fi + + LIBEXEC_FLAG="--libexecdir=${TERMUX_PREFIX}/libexec" + if [[ "${TERMUX_PKG_EXTRA_CONFIGURE_ARGS}" != "${TERMUX_PKG_EXTRA_CONFIGURE_ARGS/--libexecdir=/}" ]]; then + LIBEXEC_FLAG="" + fi + + QUIET_BUILD= + if [[ "${TERMUX_QUIET_BUILD}" = true ]]; then + QUIET_BUILD="-v0" + fi + + LIB_STRIPPING="--enable-library-stripping" + if [[ "${TERMUX_PKG_EXTRA_CONFIGURE_ARGS}" != "${TERMUX_PKG_EXTRA_CONFIGURE_ARGS/--disable-library-stripping=/}" ]] || [[ "${TERMUX_DEBUG_BUILD}" = true ]]; then + LIB_STRIPPING="" + fi + + EXECUTABLE_STRIPPING="--enable-executable-stripping" + if [[ "${TERMUX_PKG_EXTRA_CONFIGURE_ARGS}" != "${TERMUX_PKG_EXTRA_CONFIGURE_ARGS/--disable-executable-stripping=/}" ]] || [[ "${TERMUX_DEBUG_BUILD}" = true ]]; then + EXECUTABLE_STRIPPING="" + fi + + SPLIT_SECTIONS="--enable-split-sections" + if [[ "${TERMUX_PKG_EXTRA_CONFIGURE_ARGS}" != "${TERMUX_PKG_EXTRA_CONFIGURE_ARGS/--disable-split-sections=/}" ]]; then + SPLIT_SECTIONS="" + fi + + # Avoid gnulib wrapping of functions when cross compiling. See + # http://wiki.osdev.org/Cross-Porting_Software#Gnulib + # https://gitlab.com/sortix/sortix/wikis/Gnulib + # https://github.com/termux/termux-packages/issues/76 + AVOID_GNULIB="" + AVOID_GNULIB+=" ac_cv_func_nl_langinfo=yes" + AVOID_GNULIB+=" ac_cv_func_calloc_0_nonnull=yes" + AVOID_GNULIB+=" ac_cv_func_chown_works=yes" + AVOID_GNULIB+=" ac_cv_func_getgroups_works=yes" + AVOID_GNULIB+=" ac_cv_func_malloc_0_nonnull=yes" + AVOID_GNULIB+=" ac_cv_func_posix_spawn=no" + AVOID_GNULIB+=" ac_cv_func_posix_spawnp=no" + AVOID_GNULIB+=" ac_cv_func_realloc_0_nonnull=yes" + AVOID_GNULIB+=" am_cv_func_working_getline=yes" + AVOID_GNULIB+=" gl_cv_func_dup2_works=yes" + AVOID_GNULIB+=" gl_cv_func_fcntl_f_dupfd_cloexec=yes" + AVOID_GNULIB+=" gl_cv_func_fcntl_f_dupfd_works=yes" + AVOID_GNULIB+=" gl_cv_func_fnmatch_posix=yes" + AVOID_GNULIB+=" gl_cv_func_getcwd_abort_bug=no" + AVOID_GNULIB+=" gl_cv_func_getcwd_null=yes" + AVOID_GNULIB+=" gl_cv_func_getcwd_path_max=yes" + AVOID_GNULIB+=" gl_cv_func_getcwd_posix_signature=yes" + AVOID_GNULIB+=" gl_cv_func_gettimeofday_clobber=no" + AVOID_GNULIB+=" gl_cv_func_gettimeofday_posix_signature=yes" + AVOID_GNULIB+=" gl_cv_func_link_works=yes" + AVOID_GNULIB+=" gl_cv_func_lstat_dereferences_slashed_symlink=yes" + AVOID_GNULIB+=" gl_cv_func_malloc_0_nonnull=yes" + AVOID_GNULIB+=" gl_cv_func_memchr_works=yes" + AVOID_GNULIB+=" gl_cv_func_mkdir_trailing_dot_works=yes" + AVOID_GNULIB+=" gl_cv_func_mkdir_trailing_slash_works=yes" + AVOID_GNULIB+=" gl_cv_func_mkfifo_works=yes" + AVOID_GNULIB+=" gl_cv_func_mknod_works=yes" + AVOID_GNULIB+=" gl_cv_func_realpath_works=yes" + AVOID_GNULIB+=" gl_cv_func_select_detects_ebadf=yes" + AVOID_GNULIB+=" gl_cv_func_snprintf_posix=yes" + AVOID_GNULIB+=" gl_cv_func_snprintf_retval_c99=yes" + AVOID_GNULIB+=" gl_cv_func_snprintf_truncation_c99=yes" + AVOID_GNULIB+=" gl_cv_func_stat_dir_slash=yes" + AVOID_GNULIB+=" gl_cv_func_stat_file_slash=yes" + AVOID_GNULIB+=" gl_cv_func_strerror_0_works=yes" + AVOID_GNULIB+=" gl_cv_func_strtold_works=yes" + AVOID_GNULIB+=" gl_cv_func_symlink_works=yes" + AVOID_GNULIB+=" gl_cv_func_tzset_clobber=no" + AVOID_GNULIB+=" gl_cv_func_unlink_honors_slashes=yes" + AVOID_GNULIB+=" gl_cv_func_unlink_honors_slashes=yes" + AVOID_GNULIB+=" gl_cv_func_vsnprintf_posix=yes" + AVOID_GNULIB+=" gl_cv_func_vsnprintf_zerosize_c99=yes" + AVOID_GNULIB+=" gl_cv_func_wcrtomb_works=yes" + AVOID_GNULIB+=" gl_cv_func_wcwidth_works=yes" + AVOID_GNULIB+=" gl_cv_func_working_getdelim=yes" + AVOID_GNULIB+=" gl_cv_func_working_mkstemp=yes" + AVOID_GNULIB+=" gl_cv_func_working_mktime=yes" + AVOID_GNULIB+=" gl_cv_func_working_strerror=yes" + AVOID_GNULIB+=" gl_cv_header_working_fcntl_h=yes" + AVOID_GNULIB+=" gl_cv_C_locale_sans_EILSEQ=yes" + + # NOTE: We do not want to quote AVOID_GNULIB as we want word expansion. + # shellcheck disable=SC2086 + # shellcheck disable=SC2250,SC2154,SC2248,SC2312 + env $AVOID_GNULIB termux-ghc-setup configure \ + $TERMUX_HASKELL_OPTIMISATION \ + --prefix=$TERMUX_PREFIX \ + --configure-option=--disable-rpath \ + --configure-option=--disable-rpath-hack \ + --configure-option=--host=$HOST_FLAG \ + --ghc-option=-optl-Wl,-rpath=$TERMUX_PREFIX/lib \ + --ghc-option=-optl-Wl,--enable-new-dtags \ + --with-compiler="$(command -v termux-ghc)" \ + --with-ghc-pkg="$(command -v termux-ghc-pkg)" \ + --with-hsc2hs="$(command -v termux-hsc2hs)" \ + --hsc2hs-option=--cross-compile \ + --with-ld=$LD \ + --with-strip=$STRIP \ + --with-ar=$AR \ + --with-pkg-config=$PKG_CONFIG \ + --with-happy="$(command -v happy)" \ + --with-alex="$(command -v alex)" \ + --extra-include-dirs=$TERMUX_PREFIX/include \ + --extra-lib-dirs=$TERMUX_PREFIX/lib \ + --disable-tests \ + $TERMUX_HASKELL_LLVM_BACKEND \ + $SPLIT_SECTIONS \ + $EXECUTABLE_STRIPPING \ + $LIB_STRIPPING \ + $TERMUX_PKG_EXTRA_CONFIGURE_ARGS \ + $ENABLE_SHARED \ + $QUIET_BUILD \ + $LIBEXEC_FLAG \ + $DYNAMIC_EXECUTABLE +} diff --git a/scripts/build/configure/termux_step_configure_meson.sh b/scripts/build/configure/termux_step_configure_meson.sh new file mode 100644 index 000000000..0d7956fa0 --- /dev/null +++ b/scripts/build/configure/termux_step_configure_meson.sh @@ -0,0 +1,12 @@ +termux_step_configure_meson() { + termux_setup_meson + CC=gcc CXX=g++ CFLAGS= CXXFLAGS= CPPFLAGS= LDFLAGS= $TERMUX_MESON \ + $TERMUX_PKG_SRCDIR \ + $TERMUX_PKG_BUILDDIR \ + --cross-file $TERMUX_MESON_CROSSFILE \ + --prefix $TERMUX_PREFIX \ + --libdir lib \ + --buildtype minsize \ + --strip \ + $TERMUX_PKG_EXTRA_CONFIGURE_ARGS +} diff --git a/scripts/build/get_source/termux_download_src_archive.sh b/scripts/build/get_source/termux_download_src_archive.sh new file mode 100644 index 000000000..e74b691e1 --- /dev/null +++ b/scripts/build/get_source/termux_download_src_archive.sh @@ -0,0 +1,16 @@ +termux_download_src_archive() { + local PKG_SRCURL=(${TERMUX_PKG_SRCURL[@]}) + local PKG_SHA256=(${TERMUX_PKG_SHA256[@]}) + if [ ! ${#PKG_SRCURL[@]} == ${#PKG_SHA256[@]} ] && [ ! ${#PKG_SHA256[@]} == 0 ]; then + termux_error_exit "Error: length of TERMUX_PKG_SRCURL isn't equal to length of TERMUX_PKG_SHA256." + fi + + for i in $(seq 0 $(( ${#PKG_SRCURL[@]}-1 ))); do + local file="$TERMUX_PKG_CACHEDIR/$(basename "${PKG_SRCURL[$i]}")" + if [ "${PKG_SHA256[$i]}" == "" ]; then + termux_download "${PKG_SRCURL[$i]}" "$file" + else + termux_download "${PKG_SRCURL[$i]}" "$file" "${PKG_SHA256[$i]}" + fi + done +} diff --git a/scripts/build/get_source/termux_git_clone_src.sh b/scripts/build/get_source/termux_git_clone_src.sh new file mode 100644 index 000000000..5b042fffa --- /dev/null +++ b/scripts/build/get_source/termux_git_clone_src.sh @@ -0,0 +1,27 @@ +termux_git_clone_src() { + local CHECKED_OUT_FOLDER=$TERMUX_PKG_TMPDIR/checkout-$TERMUX_PKG_VERSION + local TMP_CHECKOUT=$TERMUX_PKG_CACHEDIR/tmp-checkout + + # If user aborts git clone step here the folder needs to be removed + # manually. IMO this is better than git cloning the src everytime + if [ ! -d $CHECKED_OUT_FOLDER ] && [ ! -d $TMP_CHECKOUT ]; then + if [ "$TERMUX_PKG_GIT_BRANCH" == "" ]; then + TERMUX_PKG_GIT_BRANCH=v$TERMUX_PKG_VERSION + fi + git clone --depth 1 \ + --branch $TERMUX_PKG_GIT_BRANCH \ + $TERMUX_PKG_SRCURL \ + $TMP_CHECKOUT + cd $TMP_CHECKOUT + + git submodule update --init --recursive + cd .. + fi + + if [ ! -d $CHECKED_OUT_FOLDER ]; then + cp -Rf $TMP_CHECKOUT $CHECKED_OUT_FOLDER + fi + + rm -rf $TERMUX_PKG_SRCDIR + cp -Rf $CHECKED_OUT_FOLDER $TERMUX_PKG_SRCDIR +} diff --git a/scripts/build/get_source/termux_step_get_source.sh b/scripts/build/get_source/termux_step_get_source.sh new file mode 100644 index 000000000..54d7c68be --- /dev/null +++ b/scripts/build/get_source/termux_step_get_source.sh @@ -0,0 +1,15 @@ +termux_step_get_source() { + : "${TERMUX_PKG_SRCURL:=""}" + + if [ "${TERMUX_PKG_SRCURL: -4}" == ".git" ]; then + termux_git_clone_src + else + if [ -z "${TERMUX_PKG_SRCURL}" ] || [ "${TERMUX_PKG_SKIP_SRC_EXTRACT-false}" = "true" ] || [ "$TERMUX_PKG_METAPACKAGE" = "true" ]; then + mkdir -p "$TERMUX_PKG_SRCDIR" + return + fi + termux_download_src_archive + cd $TERMUX_PKG_TMPDIR + termux_extract_src_archive + fi +} diff --git a/scripts/build/get_source/termux_unpack_src_archive.sh b/scripts/build/get_source/termux_unpack_src_archive.sh new file mode 100644 index 000000000..320b28ff1 --- /dev/null +++ b/scripts/build/get_source/termux_unpack_src_archive.sh @@ -0,0 +1,23 @@ +termux_extract_src_archive() { + # STRIP=1 extracts archives straight into TERMUX_PKG_SRCDIR while STRIP=0 puts them in subfolders. zip has same behaviour per default + # If this isn't desired then this can be fixed in termux_step_post_get_source. + local STRIP=1 + local PKG_SRCURL=(${TERMUX_PKG_SRCURL[@]}) + local PKG_SHA256=(${TERMUX_PKG_SHA256[@]}) + for i in $(seq 0 $(( ${#PKG_SRCURL[@]}-1 ))); do + local file="$TERMUX_PKG_CACHEDIR/$(basename "${PKG_SRCURL[$i]}")" + local folder + set +o pipefail + if [ "${file##*.}" = zip ]; then + folder=$(unzip -qql "$file" | head -n1 | tr -s ' ' | cut -d' ' -f5-) + rm -Rf $folder + unzip -q "$file" + mv $folder "$TERMUX_PKG_SRCDIR" + else + test "$i" -gt 0 && STRIP=0 + mkdir -p "$TERMUX_PKG_SRCDIR" + tar xf "$file" -C "$TERMUX_PKG_SRCDIR" --strip-components=$STRIP + fi + set -o pipefail + done +} diff --git a/scripts/build/setup/meson_libintl.patch b/scripts/build/setup/meson_libintl.patch new file mode 100644 index 000000000..35da1a9f9 --- /dev/null +++ b/scripts/build/setup/meson_libintl.patch @@ -0,0 +1,36 @@ +# Always return true for libintl check. + +--- misc.py.orig 2022-05-24 23:37:10.802388776 +0530 ++++ ./mesonbuild/dependencies/misc.py 2022-05-24 23:39:14.342388729 +0530 +@@ -471,25 +471,18 @@ + class IntlBuiltinDependency(BuiltinDependency): + def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]): + super().__init__(name, env, kwargs) +- +- if self.clib_compiler.has_function('ngettext', '', env)[0]: +- self.is_found = True ++ self.is_found = True + + + class IntlSystemDependency(SystemDependency): + def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]): + super().__init__(name, env, kwargs) ++ self.is_found = True + +- h = self.clib_compiler.has_header('libintl.h', '', env) +- self.link_args = self.clib_compiler.find_library('intl', env, [], self.libtype) +- +- if h[0] and self.link_args: +- self.is_found = True +- +- if self.static: +- if not self._add_sub_dependency(iconv_factory(env, self.for_machine, {'static': True})): +- self.is_found = False +- return ++ if self.static: ++ if not self._add_sub_dependency(iconv_factory(env, self.for_machine, {'static': True})): ++ self.is_found = False ++ return + + + @factory_methods({DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.SYSTEM}) diff --git a/scripts/build/setup/termux_setup_cabal.sh b/scripts/build/setup/termux_setup_cabal.sh new file mode 100644 index 000000000..a57dcdd4d --- /dev/null +++ b/scripts/build/setup/termux_setup_cabal.sh @@ -0,0 +1,36 @@ +# shellcheck shell=bash +termux_setup_cabal() { + if [[ "${TERMUX_ON_DEVICE_BUILD}" == "false" ]]; then + local TERMUX_CABAL_VERSION=3.6.2.0 + local TERMUX_CABAL_TAR="${TERMUX_COMMON_CACHEDIR}/cabal-${TERMUX_CABAL_VERSION}.tar.xz" + + local TERMUX_CABAL_RUNTIME_FOLDER + + if [[ "${TERMUX_PACKAGES_OFFLINE-false}" == "true" ]]; then + TERMUX_CABAL_RUNTIME_FOLDER="${TERMUX_SCRIPTDIR}/build-tools/cabal-${TERMUX_CABAL_VERSION}-runtime" + else + TERMUX_CABAL_RUNTIME_FOLDER="${TERMUX_COMMON_CACHEDIR}/cabal-${TERMUX_CABAL_VERSION}-runtime" + fi + + export PATH="${TERMUX_CABAL_RUNTIME_FOLDER}:${PATH}" + + [[ -d "${TERMUX_CABAL_RUNTIME_FOLDER}" ]] && return + + termux_download "https://github.com/MrAdityaAlok/ghc-cross-tools/releases/download/cabal-install-v${TERMUX_CABAL_VERSION}/cabal-install-${TERMUX_CABAL_VERSION}.tar.xz" \ + "${TERMUX_CABAL_TAR}" \ + "f433e99cb3ff85239bd633f2ae2a370bfb7103f9db80e38199e0fda27897bdfe" + + mkdir -p "${TERMUX_CABAL_RUNTIME_FOLDER}" + tar xf "${TERMUX_CABAL_TAR}" -C "${TERMUX_CABAL_RUNTIME_FOLDER}" + rm "${TERMUX_CABAL_TAR}" + + cabal update + + else + if [[ "${TERMUX_APP_PACKAGE_MANAGER}" == "apt" ]] && "$(dpkg-query -W -f '${db:Status-Status}\n' cabal-install 2>/dev/null)" != "installed" || + [[ "${TERMUX_APP_PACKAGE_MANAGER}" == "pacman" ]] && ! "$(pacman -Q cabal-install 2>/dev/null)"; then + echo "Package 'cabal-install' is not installed." + exit 1 + fi + fi +} diff --git a/scripts/build/setup/termux_setup_cmake.sh b/scripts/build/setup/termux_setup_cmake.sh new file mode 100644 index 000000000..bc1668510 --- /dev/null +++ b/scripts/build/setup/termux_setup_cmake.sh @@ -0,0 +1,42 @@ +termux_setup_cmake() { + local TERMUX_CMAKE_MAJORVESION=3.23 + local TERMUX_CMAKE_MINORVERSION=2 + local TERMUX_CMAKE_VERSION=$TERMUX_CMAKE_MAJORVESION.$TERMUX_CMAKE_MINORVERSION + local TERMUX_CMAKE_TARNAME=cmake-${TERMUX_CMAKE_VERSION}-linux-x86_64.tar.gz + local TERMUX_CMAKE_TARFILE=$TERMUX_PKG_TMPDIR/$TERMUX_CMAKE_TARNAME + local TERMUX_CMAKE_FOLDER + + if [ "${TERMUX_PACKAGES_OFFLINE-false}" = "true" ]; then + TERMUX_CMAKE_FOLDER=$TERMUX_SCRIPTDIR/build-tools/cmake-$TERMUX_CMAKE_VERSION + else + TERMUX_CMAKE_FOLDER=$TERMUX_COMMON_CACHEDIR/cmake-$TERMUX_CMAKE_VERSION + fi + + if [ "$TERMUX_ON_DEVICE_BUILD" = "false" ]; then + if [ ! -d "$TERMUX_CMAKE_FOLDER" ]; then + termux_download https://cmake.org/files/v$TERMUX_CMAKE_MAJORVESION/$TERMUX_CMAKE_TARNAME \ + "$TERMUX_CMAKE_TARFILE" \ + aaced6f745b86ce853661a595bdac6c5314a60f8181b6912a0a4920acfa32708 + rm -Rf "$TERMUX_PKG_TMPDIR/cmake-${TERMUX_CMAKE_VERSION}-linux-x86_64" + tar xf "$TERMUX_CMAKE_TARFILE" -C "$TERMUX_PKG_TMPDIR" + mv "$TERMUX_PKG_TMPDIR/cmake-${TERMUX_CMAKE_VERSION}-linux-x86_64" \ + "$TERMUX_CMAKE_FOLDER" + fi + + export PATH=$TERMUX_CMAKE_FOLDER/bin:$PATH + else + if [[ "$TERMUX_APP_PACKAGE_MANAGER" = "apt" && "$(dpkg-query -W -f '${db:Status-Status}\n' cmake 2>/dev/null)" != "installed" ]] || + [[ "$TERMUX_APP_PACKAGE_MANAGER" = "pacman" && ! "$(pacman -Q cmake 2>/dev/null)" ]]; then + echo "Package 'cmake' is not installed." + echo "You can install it with" + echo + echo " pkg install cmake" + echo + echo " pacman -S cmake" + echo + exit 1 + fi + fi + + export CMAKE_INSTALL_ALWAYS=1 +} diff --git a/scripts/build/setup/termux_setup_ghc.sh b/scripts/build/setup/termux_setup_ghc.sh new file mode 100644 index 000000000..36583a57b --- /dev/null +++ b/scripts/build/setup/termux_setup_ghc.sh @@ -0,0 +1,67 @@ +# shellcheck shell=bash +# Utility function to setup a GHC toolchain. +termux_setup_ghc() { + if [ "$TERMUX_ON_DEVICE_BUILD" = "false" ]; then + local TERMUX_GHC_VERSION=8.10.7 + local TERMUX_GHC_TEMP_FOLDER="${TERMUX_COMMON_CACHEDIR}/ghc-${TERMUX_GHC_VERSION}" + local TERMUX_GHC_TAR="${TERMUX_GHC_TEMP_FOLDER}.tar.xz" + local TERMUX_GHC_RUNTIME_FOLDER + + if [ "${TERMUX_PACKAGES_OFFLINE-false}" = "true" ]; then + TERMUX_GHC_RUNTIME_FOLDER="${TERMUX_SCRIPTDIR}/build-tools/ghc-${TERMUX_GHC_VERSION}-runtime" + else + TERMUX_GHC_RUNTIME_FOLDER="${TERMUX_COMMON_CACHEDIR}/ghc-${TERMUX_GHC_VERSION}-runtime" + fi + + export PATH="$TERMUX_GHC_RUNTIME_FOLDER/bin:$PATH" + + [ -d "$TERMUX_GHC_RUNTIME_FOLDER" ] && return + + termux_download "https://downloads.haskell.org/~ghc/${TERMUX_GHC_VERSION}/ghc-${TERMUX_GHC_VERSION}-x86_64-deb10-linux.tar.xz" \ + "$TERMUX_GHC_TAR" \ + a13719bca87a0d3ac0c7d4157a4e60887009a7f1a8dbe95c4759ec413e086d30 + + rm -Rf "$TERMUX_GHC_TEMP_FOLDER" + tar xf "$TERMUX_GHC_TAR" -C "$TERMUX_COMMON_CACHEDIR" + + ( + set -e + unset CC CXX CFLAGS CXXFLAGS CPPFLAGS LDFLAGS AR AS CPP LD RANLIB READELF STRIP + cd "$TERMUX_GHC_TEMP_FOLDER" + ./configure --prefix="$TERMUX_GHC_RUNTIME_FOLDER" + make install + ) + + # Cabal passes a host string to the libraries' configure scripts that isn't valid. + # After this patch we need to always pass --configure-option=--host=${TERMUX_HOST_PLATFORM} + # to Setup.hs configure. + ( + CABAL_VERSION="3.6.2.0" + CABAL_TEMP_FOLDER="$(mktemp -d -t cabal-"${CABAL_VERSION}".XXXXXX)" + CABAL_TAR="${CABAL_TEMP_FOLDER}/cabal-${CABAL_VERSION}.tar.gz" + + termux_download \ + https://hackage.haskell.org/package/Cabal-"${CABAL_VERSION}"/Cabal-"${CABAL_VERSION}".tar.gz \ + "${CABAL_TAR}" \ + 9e903d06a7fb0893c6f303199e737a7d555fbb5e309be8bcc782b4eb2717bc42 + + tar xf "${CABAL_TAR}" -C "${CABAL_TEMP_FOLDER}" --strip-components=1 + + cd "${CABAL_TEMP_FOLDER}" + + sed -i 's/maybeHostFlag = i/maybeHostFlag = [] -- i/' src/Distribution/Simple.hs + + runhaskell Setup configure --prefix="${TERMUX_GHC_RUNTIME_FOLDER}" + runhaskell Setup build + runhaskell Setup install + ghc-pkg recache + ) + rm -Rf "$TERMUX_GHC_TEMP_FOLDER" "$TERMUX_GHC_TAR" + else + if [[ "$TERMUX_APP_PACKAGE_MANAGER" = "apt" && "$(dpkg-query -W -f '${db:Status-Status}\n' ghc 2>/dev/null)" != "installed" ]] || + [[ "$TERMUX_APP_PACKAGE_MANAGER" = "pacman" && ! "$(pacman -Q ghc 2>/dev/null)" ]]; then + echo "Package 'ghc' is not installed." + exit 1 + fi + fi +} diff --git a/scripts/build/setup/termux_setup_ghc_cross_compiler.sh b/scripts/build/setup/termux_setup_ghc_cross_compiler.sh new file mode 100644 index 000000000..c00728523 --- /dev/null +++ b/scripts/build/setup/termux_setup_ghc_cross_compiler.sh @@ -0,0 +1,149 @@ +# shellcheck shell=bash +__termux_haskell_register_packages() { + # Register dependency haskell packages with termux-ghc-pkg. + echo "Registering haskell packages with ghc-pkg...(if any)" + while read DEP DEP_DIR; do + if [[ -z $DEP ]]; then + continue + elif [[ "${DEP}" == "ERROR" ]]; then + termux_error_exit "Failed to find dependencies of ${TERMUX_PKG_NAME} [Context: ${FUNCNAME[0]}]" + fi + if [[ "${DEP/haskell-/}" != "${DEP}" ]]; then + sed "s|${TERMUX_PREFIX}/bin/ghc-pkg|$(command -v termux-ghc-pkg)|g" \ + "${TERMUX_PREFIX}/share/haskell/register/${DEP}.sh" | sh + termux-ghc-pkg recache + # NOTE: Above command rewrites a cache file at + # "${TERMUX_PREFIX}/lib/ghc-${TERMUX_GHC_VERSION}/package.conf.d". Since it is done after + # timestamp creation, we need to remove it in massage step. + fi + done <<<"$( + # shellcheck disable=SC2086 + cd "${TERMUX_SCRIPTDIR}" && + ./scripts/buildorder.py -i "${TERMUX_PKG_BUILDER_DIR}" ${TERMUX_PACKAGES_DIRECTORIES} || echo "ERROR" + )" +} + +__termux_haskell_setup_build_script() { + local runtime_folder="$1" + + if ! command -v termux-ghc-setup &>/dev/null; then + if [ "${TERMUX_ON_DEVICE_BUILD}" = false ]; then + local build_type="" + if ! cat "${TERMUX_PKG_SRCDIR}"/*.cabal | grep -wq "^[bB]uild-type:" || + cat "${TERMUX_PKG_SRCDIR}"/*.cabal | grep -wq '^[bB]uild-type:\s*[Ss]imple$'; then + build_type="simple" + elif cat "${TERMUX_PKG_SRCDIR}"/*.cabal | grep -wq '^[bB]uild-type:\s*[Cc]onfigure$'; then + build_type="configure" + elif cat "${TERMUX_PKG_SRCDIR}"/*.cabal | grep -wq '^[bB]uild-type:\s*[Mm]ake$'; then + build_type="make" + else + # Now, it must be a custom build. + # Compile custom Setup script with GHC and make it available in PATH. + termux_setup_ghc + ghc --make "${TERMUX_PKG_SRCDIR}/Setup" -o "${runtime_folder}/bin/termux-ghc-setup" + return + fi + + ln -sf "$runtime_folder/bin/${build_type}_setup" \ + "$runtime_folder/bin/termux-ghc-setup" + else + # On device, we always have ghc installed. So, always compile Setup script. + ghc --make "${TERMUX_PKG_SRCDIR}/Setup" -o "${runtime_folder}/bin/termux-ghc-setup" + fi + fi +} + +# Utility function to setup a GHC cross-compiler toolchain targeting Android. +termux_setup_ghc_cross_compiler() { + local TERMUX_GHC_VERSION="8.10.7" + local GHC_PREFIX="ghc-cross-${TERMUX_GHC_VERSION}-${TERMUX_ARCH}" + if [[ "${TERMUX_ON_DEVICE_BUILD}" == "false" ]]; then + local TERMUX_GHC_RUNTIME_FOLDER + + if [[ "${TERMUX_PACKAGES_OFFLINE-false}" == "true" ]]; then + TERMUX_GHC_RUNTIME_FOLDER="${TERMUX_SCRIPTDIR}/build-tools/${GHC_PREFIX}-runtime" + else + TERMUX_GHC_RUNTIME_FOLDER="${TERMUX_COMMON_CACHEDIR}/${GHC_PREFIX}-runtime" + fi + + local TERMUX_GHC_TAR="${TERMUX_COMMON_CACHEDIR}/${GHC_PREFIX}.tar.xz" + + export PATH="${TERMUX_GHC_RUNTIME_FOLDER}/bin:${PATH}" + + test -d "${TERMUX_PREFIX}/lib/ghc-${TERMUX_GHC_VERSION}" || + termux_error_exit "Package 'ghc-libs' is not installed. It is required by GHC cross-compiler." \ + "You should specify it in 'TERMUX_PKG_BUILD_DEPENDS'." + + if [[ -d "${TERMUX_GHC_RUNTIME_FOLDER}" ]]; then + __termux_haskell_setup_build_script "${TERMUX_GHC_RUNTIME_FOLDER}" + __termux_haskell_register_packages + return + fi + + local CHECKSUMS + CHECKSUMS="$( + cat <<-EOF + aarch64:0912e8c6a8f4b362198c26129bb55f8e76edfcfbf38bfaf8b025a46429e6a887 + arm:4f9acf98ee44eaebec6bce915507a934d1f880dd4c7ee679c075644e3bc41f78 + i686:289a04baa67b8cbef401aebf8f5ffef90735e5a5b6e00ce39a50b82c134fe51b + x86_64:b43b4c8b80210c2b17ad4547d6d007163052edbd662495e0010b1c9b17d4f865 + EOF + )" + + termux_download "https://github.com/MrAdityaAlok/ghc-cross-tools/releases/download/ghc-v${TERMUX_GHC_VERSION}/ghc-cross-bin-${TERMUX_GHC_VERSION}-${TERMUX_ARCH}.tar.xz" \ + "${TERMUX_GHC_TAR}" \ + "$(echo "${CHECKSUMS}" | grep -w "${TERMUX_ARCH}" | cut -d ':' -f 2)" + + mkdir -p "${TERMUX_GHC_RUNTIME_FOLDER}" + + tar -xf "${TERMUX_GHC_TAR}" -C "${TERMUX_GHC_RUNTIME_FOLDER}" + + # Replace ghc settings with settings of the cross compiler. + sed "s|\$topdir/bin/unlit|${TERMUX_GHC_RUNTIME_FOLDER}/lib/ghc-${TERMUX_GHC_VERSION}/bin/unlit|g" \ + "${TERMUX_GHC_RUNTIME_FOLDER}/lib/ghc-${TERMUX_GHC_VERSION}/settings" > \ + "${TERMUX_PREFIX}/lib/ghc-${TERMUX_GHC_VERSION}/settings" + # NOTE: Above command edits file in $TERMUX_PREFIX after timestamp is created, + # so we need to remove it in massage step. + + for tool in ghc ghc-pkg hsc2hs hp2ps ghci; do + _tool="${tool}" + [[ "${tool}" == "ghci" ]] && _tool="ghc" + sed -i "s|\$executablename|${TERMUX_GHC_RUNTIME_FOLDER}/lib/ghc-${TERMUX_GHC_VERSION}/bin/${_tool}|g" \ + "${TERMUX_GHC_RUNTIME_FOLDER}/bin/termux-${tool}" + done + + # GHC ships with old version, we use our own. + termux-ghc-pkg unregister Cabal + # NOTE: Above command rewrites a cache file at + # "${TERMUX_PREFIX}/lib/ghc-${TERMUX_GHC_VERSION}/package.conf.d". Since it is done after + # timestamp creation, we need to remove it in massage step. + + __termux_haskell_setup_build_script "${TERMUX_GHC_RUNTIME_FOLDER}" + __termux_haskell_register_packages + + rm "${TERMUX_GHC_TAR}" + else + + if [[ "${TERMUX_APP_PACKAGE_MANAGER}" == "apt" ]] && "$(dpkg-query -W -f '${db:Status-Status}\n' ghc 2>/dev/null)" != "installed" || + [[ "${TERMUX_APP_PACKAGE_MANAGER}" == "pacman" ]] && ! "$(pacman -Q ghc 2>/dev/null)"; then + echo "Package 'ghc' is not installed." + exit 1 + else + local ON_DEVICE_GHC_RUNTIME="${TERMUX_COMMON_CACHEDIR}/${GHC_PREFIX}-runtime" + export PATH="${ON_DEVICE_GHC_RUNTIME}/bin:${PATH}" + + if [[ -d "${ON_DEVICE_GHC_RUNTIME}" ]]; then + __termux_haskell_setup_build_script "${ON_DEVICE_GHC_RUNTIME}" + __termux_haskell_register_packages + return + fi + + mkdir -p "${ON_DEVICE_GHC_RUNTIME}"/bin + for tool in ghc ghc-pkg hsc2hs hp2ps ghci; do + ln -sf "${TERMUX_PREFIX}/bin/${tool}" "${ON_DEVICE_GHC_RUNTIME}/bin/termux-${tool}" + done + __termux_haskell_setup_build_script "${ON_DEVICE_GHC_RUNTIME}" + __termux_haskell_register_packages + fi + fi +} diff --git a/scripts/build/setup/termux_setup_gn.sh b/scripts/build/setup/termux_setup_gn.sh new file mode 100644 index 000000000..5ff45da93 --- /dev/null +++ b/scripts/build/setup/termux_setup_gn.sh @@ -0,0 +1,55 @@ +termux_setup_gn() { + termux_setup_ninja + local GN_COMMIT=53ef169800760fdc09f0773bf380fe99eaeab339 + local GN_TARFILE=$TERMUX_COMMON_CACHEDIR/gn_$GN_COMMIT.tar.gz + local GN_SOURCE=https://gn.googlesource.com/gn/+archive/$GN_COMMIT.tar.gz + + if [ "${TERMUX_PACKAGES_OFFLINE-false}" = "true" ]; then + GN_FOLDER=$TERMUX_SCRIPTDIR/build-tools/gn-$GN_COMMIT + else + GN_FOLDER=$TERMUX_COMMON_CACHEDIR/gn-$GN_COMMIT + fi + + if [ "$TERMUX_ON_DEVICE_BUILD" = "false" ]; then + if [ ! -d "$GN_FOLDER" ]; then + # FIXME: We would like to enable checksums when downloading + # tar files, but they change each time as the tar metadata + # differs: https://github.com/google/gitiles/issues/84 + termux_download \ + $GN_SOURCE \ + $GN_TARFILE \ + SKIP_CHECKSUM + mkdir -p $GN_FOLDER + tar xf $GN_TARFILE -C $GN_FOLDER + local LAST_PWD=$(pwd) + cd $GN_FOLDER + ( + unset CC CXX CFLAGS CXXFLAGS LD LDFLAGS AR AS CPP OBJCOPY OBJDUMP RANLIB READELF STRIP + ./build/gen.py \ + --no-last-commit-position + cat <<-EOF >./out/last_commit_position.h + #ifndef OUT_LAST_COMMIT_POSITION_H_ + #define OUT_LAST_COMMIT_POSITION_H_ + #define LAST_COMMIT_POSITION_NUM 1953 + #define LAST_COMMIT_POSITION "2034 ${GN_COMMIT:0:8}" + #endif // OUT_LAST_COMMIT_POSITION_H_ + EOF + ninja -C out/ + ) + cd $LAST_PWD + fi + export PATH=$GN_FOLDER/out:$PATH + else + if [[ "$TERMUX_APP_PACKAGE_MANAGER" = "apt" && "$(dpkg-query -W -f '${db:Status-Status}\n' gn 2>/dev/null)" != "installed" ]] || + [[ "$TERMUX_APP_PACKAGE_MANAGER" = "pacman" && ! "$(pacman -Q gn 2>/dev/null)" ]]; then + echo "Package 'gn' is not installed." + echo "You can install it with" + echo + echo " pkg install gn" + echo + echo " pacman -S gn" + echo + exit 1 + fi + fi +} diff --git a/scripts/build/setup/termux_setup_golang.sh b/scripts/build/setup/termux_setup_golang.sh new file mode 100644 index 000000000..ad1fa59e9 --- /dev/null +++ b/scripts/build/setup/termux_setup_golang.sh @@ -0,0 +1,47 @@ +# Utility function for golang-using packages to setup a go toolchain. +termux_setup_golang() { + if [ "$TERMUX_ON_DEVICE_BUILD" = "false" ]; then + local TERMUX_GO_VERSION=go1.18.3 + local TERMUX_GO_PLATFORM=linux-amd64 + + local TERMUX_BUILDGO_FOLDER + if [ "${TERMUX_PACKAGES_OFFLINE-false}" = "true" ]; then + TERMUX_BUILDGO_FOLDER=${TERMUX_SCRIPTDIR}/build-tools/${TERMUX_GO_VERSION} + else + TERMUX_BUILDGO_FOLDER=${TERMUX_COMMON_CACHEDIR}/${TERMUX_GO_VERSION} + fi + + export GOROOT=$TERMUX_BUILDGO_FOLDER + export PATH=${GOROOT}/bin:${PATH} + + if [ -d "$TERMUX_BUILDGO_FOLDER" ]; then return; fi + + local TERMUX_BUILDGO_TAR=$TERMUX_COMMON_CACHEDIR/${TERMUX_GO_VERSION}.${TERMUX_GO_PLATFORM}.tar.gz + rm -Rf "$TERMUX_COMMON_CACHEDIR/go" "$TERMUX_BUILDGO_FOLDER" + termux_download https://golang.org/dl/${TERMUX_GO_VERSION}.${TERMUX_GO_PLATFORM}.tar.gz \ + "$TERMUX_BUILDGO_TAR" \ + 956f8507b302ab0bb747613695cdae10af99bbd39a90cae522b7c0302cc27245 + + ( cd "$TERMUX_COMMON_CACHEDIR"; tar xf "$TERMUX_BUILDGO_TAR"; mv go "$TERMUX_BUILDGO_FOLDER"; rm "$TERMUX_BUILDGO_TAR" ) + + ( cd "$TERMUX_BUILDGO_FOLDER"; . ${TERMUX_SCRIPTDIR}/packages/golang/fix-hardcoded-etc-resolv-conf.sh ) + else + if [[ "$TERMUX_APP_PACKAGE_MANAGER" = "apt" && "$(dpkg-query -W -f '${db:Status-Status}\n' golang 2>/dev/null)" != "installed" ]] || + [[ "$TERMUX_APP_PACKAGE_MANAGER" = "pacman" && ! "$(pacman -Q golang 2>/dev/null)" ]]; then + echo "Package 'golang' is not installed." + echo "You can install it with" + echo + echo " pkg install golang" + echo + echo " pacman -S golang" + echo + echo "or build it from source with" + echo + echo " ./build-package.sh golang" + echo + exit 1 + fi + + export GOROOT="$TERMUX_PREFIX/lib/go" + fi +} diff --git a/scripts/build/setup/termux_setup_jailbreak_cabal.sh b/scripts/build/setup/termux_setup_jailbreak_cabal.sh new file mode 100644 index 000000000..c8c20e0a7 --- /dev/null +++ b/scripts/build/setup/termux_setup_jailbreak_cabal.sh @@ -0,0 +1,35 @@ +# shellcheck shell=bash +# Utility script to setup jailbreak-cabal script. It is used by haskell build system to remove version +# constraints in cabal files. +termux_setup_jailbreak_cabal() { + if [[ "${TERMUX_ON_DEVICE_BUILD}" == "false" ]]; then + local TERMUX_JAILBREAK_VERSION=1.3.5 + local TERMUX_JAILBREAK_TAR="${TERMUX_COMMON_CACHEDIR}/jailbreak-cabal-${TERMUX_JAILBREAK_VERSION}.tar.gz" + local TERMUX_JAILBREAK_RUNTIME_FOLDER + + if [[ "${TERMUX_PACKAGES_OFFLINE-false}" == "true" ]]; then + TERMUX_JAILBREAK_RUNTIME_FOLDER="${TERMUX_SCRIPTDIR}/build-tools/jailbreak-cabal-${TERMUX_JAILBREAK_VERSION}-runtime" + else + TERMUX_JAILBREAK_RUNTIME_FOLDER="${TERMUX_COMMON_CACHEDIR}/jailbreak-cabal-${TERMUX_JAILBREAK_VERSION}-runtime" + fi + + export PATH="${TERMUX_JAILBREAK_RUNTIME_FOLDER}:${PATH}" + + [[ -d "${TERMUX_JAILBREAK_RUNTIME_FOLDER}" ]] && return + + termux_download "https://github.com/MrAdityaAlok/ghc-cross-tools/releases/download/jailbreak-cabal-v${TERMUX_JAILBREAK_VERSION}/jailbreak-cabal-${TERMUX_JAILBREAK_VERSION}.tar.xz" \ + "${TERMUX_JAILBREAK_TAR}" \ + "8d1a8b8fadf48f4abf42da025d5cf843bd68e1b3c18ecacdc0cd0c9bd470c64e" + + mkdir -p "${TERMUX_JAILBREAK_RUNTIME_FOLDER}" + tar xf "${TERMUX_JAILBREAK_TAR}" -C "${TERMUX_JAILBREAK_RUNTIME_FOLDER}" + + rm "${TERMUX_JAILBREAK_TAR}" + else + if [[ "${TERMUX_APP_PACKAGE_MANAGER}" == "apt" ]] && "$(dpkg-query -W -f '${db:Status-Status}\n' jailbreak-cabal 2>/dev/null)" != "installed" || + [[ "${TERMUX_APP_PACKAGE_MANAGER}" = "pacman" ]] && ! "$(pacman -Q jailbreak-cabal 2>/dev/null)"; then + echo "Package 'jailbreak-cabal' is not installed." + exit 1 + fi + fi +} diff --git a/scripts/build/setup/termux_setup_meson.sh b/scripts/build/setup/termux_setup_meson.sh new file mode 100644 index 000000000..2bd191477 --- /dev/null +++ b/scripts/build/setup/termux_setup_meson.sh @@ -0,0 +1,118 @@ +termux_setup_meson() { + termux_setup_ninja + local MESON_VERSION=0.61.2 + local MESON_FOLDER + + if [ "${TERMUX_PACKAGES_OFFLINE-false}" = "true" ]; then + MESON_FOLDER=${TERMUX_SCRIPTDIR}/build-tools/meson-${MESON_VERSION} + else + MESON_FOLDER=${TERMUX_COMMON_CACHEDIR}/meson-${MESON_VERSION} + fi + + if [ ! -d "$MESON_FOLDER" ]; then + local MESON_TAR_NAME=meson-$MESON_VERSION.tar.gz + local MESON_TAR_FILE=$TERMUX_PKG_TMPDIR/$MESON_TAR_NAME + local MESON_TMP_FOLDER=$TERMUX_PKG_TMPDIR/meson-$MESON_VERSION + termux_download \ + "https://github.com/mesonbuild/meson/releases/download/$MESON_VERSION/meson-$MESON_VERSION.tar.gz" \ + "$MESON_TAR_FILE" \ + 0233a7f8d959079318f6052b0939c27f68a5de86ba601f25c9ee6869fb5f5889 + tar xf "$MESON_TAR_FILE" -C "$TERMUX_PKG_TMPDIR" + if [ "$MESON_VERSION" = "0.61.2" ]; then + local MESON_0_61_2_GTKDOC_PATCH_FILE=$TERMUX_PKG_TMPDIR/meson-0.61.2-gtkdoc.patch + termux_download \ + "https://github.com/mesonbuild/meson/commit/266e8acb5807b38a550cb5145cea0e19545a21d7.patch" \ + "$MESON_0_61_2_GTKDOC_PATCH_FILE" \ + 79ecf0e16f613396f43621a928df6c17e6260aa190c320e5c01adad94abd07ad + patch --silent -p1 -d "$MESON_TMP_FOLDER" < "$MESON_0_61_2_GTKDOC_PATCH_FILE" + fi + # Patch meson to always return true for libintl check. + patch --silent -p1 -d "$MESON_TMP_FOLDER" < "$TERMUX_SCRIPTDIR"/scripts/build/setup/meson_libintl.patch || { + echo "[${FUNCNAME[0]}]: Meson libintl patch failed. Exiting now." + exit 1 + } + + mv "$MESON_TMP_FOLDER" "$MESON_FOLDER" + fi + TERMUX_MESON="$MESON_FOLDER/meson.py" + TERMUX_MESON_CROSSFILE=$TERMUX_PKG_TMPDIR/meson-crossfile-$TERMUX_ARCH.txt + local MESON_CPU MESON_CPU_FAMILY + if [ "$TERMUX_ARCH" = "arm" ]; then + MESON_CPU_FAMILY="arm" + MESON_CPU="armv7" + elif [ "$TERMUX_ARCH" = "i686" ]; then + MESON_CPU_FAMILY="x86" + MESON_CPU="i686" + elif [ "$TERMUX_ARCH" = "x86_64" ]; then + MESON_CPU_FAMILY="x86_64" + MESON_CPU="x86_64" + elif [ "$TERMUX_ARCH" = "aarch64" ]; then + MESON_CPU_FAMILY="aarch64" + MESON_CPU="aarch64" + else + termux_error_exit "Unsupported arch: $TERMUX_ARCH" + fi + + local CONTENT="" + echo "[binaries]" > $TERMUX_MESON_CROSSFILE + echo "ar = '$AR'" >> $TERMUX_MESON_CROSSFILE + echo "c = '$CC'" >> $TERMUX_MESON_CROSSFILE + echo "cmake = 'cmake'" >> $TERMUX_MESON_CROSSFILE + echo "cpp = '$CXX'" >> $TERMUX_MESON_CROSSFILE + echo "ld = '$LD'" >> $TERMUX_MESON_CROSSFILE + echo "pkgconfig = '$PKG_CONFIG'" >> $TERMUX_MESON_CROSSFILE + echo "strip = '$STRIP'" >> $TERMUX_MESON_CROSSFILE + + echo '' >> $TERMUX_MESON_CROSSFILE + echo "[properties]" >> $TERMUX_MESON_CROSSFILE + echo "needs_exe_wrapper = true" >> $TERMUX_MESON_CROSSFILE + + echo '' >> $TERMUX_MESON_CROSSFILE + echo "[built-in options]" >> $TERMUX_MESON_CROSSFILE + + echo -n "c_args = [" >> $TERMUX_MESON_CROSSFILE + local word first=true + for word in $CFLAGS $CPPFLAGS; do + if [ "$first" = "true" ]; then + first=false + else + echo -n ", " >> $TERMUX_MESON_CROSSFILE + fi + echo -n "'$word'" >> $TERMUX_MESON_CROSSFILE + done + echo ']' >> $TERMUX_MESON_CROSSFILE + + echo -n "cpp_args = [" >> $TERMUX_MESON_CROSSFILE + local word first=true + for word in $CXXFLAGS $CPPFLAGS; do + if [ "$first" = "true" ]; then + first=false + else + echo -n ", " >> $TERMUX_MESON_CROSSFILE + fi + echo -n "'$word'" >> $TERMUX_MESON_CROSSFILE + done + echo ']' >> $TERMUX_MESON_CROSSFILE + + local property + for property in c_link_args cpp_link_args; do + echo -n "$property = [" >> $TERMUX_MESON_CROSSFILE + first=true + for word in $LDFLAGS; do + if [ "$first" = "true" ]; then + first=false + else + echo -n ", " >> $TERMUX_MESON_CROSSFILE + fi + echo -n "'$word'" >> $TERMUX_MESON_CROSSFILE + done + echo ']' >> $TERMUX_MESON_CROSSFILE + done + + echo '' >> $TERMUX_MESON_CROSSFILE + echo "[host_machine]" >> $TERMUX_MESON_CROSSFILE + echo "cpu_family = '$MESON_CPU_FAMILY'" >> $TERMUX_MESON_CROSSFILE + echo "cpu = '$MESON_CPU'" >> $TERMUX_MESON_CROSSFILE + echo "endian = 'little'" >> $TERMUX_MESON_CROSSFILE + echo "system = 'android'" >> $TERMUX_MESON_CROSSFILE +} diff --git a/scripts/build/setup/termux_setup_ninja.sh b/scripts/build/setup/termux_setup_ninja.sh new file mode 100644 index 000000000..4b10096d2 --- /dev/null +++ b/scripts/build/setup/termux_setup_ninja.sh @@ -0,0 +1,42 @@ +termux_setup_ninja() { + local NINJA_VERSION=1.10.2 + local NINJA_FOLDER + + if [ "${TERMUX_PACKAGES_OFFLINE-false}" = "true" ]; then + NINJA_FOLDER=${TERMUX_SCRIPTDIR}/build-tools/ninja-${NINJA_VERSION} + else + NINJA_FOLDER=${TERMUX_COMMON_CACHEDIR}/ninja-$NINJA_VERSION + fi + + if [ "$TERMUX_ON_DEVICE_BUILD" = "false" ]; then + if [ ! -x "$NINJA_FOLDER/ninja" ]; then + mkdir -p "$NINJA_FOLDER" + local NINJA_ZIP_FILE=$TERMUX_PKG_TMPDIR/ninja-$NINJA_VERSION.zip + termux_download https://github.com/ninja-build/ninja/releases/download/v$NINJA_VERSION/ninja-linux.zip \ + "$NINJA_ZIP_FILE" \ + 763464859c7ef2ea3a0a10f4df40d2025d3bb9438fcb1228404640410c0ec22d + unzip "$NINJA_ZIP_FILE" -d "$NINJA_FOLDER" + chmod 755 $NINJA_FOLDER/ninja + fi + export PATH=$NINJA_FOLDER:$PATH + else + local NINJA_PKG_VERSION=$(bash -c ". $TERMUX_SCRIPTDIR/packages/ninja/build.sh; echo \$TERMUX_PKG_VERSION") + if ([ ! -e "$TERMUX_BUILT_PACKAGES_DIRECTORY/ninja" ] || + [ "$(cat "$TERMUX_BUILT_PACKAGES_DIRECTORY/ninja")" != "$NINJA_PKG_VERSION" ]) && + ([[ "$TERMUX_APP_PACKAGE_MANAGER" = "apt" && "$(dpkg-query -W -f '${db:Status-Status}\n' ninja 2>/dev/null)" != "installed" ]] || + [[ "$TERMUX_APP_PACKAGE_MANAGER" = "pacman" && ! "$(pacman -Q ninja 2>/dev/null)" ]]); then + echo "Package 'ninja' is not installed." + echo "You can install it with" + echo + echo " pkg install ninja" + echo + echo " pacman -S ninja" + echo + echo "or build it from source with" + echo + echo " ./build-package.sh ninja" + echo + exit 1 + fi + fi +} diff --git a/scripts/build/setup/termux_setup_nodejs.sh b/scripts/build/setup/termux_setup_nodejs.sh new file mode 100644 index 000000000..f40b921f9 --- /dev/null +++ b/scripts/build/setup/termux_setup_nodejs.sh @@ -0,0 +1,42 @@ +termux_setup_nodejs() { + # Use LTS version for now + local NODEJS_VERSION=16.14.0 + local NODEJS_FOLDER + + if [ "${TERMUX_PACKAGES_OFFLINE-false}" = "true" ]; then + NODEJS_FOLDER=${TERMUX_SCRIPTDIR}/build-tools/nodejs-${NODEJS_VERSION} + else + NODEJS_FOLDER=${TERMUX_COMMON_CACHEDIR}/nodejs-$NODEJS_VERSION + fi + + if [ "$TERMUX_ON_DEVICE_BUILD" = "false" ]; then + if [ ! -x "$NODEJS_FOLDER/bin/node" ]; then + mkdir -p "$NODEJS_FOLDER" + local NODEJS_TAR_FILE=$TERMUX_PKG_TMPDIR/nodejs-$NODEJS_VERSION.tar.xz + termux_download https://nodejs.org/dist/v${NODEJS_VERSION}/node-v${NODEJS_VERSION}-linux-x64.tar.xz \ + "$NODEJS_TAR_FILE" \ + 0570b9354959f651b814e56a4ce98d4a067bf2385b9a0e6be075739bc65b0fae + tar -xf "$NODEJS_TAR_FILE" -C "$NODEJS_FOLDER" --strip-components=1 + fi + export PATH=$NODEJS_FOLDER/bin:$PATH + else + local NODEJS_PKG_VERSION=$(bash -c ". $TERMUX_SCRIPTDIR/packages/nodejs/build.sh; echo \$TERMUX_PKG_VERSION") + if ([ ! -e "$TERMUX_BUILT_PACKAGES_DIRECTORY/nodejs" ] || + [ "$(cat "$TERMUX_BUILT_PACKAGES_DIRECTORY/nodejs")" != "$NODEJS_PKG_VERSION" ]) && + ([[ "$TERMUX_APP_PACKAGE_MANAGER" = "apt" && "$(dpkg-query -W -f '${db:Status-Status}\n' nodejs 2>/dev/null)" != "installed" ]] || + [[ "$TERMUX_APP_PACKAGE_MANAGER" = "pacman" && ! "$(pacman -Q nodejs 2>/dev/null)" ]]); then + echo "Package 'nodejs' is not installed." + echo "You can install it with" + echo + echo " pkg install nodejs" + echo + echo " pacman -S nodejs" + echo + echo "or build it from source with" + echo + echo " ./build-package.sh nodejs" + echo + exit 1 + fi + fi +} diff --git a/scripts/build/setup/termux_setup_protobuf.sh b/scripts/build/setup/termux_setup_protobuf.sh new file mode 100644 index 000000000..60e6dca00 --- /dev/null +++ b/scripts/build/setup/termux_setup_protobuf.sh @@ -0,0 +1,27 @@ +termux_setup_protobuf() { + local _PROTOBUF_VERSION=$(bash -c ". $TERMUX_SCRIPTDIR/packages/libprotobuf/build.sh; echo \${TERMUX_PKG_VERSION:2}") + local _PROTOBUF_ZIP=protoc-$_PROTOBUF_VERSION-linux-x86_64.zip + local _PROTOBUF_FOLDER + + if [ "${TERMUX_PACKAGES_OFFLINE-false}" = "true" ]; then + _PROTOBUF_FOLDER=${TERMUX_SCRIPTDIR}/build-tools/protobuf-${_PROTOBUF_VERSION} + else + _PROTOBUF_FOLDER=${TERMUX_COMMON_CACHEDIR}/protobuf-${_PROTOBUF_VERSION} + fi + + if [ "$TERMUX_ON_DEVICE_BUILD" = "false" ]; then + if [ ! -d "$_PROTOBUF_FOLDER" ]; then + termux_download \ + https://github.com/protocolbuffers/protobuf/releases/download/v$_PROTOBUF_VERSION/$_PROTOBUF_ZIP \ + $TERMUX_PKG_TMPDIR/$_PROTOBUF_ZIP \ + e7acbd3f3477c593cee58cd995490c0f95dcb4058dd4677d015535fc20a372f3 + + rm -Rf "$TERMUX_PKG_TMPDIR/protoc-$_PROTOBUF_VERSION-linux-x86_64" + unzip $TERMUX_PKG_TMPDIR/$_PROTOBUF_ZIP -d $TERMUX_PKG_TMPDIR/protobuf-$_PROTOBUF_VERSION + mv "$TERMUX_PKG_TMPDIR/protobuf-$_PROTOBUF_VERSION" \ + $_PROTOBUF_FOLDER + fi + + export PATH=$_PROTOBUF_FOLDER/bin/:$PATH + fi +} diff --git a/scripts/build/setup/termux_setup_python_crossenv.sh b/scripts/build/setup/termux_setup_python_crossenv.sh new file mode 100644 index 000000000..45fe0bd03 --- /dev/null +++ b/scripts/build/setup/termux_setup_python_crossenv.sh @@ -0,0 +1,26 @@ +termux_setup_python_crossenv() { + local _CROSSENV_VERSION=1.1.4 + local _CROSSENV_TAR=crossenv-$_CROSSENV_VERSION.tar.gz + local _CROSSENV_FOLDER + + if [ "${TERMUX_PACKAGES_OFFLINE-false}" = "true" ]; then + _CROSSENV_FOLDER=${TERMUX_SCRIPTDIR}/build-tools/crossenv-${_CROSSENV_VERSION} + else + _CROSSENV_FOLDER=${TERMUX_COMMON_CACHEDIR}/crossenv-${_CROSSENV_VERSION} + fi + export TERMUX_PYTHON_CROSSENV_SRCDIR=$_CROSSENV_FOLDER + + if [ "$TERMUX_ON_DEVICE_BUILD" = "false" ]; then + if [ ! -d "$_CROSSENV_FOLDER" ]; then + termux_download \ + https://github.com/benfogle/crossenv/archive/refs/tags/v$_CROSSENV_VERSION.tar.gz \ + $TERMUX_PKG_TMPDIR/$_CROSSENV_TAR \ + c1b0bb088ebd924e0cddbf1e601a172dc65d1f1c5f400d10a2743e3bfb703b9f + + rm -Rf "$TERMUX_PKG_TMPDIR/crossenv-$_CROSSENV_VERSION" + tar xf $TERMUX_PKG_TMPDIR/$_CROSSENV_TAR -C $TERMUX_PKG_TMPDIR + mv "$TERMUX_PKG_TMPDIR/crossenv-$_CROSSENV_VERSION" \ + $_CROSSENV_FOLDER + fi + fi +} diff --git a/scripts/build/setup/termux_setup_rust.sh b/scripts/build/setup/termux_setup_rust.sh new file mode 100644 index 000000000..3e94db13a --- /dev/null +++ b/scripts/build/setup/termux_setup_rust.sh @@ -0,0 +1,46 @@ +termux_setup_rust() { + if [ $TERMUX_ARCH = "arm" ]; then + CARGO_TARGET_NAME=armv7-linux-androideabi + else + CARGO_TARGET_NAME=$TERMUX_ARCH-linux-android + fi + + if [ "$TERMUX_ON_DEVICE_BUILD" = "true" ]; then + if [[ "$TERMUX_APP_PACKAGE_MANAGER" = "apt" && "$(dpkg-query -W -f '${db:Status-Status}\n' rust 2>/dev/null)" != "installed" ]] || + [[ "$TERMUX_APP_PACKAGE_MANAGER" = "pacman" && ! "$(pacman -Q rust 2>/dev/null)" ]]; then + echo "Package 'rust' is not installed." + echo "You can install it with" + echo + echo " pkg install rust" + echo + echo " pacman -S rust" + echo + echo "or build it from source with" + echo + echo " ./build-package.sh rust" + echo + echo "Note that package 'rust' is known to be problematic for building on device." + exit 1 + fi + return + fi + + local ENV_NAME=CARGO_TARGET_${CARGO_TARGET_NAME^^}_LINKER + ENV_NAME=${ENV_NAME//-/_} + export $ENV_NAME=$CC + export TARGET_CFLAGS="$CFLAGS $CPPFLAGS" + # This was getting applied for the host build of Rust macros or whatever, so + # unset it. + unset CFLAGS + + curl https://sh.rustup.rs -sSf > $TERMUX_PKG_TMPDIR/rustup.sh + + if [ -z "${TERMUX_RUST_VERSION-}" ]; then + TERMUX_RUST_VERSION=$(bash -c ". $TERMUX_SCRIPTDIR/packages/rust/build.sh; echo \$TERMUX_PKG_VERSION") + fi + + sh $TERMUX_PKG_TMPDIR/rustup.sh -y --default-toolchain $TERMUX_RUST_VERSION + export PATH=$HOME/.cargo/bin:$PATH + + rustup target add $CARGO_TARGET_NAME +} diff --git a/scripts/build/setup/termux_setup_swift.sh b/scripts/build/setup/termux_setup_swift.sh new file mode 100644 index 000000000..9d78f75ee --- /dev/null +++ b/scripts/build/setup/termux_setup_swift.sh @@ -0,0 +1,60 @@ +termux_setup_swift() { + local SWIFT_TRIPLE=${TERMUX_HOST_PLATFORM/-/-unknown-}$TERMUX_PKG_API_LEVEL + export SWIFT_TARGET_TRIPLE=${SWIFT_TRIPLE/arm-/armv7-} + + if [ "$TERMUX_ON_DEVICE_BUILD" = "false" ]; then + local TERMUX_SWIFT_VERSION=$(. $TERMUX_SCRIPTDIR/packages/swift/build.sh; echo $TERMUX_PKG_VERSION) + local SWIFT_RELEASE=$(. $TERMUX_SCRIPTDIR/packages/swift/build.sh; echo $SWIFT_RELEASE) + local SWIFT_BIN="swift-$TERMUX_SWIFT_VERSION-$SWIFT_RELEASE-ubuntu20.04" + local SWIFT_FOLDER + + if [ "${TERMUX_PACKAGES_OFFLINE-false}" = "true" ]; then + SWIFT_FOLDER=${TERMUX_SCRIPTDIR}/build-tools/${SWIFT_BIN} + else + SWIFT_FOLDER=${TERMUX_COMMON_CACHEDIR}/${SWIFT_BIN} + fi + + if [ ! -d "$SWIFT_FOLDER" ]; then + local SWIFT_TAR=$TERMUX_PKG_TMPDIR/${SWIFT_BIN}.tar.gz + termux_download \ + https://download.swift.org/swift-$TERMUX_SWIFT_VERSION-release/ubuntu2004/swift-$TERMUX_SWIFT_VERSION-$SWIFT_RELEASE/$SWIFT_BIN.tar.gz \ + $SWIFT_TAR \ + ac1c711985113d0d9daf7bf80205935a0688fb146546690d93c23df54d81cfb7 + + (cd $TERMUX_PKG_TMPDIR ; tar xf $SWIFT_TAR ; mv $SWIFT_BIN $SWIFT_FOLDER; rm $SWIFT_TAR) + fi + export SWIFT_BINDIR="$SWIFT_FOLDER/usr/bin" + export SWIFT_CROSSCOMPILE_CONFIG="$SWIFT_FOLDER/usr/android-$TERMUX_ARCH.json" + if [ -d $TERMUX_STANDALONE_TOOLCHAIN ]; then + cat <<- EOF > $SWIFT_CROSSCOMPILE_CONFIG + { "version": 1, + "target": "${SWIFT_TARGET_TRIPLE}", + "toolchain-bin-dir": "${SWIFT_BINDIR}", + "sdk": "${TERMUX_STANDALONE_TOOLCHAIN}/sysroot", + "extra-cc-flags": [ "-fPIC" ], + "extra-swiftc-flags": [ "-resource-dir", "${TERMUX_PREFIX}/lib/swift", + "-Xcc", "-I${TERMUX_PREFIX}/include", + "-L${TERMUX_PREFIX}/lib", + "-tools-directory", "${TERMUX_STANDALONE_TOOLCHAIN}/bin", ], + "extra-cpp-flags": [ "-lstdc++" ] } + EOF + fi + else + if [[ "${TERMUX_APP_PACKAGE_MANAGER}" == "apt" && "$(dpkg-query -W -f '${db:Status-Status}\n' swift 2>/dev/null)" != "installed" ]] || + [[ "${TERMUX_APP_PACKAGE_MANAGER}" == "pacman" && ! "$(pacman -Q swift 2>/dev/null)" ]]; then + echo "Package 'swift' is not installed." + echo "You can install it with" + echo + echo " pkg install swift" + echo + echo " pacman -S swift" + echo + echo "or build it from source with" + echo + echo " ./build-package.sh swift" + echo + exit 1 + fi + export SWIFT_BINDIR="$TERMUX_PREFIX/bin" + fi +} diff --git a/scripts/build/setup/termux_setup_zig.sh b/scripts/build/setup/termux_setup_zig.sh new file mode 100644 index 000000000..a85daa272 --- /dev/null +++ b/scripts/build/setup/termux_setup_zig.sh @@ -0,0 +1,44 @@ +termux_setup_zig() { + local ZIG_VERSION=0.9.1 + local ZIG_FOLDER + + if [ "${TERMUX_PACKAGES_OFFLINE-false}" = "true" ]; then + ZIG_FOLDER=${TERMUX_SCRIPTDIR}/build-tools/zig-${ZIG_VERSION} + else + ZIG_FOLDER=${TERMUX_COMMON_CACHEDIR}/zig-${ZIG_VERSION} + fi + + if [ "$TERMUX_ON_DEVICE_BUILD" = "false" ]; then + if [ ! -x "$ZIG_FOLDER/zig" ]; then + mkdir -p "$ZIG_FOLDER" + local ZIG_TARBALL=$TERMUX_PKG_TMPDIR/zig-$ZIG_VERSION.zip + termux_download https://ziglang.org/download/$ZIG_VERSION/zig-linux-x86_64-$ZIG_VERSION.tar.xz \ + "$ZIG_TARBALL" \ + be8da632c1d3273f766b69244d80669fe4f5e27798654681d77c992f17c237d7 + tar xf "$ZIG_TARBALL" -C "$ZIG_FOLDER" --strip-components=1 + fi + export PATH=$ZIG_FOLDER:$PATH + else + local ZIG_PKG_VERSION=$(bash -c ". $TERMUX_SCRIPTDIR/packages/zig/build.sh; echo \$TERMUX_PKG_VERSION") + if ([ ! -e "$TERMUX_BUILT_PACKAGES_DIRECTORY/zig" ] || + [ "$(cat "$TERMUX_BUILT_PACKAGES_DIRECTORY/zig")" != "$ZIG_PKG_VERSION" ]) && + [ "$(dpkg-query -W -f '${db:Status-Status}\n' zig 2>/dev/null)" != "installed" ]; then + echo "Package 'zig' is not installed." + echo "You can install it with" + echo + echo " pkg install zig" + echo + echo "or build it from source with" + echo + echo " ./build-package.sh zig" + echo + exit 1 + fi + fi + + if [ $TERMUX_ARCH = "i686" ]; then + ZIG_TARGET_NAME=i386-linux-android + else + ZIG_TARGET_NAME=$TERMUX_ARCH-linux-android + fi +} diff --git a/scripts/build/termux_create_debian_subpackages.sh b/scripts/build/termux_create_debian_subpackages.sh new file mode 100644 index 000000000..47e59ea88 --- /dev/null +++ b/scripts/build/termux_create_debian_subpackages.sh @@ -0,0 +1,106 @@ +termux_create_debian_subpackages() { + # Sub packages: + if [ "$TERMUX_PKG_NO_STATICSPLIT" = "false" ] && [[ -n $(shopt -s globstar; shopt -s nullglob; echo lib/**/*.a) ]]; then + # Add virtual -static sub package if there are include files: + local _STATIC_SUBPACKAGE_FILE=$TERMUX_PKG_TMPDIR/${TERMUX_PKG_NAME}-static.subpackage.sh + echo TERMUX_SUBPKG_INCLUDE=\"lib/**/*.a lib/**/*.la $TERMUX_PKG_STATICSPLIT_EXTRA_PATTERNS\" > "$_STATIC_SUBPACKAGE_FILE" + echo "TERMUX_SUBPKG_DESCRIPTION=\"Static libraries for ${TERMUX_PKG_NAME}\"" >> "$_STATIC_SUBPACKAGE_FILE" + fi + + # Now build all sub packages + rm -Rf "$TERMUX_TOPDIR/$TERMUX_PKG_NAME/subpackages" + for subpackage in $TERMUX_PKG_BUILDER_DIR/*.subpackage.sh $TERMUX_PKG_TMPDIR/*subpackage.sh; do + test ! -f "$subpackage" && continue + local SUB_PKG_NAME + SUB_PKG_NAME=$(basename "$subpackage" .subpackage.sh) + # Default value is same as main package, but sub package may override: + local TERMUX_SUBPKG_PLATFORM_INDEPENDENT=$TERMUX_PKG_PLATFORM_INDEPENDENT + local SUB_PKG_DIR=$TERMUX_TOPDIR/$TERMUX_PKG_NAME/subpackages/$SUB_PKG_NAME + local TERMUX_SUBPKG_ESSENTIAL=false + local TERMUX_SUBPKG_BREAKS="" + local TERMUX_SUBPKG_DEPENDS="" + local TERMUX_SUBPKG_CONFLICTS="" + local TERMUX_SUBPKG_REPLACES="" + local TERMUX_SUBPKG_CONFFILES="" + local TERMUX_SUBPKG_DEPEND_ON_PARENT="" + local SUB_PKG_MASSAGE_DIR=$SUB_PKG_DIR/massage/$TERMUX_PREFIX + local SUB_PKG_PACKAGE_DIR=$SUB_PKG_DIR/package + mkdir -p "$SUB_PKG_MASSAGE_DIR" "$SUB_PKG_PACKAGE_DIR" + + # shellcheck source=/dev/null + source "$subpackage" + + # Allow globstar (i.e. './**/') patterns. + shopt -s globstar + # Allow negation patterns. + shopt -s extglob + for includeset in $TERMUX_SUBPKG_INCLUDE; do + local _INCLUDE_DIRSET + _INCLUDE_DIRSET=$(dirname "$includeset") + test "$_INCLUDE_DIRSET" = "." && _INCLUDE_DIRSET="" + + if [ -e "$includeset" ] || [ -L "$includeset" ]; then + # Add the -L clause to handle relative symbolic links: + mkdir -p "$SUB_PKG_MASSAGE_DIR/$_INCLUDE_DIRSET" + mv "$includeset" "$SUB_PKG_MASSAGE_DIR/$_INCLUDE_DIRSET" + fi + done + shopt -u globstar extglob + + local SUB_PKG_ARCH=$TERMUX_ARCH + [ "$TERMUX_SUBPKG_PLATFORM_INDEPENDENT" = "true" ] && SUB_PKG_ARCH=all + + cd "$SUB_PKG_DIR/massage" + local SUB_PKG_INSTALLSIZE + SUB_PKG_INSTALLSIZE=$(du -sk . | cut -f 1) + tar -cJf "$SUB_PKG_PACKAGE_DIR/data.tar.xz" . + + mkdir -p DEBIAN + cd DEBIAN + + cat > control <<-HERE + Package: $SUB_PKG_NAME + Architecture: ${SUB_PKG_ARCH} + Installed-Size: ${SUB_PKG_INSTALLSIZE} + Maintainer: $TERMUX_PKG_MAINTAINER + Version: $TERMUX_PKG_FULLVERSION + Homepage: $TERMUX_PKG_HOMEPAGE + HERE + + local PKG_DEPS_SPC=" ${TERMUX_PKG_DEPENDS//,/} " + + if [ -z "$TERMUX_SUBPKG_DEPEND_ON_PARENT" ] && [ "${PKG_DEPS_SPC/ $SUB_PKG_NAME /}" = "$PKG_DEPS_SPC" ]; then + TERMUX_SUBPKG_DEPENDS+=", $TERMUX_PKG_NAME (= $TERMUX_PKG_FULLVERSION)" + elif [ "$TERMUX_SUBPKG_DEPEND_ON_PARENT" = unversioned ]; then + TERMUX_SUBPKG_DEPENDS+=", $TERMUX_PKG_NAME" + elif [ "$TERMUX_SUBPKG_DEPEND_ON_PARENT" = deps ]; then + TERMUX_SUBPKG_DEPENDS+=", $TERMUX_PKG_DEPENDS" + fi + + [ "$TERMUX_SUBPKG_ESSENTIAL" = "true" ] && echo "Essential: yes" >> control + test ! -z "$TERMUX_SUBPKG_DEPENDS" && echo "Depends: ${TERMUX_SUBPKG_DEPENDS/#, /}" >> control + test ! -z "$TERMUX_SUBPKG_BREAKS" && echo "Breaks: $TERMUX_SUBPKG_BREAKS" >> control + test ! -z "$TERMUX_SUBPKG_CONFLICTS" && echo "Conflicts: $TERMUX_SUBPKG_CONFLICTS" >> control + test ! -z "$TERMUX_SUBPKG_REPLACES" && echo "Replaces: $TERMUX_SUBPKG_REPLACES" >> control + echo "Description: $TERMUX_SUBPKG_DESCRIPTION" >> control + + for f in $TERMUX_SUBPKG_CONFFILES; do echo "$TERMUX_PREFIX/$f" >> conffiles; done + + # Allow packages to create arbitrary control files. + termux_step_create_subpkg_debscripts + + # Create control.tar.xz + tar -cJf "$SUB_PKG_PACKAGE_DIR/control.tar.xz" -H gnu . + + # Create the actual .deb file: + TERMUX_SUBPKG_DEBFILE=$TERMUX_OUTPUT_DIR/${SUB_PKG_NAME}${DEBUG}_${TERMUX_PKG_FULLVERSION}_${SUB_PKG_ARCH}.deb + test ! -f "$TERMUX_COMMON_CACHEDIR/debian-binary" && echo "2.0" > "$TERMUX_COMMON_CACHEDIR/debian-binary" + ${AR-ar} cr "$TERMUX_SUBPKG_DEBFILE" \ + "$TERMUX_COMMON_CACHEDIR/debian-binary" \ + "$SUB_PKG_PACKAGE_DIR/control.tar.xz" \ + "$SUB_PKG_PACKAGE_DIR/data.tar.xz" + + # Go back to main package: + cd "$TERMUX_PKG_MASSAGEDIR/$TERMUX_PREFIX" + done +} diff --git a/scripts/build/termux_create_pacman_subpackages.sh b/scripts/build/termux_create_pacman_subpackages.sh new file mode 100644 index 000000000..bf8af7b44 --- /dev/null +++ b/scripts/build/termux_create_pacman_subpackages.sh @@ -0,0 +1,166 @@ +termux_create_pacman_subpackages() { + # Sub packages: + if [ "$TERMUX_PKG_NO_STATICSPLIT" = "false" ] && [[ -n $(shopt -s globstar; shopt -s nullglob; echo lib/**/*.a) ]]; then + # Add virtual -static sub package if there are include files: + local _STATIC_SUBPACKAGE_FILE=$TERMUX_PKG_TMPDIR/${TERMUX_PKG_NAME}-static.subpackage.sh + echo TERMUX_SUBPKG_INCLUDE=\"lib/**/*.a lib/**/*.la $TERMUX_PKG_STATICSPLIT_EXTRA_PATTERNS\" > "$_STATIC_SUBPACKAGE_FILE" + echo "TERMUX_SUBPKG_DESCRIPTION=\"Static libraries for ${TERMUX_PKG_NAME}\"" >> "$_STATIC_SUBPACKAGE_FILE" + fi + + # Now build all sub packages + rm -Rf "$TERMUX_TOPDIR/$TERMUX_PKG_NAME/subpackages" + for subpackage in $TERMUX_PKG_BUILDER_DIR/*.subpackage.sh $TERMUX_PKG_TMPDIR/*subpackage.sh; do + test ! -f "$subpackage" && continue + local SUB_PKG_NAME + SUB_PKG_NAME=$(basename "$subpackage" .subpackage.sh) + # Default value is same as main package, but sub package may override: + local TERMUX_SUBPKG_PLATFORM_INDEPENDENT=$TERMUX_PKG_PLATFORM_INDEPENDENT + local SUB_PKG_DIR=$TERMUX_TOPDIR/$TERMUX_PKG_NAME/subpackages/$SUB_PKG_NAME + local TERMUX_SUBPKG_ESSENTIAL=false + local TERMUX_SUBPKG_BREAKS="" + local TERMUX_SUBPKG_DEPENDS="" + local TERMUX_SUBPKG_CONFLICTS="" + local TERMUX_SUBPKG_REPLACES="" + local TERMUX_SUBPKG_CONFFILES="" + local TERMUX_SUBPKG_DEPEND_ON_PARENT="" + local TERMUX_SUBPKG_GROUPS="" + local SUB_PKG_MASSAGE_DIR=$SUB_PKG_DIR/massage/$TERMUX_PREFIX + local SUB_PKG_PACKAGE_DIR=$SUB_PKG_DIR/package + mkdir -p "$SUB_PKG_MASSAGE_DIR" "$SUB_PKG_PACKAGE_DIR" + + # shellcheck source=/dev/null + source "$subpackage" + + # Allow globstar (i.e. './**/') patterns. + shopt -s globstar + for includeset in $TERMUX_SUBPKG_INCLUDE; do + local _INCLUDE_DIRSET + _INCLUDE_DIRSET=$(dirname "$includeset") + test "$_INCLUDE_DIRSET" = "." && _INCLUDE_DIRSET="" + + if [ -e "$includeset" ] || [ -L "$includeset" ]; then + # Add the -L clause to handle relative symbolic links: + mkdir -p "$SUB_PKG_MASSAGE_DIR/$_INCLUDE_DIRSET" + mv "$includeset" "$SUB_PKG_MASSAGE_DIR/$_INCLUDE_DIRSET" + fi + done + shopt -u globstar + + local SUB_PKG_ARCH=$TERMUX_ARCH + [ "$TERMUX_SUBPKG_PLATFORM_INDEPENDENT" = "true" ] && SUB_PKG_ARCH=any + + cd "$SUB_PKG_DIR/massage" + local SUB_PKG_INSTALLSIZE + SUB_PKG_INSTALLSIZE=$(du -bs . | cut -f 1) + + local BUILD_DATE + BUILD_DATE=$(date +%s) + + local PKG_DEPS_SPC=" ${TERMUX_PKG_DEPENDS//,/} " + if [ -z "$TERMUX_SUBPKG_DEPEND_ON_PARENT" ] && [ "${PKG_DEPS_SPC/ $SUB_PKG_NAME /}" = "$PKG_DEPS_SPC" ]; then + # Does pacman supports versioned dependencies? + #TERMUX_SUBPKG_DEPENDS+=", $TERMUX_PKG_NAME (= $TERMUX_PKG_FULLVERSION)" + TERMUX_SUBPKG_DEPENDS+=", $TERMUX_PKG_NAME" + elif [ "$TERMUX_SUBPKG_DEPEND_ON_PARENT" = unversioned ]; then + TERMUX_SUBPKG_DEPENDS+=", $TERMUX_PKG_NAME" + elif [ "$TERMUX_SUBPKG_DEPEND_ON_PARENT" = deps ]; then + TERMUX_SUBPKG_DEPENDS+=", $TERMUX_PKG_DEPENDS" + fi + + # Package metadata. + { + echo "pkgname = $SUB_PKG_NAME" + echo "pkgbase = $TERMUX_PKG_NAME" + echo "pkgver = $TERMUX_PKG_FULLVERSION_FOR_PACMAN" + echo "pkgdesc = $(echo "$TERMUX_SUBPKG_DESCRIPTION" | tr '\n' ' ')" + echo "url = $TERMUX_PKG_HOMEPAGE" + echo "builddate = $BUILD_DATE" + echo "packager = $TERMUX_PKG_MAINTAINER" + echo "size = $SUB_PKG_INSTALLSIZE" + echo "arch = $SUB_PKG_ARCH" + + if [ -n "$TERMUX_SUBPKG_REPLACES" ]; then + tr ',' '\n' <<< "$TERMUX_SUBPKG_REPLACES" | sed 's|(||g; s|)||g; s| ||g; s|>>|>|g; s|<<|<|g' | awk '{ printf "replaces = %s\n", $1 }' + fi + + if [ -n "$TERMUX_SUBPKG_CONFLICTS" ]; then + tr ',' '\n' <<< "$TERMUX_SUBPKG_CONFLICTS" | sed 's|(||g; s|)||g; s| ||g; s|>>|>|g; s|<<|<|g' | awk '{ printf "conflict = %s\n", $1 }' + fi + + if [ -n "$TERMUX_SUBPKG_BREAKS" ]; then + tr ',' '\n' <<< "$TERMUX_SUBPKG_BREAKS" | sed 's|(||g; s|)||g; s| ||g; s|>>|>|g; s|<<|<|g' | awk '{ printf "conflict = %s\n", $1 }' + fi + + if [ -n "$TERMUX_SUBPKG_DEPENDS" ]; then + tr ',' '\n' <<< "${TERMUX_SUBPKG_DEPENDS/#, /}" | sed 's|(||g; s|)||g; s| ||g; s|>>|>|g; s|<<|<|g' | awk '{ printf "depend = %s\n", $1 }' | sed 's/|.*//' + fi + + if [ -n "$TERMUX_SUBPKG_CONFFILES" ]; then + tr ',' '\n' <<< "$TERMUX_SUBPKG_CONFFILES" | awk '{ printf "backup = '"${TERMUX_PREFIX:1}"'/%s\n", $1 }' + fi + + if [ -n "$TERMUX_SUBPKG_GROUPS" ]; then + tr ',' '\n' <<< "${TERMUX_SUBPKG_GROUPS/#, /}" | awk '{ printf "group = %s\n", $1 }' + fi + } > .PKGINFO + + # Build metadata. + { + echo "format = 2" + echo "pkgname = $SUB_PKG_NAME" + echo "pkgbase = $TERMUX_PKG_NAME" + echo "pkgver = $TERMUX_PKG_FULLVERSION_FOR_PACMAN" + echo "pkgarch = $SUB_PKG_ARCH" + echo "packager = $TERMUX_PKG_MAINTAINER" + echo "builddate = $BUILD_DATE" + } > .BUILDINFO + + # Write package installation hooks. + termux_step_create_subpkg_debscripts + termux_step_create_pacman_install_hook + + # Configuring the selection of a copress for a batch. + local COMPRESS + local PKG_FORMAT + case $TERMUX_PACMAN_PACKAGE_COMPRESSION in + "gzip") + COMPRESS=(gzip -c -f -n) + PKG_FORMAT="gz";; + "bzip2") + COMPRESS=(bzip2 -c -f) + PKG_FORMAT="bz2";; + "zstd") + COMPRESS=(zstd -c -z -q -) + PKG_FORMAT="zst";; + "lrzip") + COMPRESS=(lrzip -q) + PKG_FORMAT="lrz";; + "lzop") + COMPRESS=(lzop -q) + PKG_FORMAT="lzop";; + "lz4") + COMPRESS=(lz4 -q) + PKG_FORMAT="lz4";; + "lzip") + COMPRESS=(lzip -c -f) + PKG_FORMAT="lz";; + "xz" | *) + COMPRESS=(xz -c -z -) + PKG_FORMAT="xz";; + esac + + # Create the actual .pkg file: + local TERMUX_SUBPKG_PACMAN_FILE=$TERMUX_OUTPUT_DIR/${SUB_PKG_NAME}${DEBUG}-${TERMUX_PKG_FULLVERSION_FOR_PACMAN}-${SUB_PKG_ARCH}.pkg.tar.${PKG_FORMAT} + shopt -s dotglob globstar + printf '%s\0' **/* | bsdtar -cnf - --format=mtree \ + --options='!all,use-set,type,uid,gid,mode,time,size,md5,sha256,link' \ + --null --files-from - --exclude .MTREE | \ + gzip -c -f -n > .MTREE + printf '%s\0' **/* | bsdtar --no-fflags -cnf - --null --files-from - | \ + $COMPRESS > "$TERMUX_SUBPKG_PACMAN_FILE" + shopt -u dotglob globstar + + # Go back to main package: + cd "$TERMUX_PKG_MASSAGEDIR/$TERMUX_PREFIX" + done +} diff --git a/scripts/build/termux_download.sh b/scripts/build/termux_download.sh new file mode 100755 index 000000000..7414a167b --- /dev/null +++ b/scripts/build/termux_download.sh @@ -0,0 +1,43 @@ +termux_download() { + if [ $# != 3 ]; then + termux_error_exit "termux_download(): Invalid arguments - expected \$URL \$DESTINATION \$CHECKSUM" + fi + local URL="$1" + local DESTINATION="$2" + local CHECKSUM="$3" + + if [ -f "$DESTINATION" ] && [ "$CHECKSUM" != "SKIP_CHECKSUM" ]; then + # Keep existing file if checksum matches. + local EXISTING_CHECKSUM + EXISTING_CHECKSUM=$(sha256sum "$DESTINATION" | cut -f 1 -d ' ') + if [ "$EXISTING_CHECKSUM" = "$CHECKSUM" ]; then return; fi + fi + + local TMPFILE + TMPFILE=$(mktemp "$TERMUX_PKG_TMPDIR/download.${TERMUX_PKG_NAME-unnamed}.XXXXXXXXX") + echo "Downloading ${URL}" + if curl --fail --retry 20 --retry-connrefused --retry-delay 30 --location --output "$TMPFILE" "$URL"; then + local ACTUAL_CHECKSUM + ACTUAL_CHECKSUM=$(sha256sum "$TMPFILE" | cut -f 1 -d ' ') + if [ "$CHECKSUM" != "SKIP_CHECKSUM" ]; then + if [ "$CHECKSUM" != "$ACTUAL_CHECKSUM" ]; then + >&2 printf "Wrong checksum for %s:\nExpected: %s\nActual: %s\n" \ + "$URL" "$CHECKSUM" "$ACTUAL_CHECKSUM" + return 1 + fi + elif [ -z "$CHECKSUM" ]; then + printf "WARNING: No checksum check for %s:\nActual: %s\n" \ + "$URL" "$ACTUAL_CHECKSUM" + fi + mv "$TMPFILE" "$DESTINATION" + return 0 + fi + + echo "Failed to download $URL" >&2 + return 1 +} + +# Make script standalone executable as well as sourceable +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + termux_download "$@" +fi diff --git a/scripts/build/termux_download_deb_pac.sh b/scripts/build/termux_download_deb_pac.sh new file mode 100755 index 000000000..28f7c66a7 --- /dev/null +++ b/scripts/build/termux_download_deb_pac.sh @@ -0,0 +1,70 @@ +termux_download_deb_pac() { + local PACKAGE=$1 + local PACKAGE_ARCH=$2 + local VERSION=$3 + local VERSION_PACMAN=$4 + + if [ "$TERMUX_ON_DEVICE_BUILD" = "true" ]; then + case "$TERMUX_APP_PACKAGE_MANAGER" in + "apt") apt install -y "${PACKAGE}=${VERSION}";; + "pacman") pacman -S "${PACKAGE}=${VERSION_PACMAN}" --needed --noconfirm;; + esac + return "$?" + fi + + local DEB_FILE="${PACKAGE}_${VERSION}_${PACKAGE_ARCH}.deb" + PKG_HASH="" + + for idx in $(seq ${#TERMUX_REPO_URL[@]}); do + local TERMUX_REPO_NAME=$(echo ${TERMUX_REPO_URL[$idx-1]} | sed -e 's%https://%%g' -e 's%http://%%g' -e 's%/%-%g') + local PACKAGE_FILE_PATH="${TERMUX_REPO_NAME}-${TERMUX_REPO_DISTRIBUTION[$idx-1]}-${TERMUX_REPO_COMPONENT[$idx-1]}-Packages" + if [ "${PACKAGE_ARCH}" = 'all' ]; then + for arch in 'aarch64' 'arm' 'i686' 'x86_64'; do + if [ -f "${TERMUX_COMMON_CACHEDIR}-${arch}/${PACKAGE_FILE_PATH}" ]; then + read -d "\n" PKG_PATH PKG_HASH <<<$(./scripts/get_hash_from_file.py "${TERMUX_COMMON_CACHEDIR}-${arch}/$PACKAGE_FILE_PATH" $PACKAGE $VERSION) + if [ -n "$PKG_HASH" ]; then + if [ ! "$TERMUX_QUIET_BUILD" = true ]; then + echo "Found $PACKAGE in ${TERMUX_REPO_URL[$idx-1]}/dists/${TERMUX_REPO_DISTRIBUTION[$idx-1]}" + fi + break 2 + fi + fi + done + elif [ ! -f "${TERMUX_COMMON_CACHEDIR}-${PACKAGE_ARCH}/${PACKAGE_FILE_PATH}" ] && \ + [ -f "${TERMUX_COMMON_CACHEDIR}-aarch64/${PACKAGE_FILE_PATH}" ]; then + # Packages file for $PACKAGE_ARCH did not + # exist. Could be an aptly mirror where the + # all arch is mixed into the other arches, + # check for package in aarch64 Packages + # instead. + read -d "\n" PKG_PATH PKG_HASH <<<$(./scripts/get_hash_from_file.py "${TERMUX_COMMON_CACHEDIR}-aarch64/$PACKAGE_FILE_PATH" $PACKAGE $VERSION) + if [ -n "$PKG_HASH" ]; then + if [ ! "$TERMUX_QUIET_BUILD" = true ]; then + echo "Found $PACKAGE in ${TERMUX_REPO_URL[$idx-1]}/dists/${TERMUX_REPO_DISTRIBUTION[$idx-1]}" + fi + break + fi + elif [ -f "${TERMUX_COMMON_CACHEDIR}-${PACKAGE_ARCH}/${PACKAGE_FILE_PATH}" ]; then + read -d "\n" PKG_PATH PKG_HASH <<<$(./scripts/get_hash_from_file.py "${TERMUX_COMMON_CACHEDIR}-${PACKAGE_ARCH}/$PACKAGE_FILE_PATH" $PACKAGE $VERSION) + if [ -n "$PKG_HASH" ]; then + if [ ! "$TERMUX_QUIET_BUILD" = true ]; then + echo "Found $PACKAGE in ${TERMUX_REPO_URL[$idx-1]}/dists/${TERMUX_REPO_DISTRIBUTION[$idx-1]}" + fi + break + fi + fi + done + + if [ "$PKG_HASH" = "" ]; then + return 1 + fi + + termux_download "${TERMUX_REPO_URL[${idx}-1]}/${PKG_PATH}" \ + "${TERMUX_COMMON_CACHEDIR}-${PACKAGE_ARCH}/${DEB_FILE}" \ + "$PKG_HASH" +} + +# Make script standalone executable as well as sourceable +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + termux_download "$@" +fi diff --git a/scripts/build/termux_error_exit.sh b/scripts/build/termux_error_exit.sh new file mode 100644 index 000000000..99f14a3b1 --- /dev/null +++ b/scripts/build/termux_error_exit.sh @@ -0,0 +1,4 @@ +termux_error_exit() { + echo "ERROR: $*" 1>&2 + exit 1 +} diff --git a/scripts/build/termux_extract_dep_info.sh b/scripts/build/termux_extract_dep_info.sh new file mode 100755 index 000000000..5cc469bfd --- /dev/null +++ b/scripts/build/termux_extract_dep_info.sh @@ -0,0 +1,61 @@ +termux_extract_dep_info() { + PKG=$1 + PKG_DIR=$2 + if [ "$PKG" != "$(basename ${PKG_DIR})" ]; then + # We are dealing with a subpackage + TERMUX_ARCH=$( + # set TERMUX_SUBPKG_PLATFORM_INDEPENDENT to + # parent package's value and override if + # needed + TERMUX_PKG_PLATFORM_INDEPENDENT=false + source ${PKG_DIR}/build.sh + TERMUX_SUBPKG_PLATFORM_INDEPENDENT=$TERMUX_PKG_PLATFORM_INDEPENDENT + if [ "$TERMUX_INSTALL_DEPS" = "false" ] || \ + [ "$TERMUX_PKG_NO_STATICSPLIT" = "true" ] || \ + [ "${PKG/-static/}-static" != "${PKG}" ]; then + source ${PKG_DIR}/${PKG}.subpackage.sh + fi + if [ "$TERMUX_SUBPKG_PLATFORM_INDEPENDENT" = "true" ]; then + echo all + else + echo $TERMUX_ARCH + fi + ) + else + TERMUX_ARCH=$( + TERMUX_PKG_PLATFORM_INDEPENDENT="false" + source ${PKG_DIR}/build.sh + if [ "$TERMUX_PKG_PLATFORM_INDEPENDENT" = "true" ]; then + echo all + else + echo $TERMUX_ARCH + fi + ) + fi + ( + # debian version + TERMUX_PKG_REVISION="0" + source ${PKG_DIR}/build.sh + if [ "$TERMUX_PKG_REVISION" != "0" ] || \ + [ "$TERMUX_PKG_VERSION" != "${TERMUX_PKG_VERSION/-/}" ]; then + TERMUX_PKG_VERSION+="-$TERMUX_PKG_REVISION" + fi + echo -n "${TERMUX_ARCH} ${TERMUX_PKG_VERSION} " + ) + ( + # pacman version + TERMUX_PKG_REVISION="0" + source ${PKG_DIR}/build.sh + TERMUX_PKG_VERSION_EDITED=${TERMUX_PKG_VERSION//-/.} + INCORRECT_SYMBOLS=$(echo $TERMUX_PKG_VERSION_EDITED | grep -o '[0-9][a-z]') + if [ -n "$INCORRECT_SYMBOLS" ]; then + TERMUX_PKG_VERSION_EDITED=${TERMUX_PKG_VERSION_EDITED//${INCORRECT_SYMBOLS:0:1}${INCORRECT_SYMBOLS:1:1}/${INCORRECT_SYMBOLS:0:1}.${INCORRECT_SYMBOLS:1:1}} + fi + echo "${TERMUX_PKG_VERSION_EDITED}-${TERMUX_PKG_REVISION}" + ) +} + +# Make script standalone executable as well as sourceable +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + termux_extract_dep_info "$@" +fi diff --git a/scripts/build/termux_get_repo_files.sh b/scripts/build/termux_get_repo_files.sh new file mode 100644 index 000000000..a5bd8b3d1 --- /dev/null +++ b/scripts/build/termux_get_repo_files.sh @@ -0,0 +1,55 @@ +termux_get_repo_files() { + # Not needed for on-device builds or when building + # dependencies. + if [ "$TERMUX_ON_DEVICE_BUILD" = "true" ] || [ "$TERMUX_INSTALL_DEPS" = "false" ]; then + return + fi + + for idx in $(seq ${#TERMUX_REPO_URL[@]}); do + local TERMUX_REPO_NAME=$(echo ${TERMUX_REPO_URL[$idx-1]} | sed -e 's%https://%%g' -e 's%http://%%g' -e 's%/%-%g') + local RELEASE_FILE=${TERMUX_COMMON_CACHEDIR}/${TERMUX_REPO_NAME}-${TERMUX_REPO_DISTRIBUTION[$idx-1]}-Release + local repo_base="${TERMUX_REPO_URL[$idx-1]}/dists/${TERMUX_REPO_DISTRIBUTION[$idx-1]}" + local dl_prefix="${TERMUX_REPO_NAME}-${TERMUX_REPO_DISTRIBUTION[$idx-1]}-${TERMUX_REPO_COMPONENT[$idx-1]}" + + local download_attempts=6 + while ((download_attempts > 0)); do + if termux_download "${repo_base}/Release" \ + "$RELEASE_FILE" SKIP_CHECKSUM && \ + termux_download "${repo_base}/Release.gpg" \ + "${RELEASE_FILE}.gpg" SKIP_CHECKSUM; then + + if ! gpg --verify "${RELEASE_FILE}.gpg" "$RELEASE_FILE"; then + termux_error_exit "failed to verify gpg signature of $RELEASE_FILE" + fi + + local failed=false + for arch in all $TERMUX_ARCH; do + local PACKAGES_HASH=$(./scripts/get_hash_from_file.py ${RELEASE_FILE} $arch ${TERMUX_REPO_COMPONENT[$idx-1]}) + + # If packages_hash = "" then the repo probably doesn't contain debs for $arch + if [ -n "$PACKAGES_HASH" ]; then + if ! termux_download "${repo_base}/${TERMUX_REPO_COMPONENT[$idx-1]}/binary-$arch/Packages" \ + "${TERMUX_COMMON_CACHEDIR}-$arch/${dl_prefix}-Packages" \ + $PACKAGES_HASH; then + failed=true + break + fi + fi + done + + if ! $failed; then + break + fi + fi + + download_attempts=$((download_attempts - 1)) + if ((download_attempts < 1)); then + termux_error_exit "Failed to download package repository metadata. Try to build without -i/-I option." + fi + + echo "Retrying download in 30 seconds (${download_attempts} attempts left)..." >&2 + sleep 30 + done + + done +} diff --git a/scripts/build/termux_step_create_debian_package.sh b/scripts/build/termux_step_create_debian_package.sh new file mode 100644 index 000000000..a85093de5 --- /dev/null +++ b/scripts/build/termux_step_create_debian_package.sh @@ -0,0 +1,53 @@ +termux_step_create_debian_package() { + if [ "$TERMUX_PKG_METAPACKAGE" = "true" ]; then + # Metapackage doesn't have data inside. + rm -rf data + fi + tar -cJf "$TERMUX_PKG_PACKAGEDIR/data.tar.xz" -H gnu . + + # Get install size. This will be written as the "Installed-Size" deb field so is measured in 1024-byte blocks: + local TERMUX_PKG_INSTALLSIZE + TERMUX_PKG_INSTALLSIZE=$(du -sk . | cut -f 1) + + # From here on TERMUX_ARCH is set to "all" if TERMUX_PKG_PLATFORM_INDEPENDENT is set by the package + [ "$TERMUX_PKG_PLATFORM_INDEPENDENT" = "true" ] && TERMUX_ARCH=all + + mkdir -p DEBIAN + cat > DEBIAN/control <<-HERE + Package: $TERMUX_PKG_NAME + Architecture: ${TERMUX_ARCH} + Installed-Size: ${TERMUX_PKG_INSTALLSIZE} + Maintainer: $TERMUX_PKG_MAINTAINER + Version: $TERMUX_PKG_FULLVERSION + Homepage: $TERMUX_PKG_HOMEPAGE + HERE + test ! -z "$TERMUX_PKG_BREAKS" && echo "Breaks: $TERMUX_PKG_BREAKS" >> DEBIAN/control + test ! -z "$TERMUX_PKG_PRE_DEPENDS" && echo "Pre-Depends: $TERMUX_PKG_PRE_DEPENDS" >> DEBIAN/control + test ! -z "$TERMUX_PKG_DEPENDS" && echo "Depends: $TERMUX_PKG_DEPENDS" >> DEBIAN/control + [ "$TERMUX_PKG_ESSENTIAL" = "true" ] && echo "Essential: yes" >> DEBIAN/control + test ! -z "$TERMUX_PKG_CONFLICTS" && echo "Conflicts: $TERMUX_PKG_CONFLICTS" >> DEBIAN/control + test ! -z "$TERMUX_PKG_RECOMMENDS" && echo "Recommends: $TERMUX_PKG_RECOMMENDS" >> DEBIAN/control + test ! -z "$TERMUX_PKG_REPLACES" && echo "Replaces: $TERMUX_PKG_REPLACES" >> DEBIAN/control + test ! -z "$TERMUX_PKG_PROVIDES" && echo "Provides: $TERMUX_PKG_PROVIDES" >> DEBIAN/control + test ! -z "$TERMUX_PKG_SUGGESTS" && echo "Suggests: $TERMUX_PKG_SUGGESTS" >> DEBIAN/control + echo "Description: $TERMUX_PKG_DESCRIPTION" >> DEBIAN/control + + # Create DEBIAN/conffiles (see https://www.debian.org/doc/debian-policy/ap-pkg-conffiles.html): + for f in $TERMUX_PKG_CONFFILES; do echo "$TERMUX_PREFIX/$f" >> DEBIAN/conffiles; done + + # Allow packages to create arbitrary control files. + # XXX: Should be done in a better way without a function? + cd DEBIAN + termux_step_create_debscripts + + # Create control.tar.xz + tar -cJf "$TERMUX_PKG_PACKAGEDIR/control.tar.xz" -H gnu . + + test ! -f "$TERMUX_COMMON_CACHEDIR/debian-binary" && echo "2.0" > "$TERMUX_COMMON_CACHEDIR/debian-binary" + TERMUX_PKG_DEBFILE=$TERMUX_OUTPUT_DIR/${TERMUX_PKG_NAME}${DEBUG}_${TERMUX_PKG_FULLVERSION}_${TERMUX_ARCH}.deb + # Create the actual .deb file: + ${AR-ar} cr "$TERMUX_PKG_DEBFILE" \ + "$TERMUX_COMMON_CACHEDIR/debian-binary" \ + "$TERMUX_PKG_PACKAGEDIR/control.tar.xz" \ + "$TERMUX_PKG_PACKAGEDIR/data.tar.xz" +} diff --git a/scripts/build/termux_step_create_pacman_install_hook.sh b/scripts/build/termux_step_create_pacman_install_hook.sh new file mode 100644 index 000000000..a80d5cd25 --- /dev/null +++ b/scripts/build/termux_step_create_pacman_install_hook.sh @@ -0,0 +1,32 @@ +termux_step_create_pacman_install_hook() { + # Unlike dpkg, pacman doesn't use separate scripts for package installation + # hooks. Instead it uses a single script with functions. + if [ -f "./preinst" ]; then + echo "pre_install() {" >> .INSTALL + cat preinst | grep -v '^#' >> .INSTALL + echo "}" >> .INSTALL + rm -f preinst + fi + if [ -f "./postinst" ]; then + echo "post_install() {" >> .INSTALL + cat postinst | grep -v '^#' >> .INSTALL + echo "}" >> .INSTALL + rm -f postinst + fi + if [ -f "./prerm" ]; then + echo "pre_remove() {" >> .INSTALL + cat prerm | grep -v '^#' >> .INSTALL + echo "}" >> .INSTALL + rm -f prerm + fi + if [ -f "./postrm" ]; then + echo "post_remove() {" >> .INSTALL + cat postrm | grep -v '^#' >> .INSTALL + echo "}" >> .INSTALL + rm -f postrm + fi + + # Conversion from dpkg triggers to libalpm hooks is not supported + # currently. Delete unneeded triggers file. + rm -f triggers +} diff --git a/scripts/build/termux_step_create_pacman_package.sh b/scripts/build/termux_step_create_pacman_package.sh new file mode 100644 index 000000000..0c79cc650 --- /dev/null +++ b/scripts/build/termux_step_create_pacman_package.sh @@ -0,0 +1,124 @@ +termux_step_create_pacman_package() { + local TERMUX_PKG_INSTALLSIZE + TERMUX_PKG_INSTALLSIZE=$(du -bs . | cut -f 1) + + # From here on TERMUX_ARCH is set to "all" if TERMUX_PKG_PLATFORM_INDEPENDENT is set by the package + [ "$TERMUX_PKG_PLATFORM_INDEPENDENT" = "true" ] && TERMUX_ARCH=any + + # Configuring the selection of a copress for a batch. + local COMPRESS + local PKG_FORMAT + case $TERMUX_PACMAN_PACKAGE_COMPRESSION in + "gzip") + COMPRESS=(gzip -c -f -n) + PKG_FORMAT="gz";; + "bzip2") + COMPRESS=(bzip2 -c -f) + PKG_FORMAT="bz2";; + "zstd") + COMPRESS=(zstd -c -z -q -) + PKG_FORMAT="zst";; + "lrzip") + COMPRESS=(lrzip -q) + PKG_FORMAT="lrz";; + "lzop") + COMPRESS=(lzop -q) + PKG_FORMAT="lzop";; + "lz4") + COMPRESS=(lz4 -q) + PKG_FORMAT="lz4";; + "lzip") + COMPRESS=(lzip -c -f) + PKG_FORMAT="lz";; + "xz" | *) + COMPRESS=(xz -c -z -) + PKG_FORMAT="xz";; + esac + + local PACMAN_FILE=$TERMUX_OUTPUT_DIR/${TERMUX_PKG_NAME}${DEBUG}-${TERMUX_PKG_FULLVERSION_FOR_PACMAN}-${TERMUX_ARCH}.pkg.tar.${PKG_FORMAT} + + local BUILD_DATE + BUILD_DATE=$(date +%s) + + # Package metadata. + { + echo "pkgname = $TERMUX_PKG_NAME" + echo "pkgbase = $TERMUX_PKG_NAME" + echo "pkgver = $TERMUX_PKG_FULLVERSION_FOR_PACMAN" + echo "pkgdesc = $(echo "$TERMUX_PKG_DESCRIPTION" | tr '\n' ' ')" + echo "url = $TERMUX_PKG_HOMEPAGE" + echo "builddate = $BUILD_DATE" + echo "packager = $TERMUX_PKG_MAINTAINER" + echo "size = $TERMUX_PKG_INSTALLSIZE" + echo "arch = $TERMUX_ARCH" + + if [ -n "$TERMUX_PKG_LICENSE" ]; then + tr ',' '\n' <<< "$TERMUX_PKG_LICENSE" | awk '{ printf "license = %s\n", $0 }' + fi + + if [ -n "$TERMUX_PKG_REPLACES" ]; then + tr ',' '\n' <<< "$TERMUX_PKG_REPLACES" | sed 's|(||g; s|)||g; s| ||g; s|>>|>|g; s|<<|<|g' | awk '{ printf "replaces = %s\n", $1 }' + fi + + if [ -n "$TERMUX_PKG_CONFLICTS" ]; then + tr ',' '\n' <<< "$TERMUX_PKG_CONFLICTS" | sed 's|(||g; s|)||g; s| ||g; s|>>|>|g; s|<<|<|g' | awk '{ printf "conflict = %s\n", $1 }' + fi + + if [ -n "$TERMUX_PKG_BREAKS" ]; then + tr ',' '\n' <<< "$TERMUX_PKG_BREAKS" | sed 's|(||g; s|)||g; s| ||g; s|>>|>|g; s|<<|<|g' | awk '{ printf "conflict = %s\n", $1 }' + fi + + if [ -n "$TERMUX_PKG_PROVIDES" ]; then + tr ',' '\n' <<< "$TERMUX_PKG_PROVIDES" | sed 's|(||g; s|)||g; s| ||g; s|>>|>|g; s|<<|<|g' | awk '{ printf "provides = %s\n", $1 }' + fi + + if [ -n "$TERMUX_PKG_DEPENDS" ]; then + tr ',' '\n' <<< "$TERMUX_PKG_DEPENDS" | sed 's|(||g; s|)||g; s| ||g; s|>>|>|g; s|<<|<|g' | awk '{ printf "depend = %s\n", $1 }' | sed 's/|.*//' + fi + + if [ -n "$TERMUX_PKG_RECOMMENDS" ]; then + tr ',' '\n' <<< "$TERMUX_PKG_RECOMMENDS" | awk '{ printf "optdepend = %s\n", $1 }' + fi + + if [ -n "$TERMUX_PKG_SUGGESTS" ]; then + tr ',' '\n' <<< "$TERMUX_PKG_SUGGESTS" | awk '{ printf "optdepend = %s\n", $1 }' + fi + + if [ -n "$TERMUX_PKG_BUILD_DEPENDS" ]; then + tr ',' '\n' <<< "$TERMUX_PKG_BUILD_DEPENDS" | sed 's|(||g; s|)||g; s| ||g; s|>>|>|g; s|<<|<|g' | awk '{ printf "makedepend = %s\n", $1 }' + fi + + if [ -n "$TERMUX_PKG_CONFFILES" ]; then + tr ',' '\n' <<< "$TERMUX_PKG_CONFFILES" | awk '{ printf "backup = '"${TERMUX_PREFIX:1}"'/%s\n", $1 }' + fi + + if [ -n "$TERMUX_PKG_GROUPS" ]; then + tr ',' '\n' <<< "${TERMUX_PKG_GROUPS/#, /}" | awk '{ printf "group = %s\n", $1 }' + fi + } > .PKGINFO + + # Build metadata. + { + echo "format = 2" + echo "pkgname = $TERMUX_PKG_NAME" + echo "pkgbase = $TERMUX_PKG_NAME" + echo "pkgver = $TERMUX_PKG_FULLVERSION_FOR_PACMAN" + echo "pkgarch = $TERMUX_ARCH" + echo "packager = $TERMUX_PKG_MAINTAINER" + echo "builddate = $BUILD_DATE" + } > .BUILDINFO + + # Write installation hooks. + termux_step_create_debscripts + termux_step_create_pacman_install_hook + + # Create package + shopt -s dotglob globstar + printf '%s\0' **/* | bsdtar -cnf - --format=mtree \ + --options='!all,use-set,type,uid,gid,mode,time,size,md5,sha256,link' \ + --null --files-from - --exclude .MTREE | \ + gzip -c -f -n > .MTREE + printf '%s\0' **/* | bsdtar --no-fflags -cnf - --null --files-from - | \ + $COMPRESS > "$PACMAN_FILE" + shopt -u dotglob globstar +} diff --git a/scripts/build/termux_step_create_timestamp_file.sh b/scripts/build/termux_step_create_timestamp_file.sh new file mode 100644 index 000000000..c847d2c15 --- /dev/null +++ b/scripts/build/termux_step_create_timestamp_file.sh @@ -0,0 +1,9 @@ +termux_step_create_timestamp_file() { + # Keep track of when build started so we can see what files + # have been created. We start by sleeping so that any + # generated files (such as zlib.pc) get an older timestamp + # than the TERMUX_BUILD_TS_FILE. + sleep 1 + TERMUX_BUILD_TS_FILE=$TERMUX_PKG_TMPDIR/timestamp_$TERMUX_PKG_NAME + touch "$TERMUX_BUILD_TS_FILE" +} diff --git a/scripts/build/termux_step_extract_into_massagedir.sh b/scripts/build/termux_step_extract_into_massagedir.sh new file mode 100644 index 000000000..eb7e5bc30 --- /dev/null +++ b/scripts/build/termux_step_extract_into_massagedir.sh @@ -0,0 +1,15 @@ +termux_step_extract_into_massagedir() { + local TARBALL_ORIG=$TERMUX_PKG_PACKAGEDIR/${TERMUX_PKG_NAME}_orig.tar.gz + + # Build diff tar with what has changed during the build: + cd $TERMUX_PREFIX + tar -N "$TERMUX_BUILD_TS_FILE" \ + --exclude='lib/libutil.so' --exclude='tmp' \ + -czf "$TARBALL_ORIG" . + + # Extract tar in order to massage it + mkdir -p "$TERMUX_PKG_MASSAGEDIR/$TERMUX_PREFIX" + cd "$TERMUX_PKG_MASSAGEDIR/$TERMUX_PREFIX" + tar xf "$TARBALL_ORIG" + rm "$TARBALL_ORIG" +} diff --git a/scripts/build/termux_step_finish_build.sh b/scripts/build/termux_step_finish_build.sh new file mode 100644 index 000000000..4186fa44d --- /dev/null +++ b/scripts/build/termux_step_finish_build.sh @@ -0,0 +1,9 @@ +termux_step_finish_build() { + echo "termux - build of '$TERMUX_PKG_NAME' done" + test -t 1 && printf "\033]0;%s - DONE\007" "$TERMUX_PKG_NAME" + + mkdir -p "$TERMUX_BUILT_PACKAGES_DIRECTORY" + echo "$TERMUX_PKG_FULLVERSION" > "$TERMUX_BUILT_PACKAGES_DIRECTORY/$TERMUX_PKG_NAME" + + exit 0 +} diff --git a/scripts/build/termux_step_get_dependencies.sh b/scripts/build/termux_step_get_dependencies.sh new file mode 100644 index 000000000..b221b4810 --- /dev/null +++ b/scripts/build/termux_step_get_dependencies.sh @@ -0,0 +1,74 @@ +termux_step_get_dependencies() { + if [ "$TERMUX_SKIP_DEPCHECK" = false ] && [ "$TERMUX_INSTALL_DEPS" = true ] && [ "$TERMUX_PKG_METAPACKAGE" = "false" ]; then + # Download repo files + termux_get_repo_files + + # When doing build on device, ensure that apt lists are up-to-date. + if [ "$TERMUX_ON_DEVICE_BUILD" = "true" ]; then + case "$TERMUX_APP_PACKAGE_MANAGER" in + "apt") apt update;; + "pacman") pacman -Sy;; + esac + fi + + # Download dependencies + while read PKG PKG_DIR; do + if [ -z $PKG ]; then + continue + elif [ "$PKG" = "ERROR" ]; then + termux_error_exit "Obtaining buildorder failed" + fi + # 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..." + fi + + if [ -e "$TERMUX_BUILT_PACKAGES_DIRECTORY/$PKG" ]; then + if [ "$(cat "$TERMUX_BUILT_PACKAGES_DIRECTORY/$PKG")" = "$DEP_VERSION" ]; then + continue + 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 -I --format $TERMUX_PACKAGE_FORMAT "${PKG_DIR}" + continue + fi + if [ "$TERMUX_ON_DEVICE_BUILD" = "false" ]; then + if [ ! "$TERMUX_QUIET_BUILD" = true ]; then + echo "extracting $PKG..." + fi + ( + cd $TERMUX_COMMON_CACHEDIR-$DEP_ARCH + ar x ${PKG}_${DEP_VERSION}_${DEP_ARCH}.deb data.tar.xz + if tar -tf data.tar.xz|grep "^./$">/dev/null; then + # Strip prefixed ./, to avoid possible + # permission errors from tar + tar -xf data.tar.xz --strip-components=1 \ + --no-overwrite-dir -C / + else + tar -xf data.tar.xz --no-overwrite-dir -C / + 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 + # Build dependencies + while read PKG PKG_DIR; do + if [ -z $PKG ]; then + continue + 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 -s --format $TERMUX_PACKAGE_FORMAT "${PKG_DIR}" + done<<<$(./scripts/buildorder.py "$TERMUX_PKG_BUILDER_DIR" $TERMUX_PACKAGES_DIRECTORIES || echo "ERROR") + fi +} diff --git a/scripts/build/termux_step_handle_buildarch.sh b/scripts/build/termux_step_handle_buildarch.sh new file mode 100644 index 000000000..141d3812d --- /dev/null +++ b/scripts/build/termux_step_handle_buildarch.sh @@ -0,0 +1,30 @@ +termux_step_handle_buildarch() { + [ "$TERMUX_ON_DEVICE_BUILD" = "true" ] && return + + # If $TERMUX_PREFIX already exists, it may have been built for a different arch + local TERMUX_ARCH_FILE=/data/TERMUX_ARCH + if [ -f "${TERMUX_ARCH_FILE}" ]; then + local TERMUX_PREVIOUS_ARCH + TERMUX_PREVIOUS_ARCH=$(cat $TERMUX_ARCH_FILE) + if [ "$TERMUX_PREVIOUS_ARCH" != "$TERMUX_ARCH" ]; then + local TERMUX_DATA_BACKUPDIRS=$TERMUX_TOPDIR/_databackups + mkdir -p "$TERMUX_DATA_BACKUPDIRS" + local TERMUX_DATA_PREVIOUS_BACKUPDIR=$TERMUX_DATA_BACKUPDIRS/$TERMUX_PREVIOUS_ARCH + local TERMUX_DATA_CURRENT_BACKUPDIR=$TERMUX_DATA_BACKUPDIRS/$TERMUX_ARCH + # Save current /data (removing old backup if any) + if test -e "$TERMUX_DATA_PREVIOUS_BACKUPDIR"; then + termux_error_exit "Directory already exists" + fi + if [ -d /data/data ]; then + mv /data/data "$TERMUX_DATA_PREVIOUS_BACKUPDIR" + fi + # Restore new one (if any) + if [ -d "$TERMUX_DATA_CURRENT_BACKUPDIR" ]; then + mv "$TERMUX_DATA_CURRENT_BACKUPDIR" /data/data + fi + fi + fi + + # Keep track of current arch we are building for. + echo "$TERMUX_ARCH" > $TERMUX_ARCH_FILE +} diff --git a/scripts/build/termux_step_handle_hostbuild.sh b/scripts/build/termux_step_handle_hostbuild.sh new file mode 100644 index 000000000..039f12b78 --- /dev/null +++ b/scripts/build/termux_step_handle_hostbuild.sh @@ -0,0 +1,18 @@ +termux_step_handle_hostbuild() { + [ "$TERMUX_PKG_METAPACKAGE" = "true" ] && return + [ "$TERMUX_PKG_HOSTBUILD" = "false" ] && return + + cd "$TERMUX_PKG_SRCDIR" + for patch in $TERMUX_PKG_BUILDER_DIR/*.patch.beforehostbuild; do + echo "Applying patch: $(basename $patch)" + test -f "$patch" && sed "s%\@TERMUX_PREFIX\@%${TERMUX_PREFIX}%g" "$patch" | patch --silent -p1 + done + + if [ ! -f "$TERMUX_HOSTBUILD_MARKER" ]; then + rm -Rf "$TERMUX_PKG_HOSTBUILD_DIR" + mkdir -p "$TERMUX_PKG_HOSTBUILD_DIR" + cd "$TERMUX_PKG_HOSTBUILD_DIR" + termux_step_host_build + touch "$TERMUX_HOSTBUILD_MARKER" + fi +} diff --git a/scripts/build/termux_step_host_build.sh b/scripts/build/termux_step_host_build.sh new file mode 100644 index 000000000..1705bd4e8 --- /dev/null +++ b/scripts/build/termux_step_host_build.sh @@ -0,0 +1,4 @@ +termux_step_host_build() { + "$TERMUX_PKG_SRCDIR/configure" ${TERMUX_PKG_EXTRA_HOSTBUILD_CONFIGURE_ARGS} + make -j "$TERMUX_MAKE_PROCESSES" +} diff --git a/scripts/build/termux_step_install_license.sh b/scripts/build/termux_step_install_license.sh new file mode 100644 index 000000000..1d4b1a576 --- /dev/null +++ b/scripts/build/termux_step_install_license.sh @@ -0,0 +1,78 @@ +termux_step_install_license() { + [ "$TERMUX_PKG_METAPACKAGE" = "true" ] && return + + mkdir -p "$TERMUX_PREFIX/share/doc/$TERMUX_PKG_NAME" + local LICENSE + local COUNTER=0 + if [ ! "${TERMUX_PKG_LICENSE_FILE}" = "" ]; then + INSTALLED_LICENSES=() + COUNTER=1 + while read -r LICENSE; do + if [ ! -f "$TERMUX_PKG_SRCDIR/$LICENSE" ]; then + termux_error_exit "$TERMUX_PKG_SRCDIR/$LICENSE does not exist" + fi + if [[ " ${INSTALLED_LICENSES[@]} " =~ " $(basename $LICENSE) " ]]; then + # We have already installed a license file named $(basename $LICENSE) so add a suffix to it + TARGET="$TERMUX_PREFIX/share/doc/${TERMUX_PKG_NAME}/$(basename $LICENSE).$COUNTER" + COUNTER=$((COUNTER + 1)) + else + TARGET="$TERMUX_PREFIX/share/doc/${TERMUX_PKG_NAME}/$(basename $LICENSE)" + INSTALLED_LICENSES+=("$(basename $LICENSE)") + fi + cp -f "${TERMUX_PKG_SRCDIR}/${LICENSE}" "$TARGET" + done < <(echo "$TERMUX_PKG_LICENSE_FILE" | sed "s/,/\n/g") + else + while read -r LICENSE; do + # These licenses contain copyright information, so + # we cannot use a generic license file + if [ "$LICENSE" == "MIT" ] || \ + [ "$LICENSE" == "ISC" ] || \ + [ "$LICENSE" == "PythonPL" ] || \ + [ "$LICENSE" == "Openfont-1.1" ] || \ + [ "$LICENSE" == "ZLIB" ] || \ + [ "$LICENSE" == "Libpng" ] || \ + [ "$LICENSE" == "BSD" ] || \ + [ "$LICENSE" == "BSD 2-Clause" ] || \ + [ "$LICENSE" == "BSD 3-Clause" ] || \ + [ "$LICENSE" == "BSD Simplified" ]; then + for FILE in LICENSE \ + LICENSE.md \ + LICENSE.txt \ + LICENSE.TXT \ + COPYING \ + COPYRIGHT \ + Copyright.txt \ + Copyright \ + LICENCE \ + License \ + license \ + license.md \ + License.txt \ + license.txt \ + licence; do + if [ -f "$TERMUX_PKG_SRCDIR/$FILE" ]; then + if [[ $COUNTER -gt 0 ]]; then + cp -f "${TERMUX_PKG_SRCDIR}/$FILE" "${TERMUX_PREFIX}/share/doc/${TERMUX_PKG_NAME}/LICENSE.${COUNTER}" + else + cp -f "${TERMUX_PKG_SRCDIR}/$FILE" "${TERMUX_PREFIX}/share/doc/${TERMUX_PKG_NAME}/LICENSE" + fi + COUNTER=$((COUNTER + 1)) + fi + done + elif [ -f "$TERMUX_SCRIPTDIR/packages/termux-licenses/LICENSES/${LICENSE}.txt" ]; then + if [[ $COUNTER -gt 0 ]]; then + ln -sf "../../LICENSES/${LICENSE}.txt" "$TERMUX_PREFIX/share/doc/$TERMUX_PKG_NAME/LICENSE.${COUNTER}" + else + ln -sf "../../LICENSES/${LICENSE}.txt" "$TERMUX_PREFIX/share/doc/$TERMUX_PKG_NAME/LICENSE" + fi + COUNTER=$((COUNTER + 1)) + fi + done < <(echo "$TERMUX_PKG_LICENSE" | sed "s/,/\n/g") + + for LICENSE in "$TERMUX_PREFIX/share/doc/$TERMUX_PKG_NAME"/LICENSE*; do + if [ "$LICENSE" = "$TERMUX_PREFIX/share/doc/$TERMUX_PKG_NAME/LICENSE*" ]; then + termux_error_exit "No LICENSE file was installed for $TERMUX_PKG_NAME" + fi + done + fi +} diff --git a/scripts/build/termux_step_install_service_scripts.sh b/scripts/build/termux_step_install_service_scripts.sh new file mode 100644 index 000000000..890e23fbd --- /dev/null +++ b/scripts/build/termux_step_install_service_scripts.sh @@ -0,0 +1,49 @@ +termux_step_install_service_scripts() { + array_length=${#TERMUX_PKG_SERVICE_SCRIPT[@]} + if [ $array_length -eq 0 ]; then return; fi + + # TERMUX_PKG_SERVICE_SCRIPT should have the structure =("daemon name" 'script to execute') + if [ $(( $array_length & 1 )) -eq 1 ]; then + termux_error_exit "TERMUX_PKG_SERVICE_SCRIPT has to be an array of even length" + fi + + mkdir -p $TERMUX_PREFIX/var/service + cd $TERMUX_PREFIX/var/service + for ((i=0; i<${array_length}; i+=2)); do + mkdir -p ${TERMUX_PKG_SERVICE_SCRIPT[$i]} + # We unlink ${TERMUX_PKG_SERVICE_SCRIPT[$i]}/run if it exists to + # allow it to be overwritten through TERMUX_PKG_SERVICE_SCRIPT + if [ -L "${TERMUX_PKG_SERVICE_SCRIPT[$i]}/run" ]; then + unlink "${TERMUX_PKG_SERVICE_SCRIPT[$i]}/run" + fi + echo "#!$TERMUX_PREFIX/bin/sh" > ${TERMUX_PKG_SERVICE_SCRIPT[$i]}/run + echo -e ${TERMUX_PKG_SERVICE_SCRIPT[$((i + 1))]} >> ${TERMUX_PKG_SERVICE_SCRIPT[$i]}/run + + # Do not add service script to CONFFILES if it already exists there + if [[ $TERMUX_PKG_CONFFILES != *${TERMUX_PKG_SERVICE_SCRIPT[$i]}/run* ]]; then + TERMUX_PKG_CONFFILES+=" var/service/${TERMUX_PKG_SERVICE_SCRIPT[$i]}/run" + fi + + chmod +x ${TERMUX_PKG_SERVICE_SCRIPT[$i]}/run + + # Avoid creating service//log/log/ + if [ "${TERMUX_PKG_SERVICE_SCRIPT[$i]: -4}" != "/log" ]; then + touch ${TERMUX_PKG_SERVICE_SCRIPT[$i]}/down + TERMUX_PKG_CONFFILES+=" var/service/${TERMUX_PKG_SERVICE_SCRIPT[$i]}/down" + local _log_run=${TERMUX_PKG_SERVICE_SCRIPT[$i]}/log/run + rm -rf "${_log_run}" + mkdir -p "$(dirname "${_log_run}")" + cat <<-EOF > "${_log_run}" + #!$TERMUX_PREFIX/bin/sh + svlogger="$TERMUX_PREFIX/share/termux-services/svlogger" + exec "\${svlogger}" "\$@" + EOF + chmod 0700 "${_log_run}" + + TERMUX_PKG_CONFFILES+=" + var/service/${TERMUX_PKG_SERVICE_SCRIPT[$i]}/log/run + var/service/${TERMUX_PKG_SERVICE_SCRIPT[$i]}/log/down + " + fi + done +} diff --git a/scripts/build/termux_step_make.sh b/scripts/build/termux_step_make.sh new file mode 100644 index 000000000..5e7666890 --- /dev/null +++ b/scripts/build/termux_step_make.sh @@ -0,0 +1,20 @@ +termux_step_make() { + [ "$TERMUX_PKG_METAPACKAGE" = "true" ] && return + + local QUIET_BUILD= + if [ "$TERMUX_QUIET_BUILD" = true ]; then + QUIET_BUILD="-s" + fi + + if test -f build.ninja; then + ninja -w dupbuild=warn -j $TERMUX_MAKE_PROCESSES + elif ls ./*.cabal &>/dev/null; then + termux-ghc-setup -j$TERMUX_MAKE_PROCESSES build + elif ls ./*akefile &>/dev/null || [ ! -z "$TERMUX_PKG_EXTRA_MAKE_ARGS" ]; then + if [ -z "$TERMUX_PKG_EXTRA_MAKE_ARGS" ]; then + make -j $TERMUX_MAKE_PROCESSES $QUIET_BUILD + else + make -j $TERMUX_MAKE_PROCESSES $QUIET_BUILD ${TERMUX_PKG_EXTRA_MAKE_ARGS} + fi + fi +} diff --git a/scripts/build/termux_step_make_install.sh b/scripts/build/termux_step_make_install.sh new file mode 100644 index 000000000..41b8207a5 --- /dev/null +++ b/scripts/build/termux_step_make_install.sh @@ -0,0 +1,46 @@ +termux_step_make_install() { + [ "$TERMUX_PKG_METAPACKAGE" = "true" ] && return + + if test -f build.ninja; then + ninja -w dupbuild=warn -j $TERMUX_MAKE_PROCESSES install + elif ls ./*.cabal &>/dev/null; then + termux-ghc-setup copy + if [ "${TERMUX_PKG_IS_HASKELL_LIB}" = true ]; then + termux-ghc-setup register --gen-script + termux-ghc-setup unregister --gen-script + + install -Dm744 register.sh "${TERMUX_PREFIX}"/share/haskell/register/"${TERMUX_PKG_NAME}".sh + install -Dm744 unregister.sh "${TERMUX_PREFIX}"/share/haskell/unregister/"${TERMUX_PKG_NAME}".sh + + sed -i -r -e "s|$(command -v termux-ghc-pkg)|${TERMUX_PREFIX}/bin/ghc-pkg|g" \ + -e "s|ghc-pkg.*update[^ ]* |&'--force' |" \ + -e "s|export PATH=.*||g" \ + "${TERMUX_PREFIX}"/share/haskell/register/"${TERMUX_PKG_NAME}".sh + + sed -i -r -e "s|$(command -v termux-ghc-pkg)|${TERMUX_PREFIX}/bin/ghc-pkg|g" \ + -e "s|export PATH=.*||g" \ + -e "s|ghc-pkg.*unregister[^ ]* |&'--force' |" \ + "${TERMUX_PREFIX}"/share/haskell/unregister/"${TERMUX_PKG_NAME}".sh + fi + + elif ls ./*akefile &>/dev/null || [ -n "$TERMUX_PKG_EXTRA_MAKE_ARGS" ]; then + : "${TERMUX_PKG_MAKE_INSTALL_TARGET:="install"}" + # Some packages have problem with parallell install, and it does not buy much, so use -j 1. + if [ -z "$TERMUX_PKG_EXTRA_MAKE_ARGS" ]; then + make -j 1 ${TERMUX_PKG_MAKE_INSTALL_TARGET} + else + make -j 1 ${TERMUX_PKG_EXTRA_MAKE_ARGS} ${TERMUX_PKG_MAKE_INSTALL_TARGET} + fi + elif test -f Cargo.toml; then + termux_setup_rust + cargo install \ + --jobs $TERMUX_MAKE_PROCESSES \ + --path . \ + --force \ + --locked \ + --no-track \ + --target $CARGO_TARGET_NAME \ + --root $TERMUX_PREFIX \ + $TERMUX_PKG_EXTRA_CONFIGURE_ARGS + fi +} diff --git a/scripts/build/termux_step_massage.sh b/scripts/build/termux_step_massage.sh new file mode 100644 index 000000000..eae4be1c8 --- /dev/null +++ b/scripts/build/termux_step_massage.sh @@ -0,0 +1,114 @@ +termux_step_massage() { + [ "$TERMUX_PKG_METAPACKAGE" = "true" ] && return + + cd "$TERMUX_PKG_MASSAGEDIR/$TERMUX_PREFIX" + + # Remove lib/charset.alias which is installed by gettext-using packages: + rm -f lib/charset.alias + + # Remove locale files we're not interested in:: + rm -Rf share/locale + + # Remove old kept libraries (readline): + find . -name '*.old' -print0 | xargs -0 -r rm -f + + # Move over sbin to bin: + for file in sbin/*; do if test -f "$file"; then mv "$file" bin/; fi; done + + # Remove world permissions and make sure that user still have read-write permissions. + chmod -Rf u+rw,g-rwx,o-rwx . || true + + if [ "$TERMUX_DEBUG_BUILD" = "false" ]; then + # Strip binaries. file(1) may fail for certain unusual files, so disable pipefail. + set +e +o pipefail + find . \( -path "./bin/*" -o -path "./lib/*" -o -path "./libexec/*" \) -type f | + xargs -r file | grep -E "ELF .+ (executable|shared object)" | cut -f 1 -d : | + xargs -r "$STRIP" --strip-unneeded --preserve-dates + set -e -o pipefail + fi + + if [ "$TERMUX_PKG_NO_ELF_CLEANER" != "true" ]; then + # Remove entries unsupported by Android's linker: + find . \( -path "./bin/*" -o -path "./lib/*" -o -path "./libexec/*" -o -path "./opt/*" \) -type f -print0 | xargs -r -0 "$TERMUX_ELF_CLEANER" + fi + + if [ "$TERMUX_PKG_NO_SHEBANG_FIX" != "true" ]; then + # Fix shebang paths: + while IFS= read -r -d '' file; do + head -c 100 "$file" | grep -E "^#\!.*\\/bin\\/.*" | grep -q -E -v "^#\! ?\\/system" && + sed --follow-symlinks -i -E "1 s@^#\!(.*)/bin/(.*)@#\!$TERMUX_PREFIX/bin/\2@" "$file" + done < <(find -L . -type f -print0) + fi + + # Delete the info directory file. + rm -rf ./share/info/dir + + # Mostly specific to X11-related packages. + rm -f ./share/icons/hicolor/icon-theme.cache + + test ! -z "$TERMUX_PKG_RM_AFTER_INSTALL" && rm -Rf $TERMUX_PKG_RM_AFTER_INSTALL + + find . -type d -empty -delete # Remove empty directories + + if [ -d share/man ]; then + # Remove non-english man pages: + find share/man -mindepth 1 -maxdepth 1 -type d ! -name man\* | xargs -r rm -rf + + # Compress man pages with gzip: + find share/man -type f ! -iname \*.gz -print0 | xargs -r -0 gzip + + # Update man page symlinks, e.g. unzstd.1 -> zstd.1: + while IFS= read -r -d '' file; do + local _link_value + _link_value=$(readlink $file) + rm $file + ln -s $_link_value.gz $file.gz + done < <(find share/man -type l ! -iname \*.gz -print0) + fi + + # Check so files were actually installed. Exclude + # share/doc/$TERMUX_PKG_NAME/ as a license file is always + # installed there. + if [ "$(find . -type f -not -path "./share/doc/$TERMUX_PKG_NAME/*")" = "" ]; then + termux_error_exit "No files in package. Maybe you need to run autoreconf -fi before configuring?" + fi + + local HARDLINKS + HARDLINKS="$(find . -type f -links +1)" + if [ -n "$HARDLINKS" ]; then + termux_error_exit "Package contains hard links: $HARDLINKS" + fi + + # Check so that package is not affected by https://github.com/android/ndk/issues/1614 + SYMBOLS="$(llvm-readelf -s $($TERMUX_HOST_PLATFORM-clang -print-libgcc-file-name) | grep "FUNC GLOBAL HIDDEN" | awk '{print $8}')" + # Also check for unresolved symbols defined in libandroid-* (#9944) + SYMBOLS+=" $(echo libandroid_{sem_{open,close,unlink},shm{ctl,get,at,dt}})" + LIBRARIES="" + if [ -d "lib" ]; then + LIBRARIES="$(find lib -name "*.so")" + fi + for lib in $LIBRARIES; do + for sym in $SYMBOLS; do + if ! llvm-readelf -h $lib &> /dev/null; then + continue + fi + if llvm-readelf -s $lib | egrep 'NOTYPE[[:space:]]+GLOBAL[[:space:]]+DEFAULT[[:space:]]+UND[[:space:]]+'$sym'$' &> /dev/null; then + termux_error_exit "$lib contains undefined symbol $sym" + fi + done + done + + if [ "$TERMUX_PACKAGE_FORMAT" = "debian" ]; then + termux_create_debian_subpackages + elif [ "$TERMUX_PACKAGE_FORMAT" = "pacman" ]; then + termux_create_pacman_subpackages + fi + + # Remove unnecessary files in haskell pacakges: + if [[ "${TERMUX_PKG_NAME}" != "ghc-libs" ]] && [[ "${TERMUX_PKG_NAME}" != "ghc" ]]; then + test -d ./lib/ghc-* && rm -rf ./lib/ghc-* 2>/dev/null # Remove full ghc-* dir since cross compiler installs packages in "./lib/${TERMUX_ARCH}-android-ghc-X.Y.Z" + fi + + # .. remove empty directories (NOTE: keep this last): + find . -type d -empty -delete +} diff --git a/scripts/build/termux_step_override_config_scripts.sh b/scripts/build/termux_step_override_config_scripts.sh new file mode 100644 index 000000000..0b9c635c4 --- /dev/null +++ b/scripts/build/termux_step_override_config_scripts.sh @@ -0,0 +1,44 @@ +termux_step_override_config_scripts() { + if [ "$TERMUX_ON_DEVICE_BUILD" = true ]; then + return + fi + + # Make $TERMUX_PREFIX/bin/sh executable on the builder, so that build + # scripts can assume that it works on both builder and host later on: + ln -sf /bin/sh "$TERMUX_PREFIX/bin/sh" + + if [ "$TERMUX_INSTALL_DEPS" = false ]; then + return + fi + + if [ "$TERMUX_PKG_DEPENDS" != "${TERMUX_PKG_DEPENDS/libllvm/}" ]; then + LLVM_DEFAULT_TARGET_TRIPLE=$TERMUX_HOST_PLATFORM + if [ $TERMUX_ARCH = "arm" ]; then + LLVM_TARGET_ARCH=ARM + elif [ $TERMUX_ARCH = "aarch64" ]; then + LLVM_TARGET_ARCH=AArch64 + elif [ $TERMUX_ARCH = "i686" ]; then + LLVM_TARGET_ARCH=X86 + elif [ $TERMUX_ARCH = "x86_64" ]; then + LLVM_TARGET_ARCH=X86 + fi + LIBLLVM_VERSION=$(. $TERMUX_SCRIPTDIR/packages/libllvm/build.sh; echo $TERMUX_PKG_VERSION) + sed $TERMUX_SCRIPTDIR/packages/libllvm/llvm-config.in \ + -e "s|@TERMUX_PKG_VERSION@|$LIBLLVM_VERSION|g" \ + -e "s|@TERMUX_PREFIX@|$TERMUX_PREFIX|g" \ + -e "s|@TERMUX_PKG_SRCDIR@|$TERMUX_TOPDIR/libllvm/src|g" \ + -e "s|@LLVM_TARGET_ARCH@|$LLVM_TARGET_ARCH|g" \ + -e "s|@LLVM_DEFAULT_TARGET_TRIPLE@|$LLVM_DEFAULT_TARGET_TRIPLE|g" \ + -e "s|@TERMUX_ARCH@|$TERMUX_ARCH|g" > $TERMUX_PREFIX/bin/llvm-config + chmod 755 $TERMUX_PREFIX/bin/llvm-config + fi + + if [ "$TERMUX_PKG_DEPENDS" != "${TERMUX_PKG_DEPENDS/postgresql/}" ]; then + local postgresql_version=$(. $TERMUX_SCRIPTDIR/packages/postgresql/build.sh; echo $TERMUX_PKG_VERSION) + sed $TERMUX_SCRIPTDIR/packages/postgresql/pg_config.in \ + -e "s|@POSTGRESQL_VERSION@|$postgresql_version|g" \ + -e "s|@TERMUX_HOST_PLATFORM@|$TERMUX_HOST_PLATFORM|g" \ + -e "s|@TERMUX_PREFIX@|$TERMUX_PREFIX|g" > $TERMUX_PREFIX/bin/pg_config + chmod 755 $TERMUX_PREFIX/bin/pg_config + fi +} diff --git a/scripts/build/termux_step_patch_package.sh b/scripts/build/termux_step_patch_package.sh new file mode 100644 index 000000000..90e7ceb71 --- /dev/null +++ b/scripts/build/termux_step_patch_package.sh @@ -0,0 +1,31 @@ +termux_step_patch_package() { + [ "$TERMUX_PKG_METAPACKAGE" = "true" ] && return + + cd "$TERMUX_PKG_SRCDIR" + # Suffix patch with ".patch32" or ".patch64" to only apply for + # these bitnesses + local PATCHES=$(find $TERMUX_PKG_BUILDER_DIR -mindepth 1 -maxdepth 1 \ + -name \*.patch -o -name \*.patch$TERMUX_ARCH_BITS | sort) + local DEBUG_PATCHES="" + if [ "$TERMUX_DEBUG_BUILD" = "true" ]; then + DEBUG_PATCHES=$(find $TERMUX_PKG_BUILDER_DIR -mindepth 1 -maxdepth 1 -name \*.patch.debug | sort) + fi + local ON_DEVICE_PATCHES="" + # .patch.ondevice patches should only be applied when building + # on device + if [ "$TERMUX_ON_DEVICE_BUILD" = "true" ]; then + ON_DEVICE_PATCHES=$(find $TERMUX_PKG_BUILDER_DIR -mindepth 1 -maxdepth 1 -name \*.patch.ondevice | sort) + fi + shopt -s nullglob + for patch in $PATCHES $DEBUG_PATCHES $ON_DEVICE_PATCHES; do + echo "Applying patch: $(basename $patch)" + test -f "$patch" && sed \ + -e "s%\@TERMUX_APP_PACKAGE\@%${TERMUX_APP_PACKAGE}%g" \ + -e "s%\@TERMUX_BASE_DIR\@%${TERMUX_BASE_DIR}%g" \ + -e "s%\@TERMUX_CACHE_DIR\@%${TERMUX_CACHE_DIR}%g" \ + -e "s%\@TERMUX_HOME\@%${TERMUX_ANDROID_HOME}%g" \ + -e "s%\@TERMUX_PREFIX\@%${TERMUX_PREFIX}%g" \ + "$patch" | patch --silent -p1 + done + shopt -u nullglob +} diff --git a/scripts/build/termux_step_replace_guess_scripts.sh b/scripts/build/termux_step_replace_guess_scripts.sh new file mode 100644 index 000000000..cacb459ea --- /dev/null +++ b/scripts/build/termux_step_replace_guess_scripts.sh @@ -0,0 +1,7 @@ +termux_step_replace_guess_scripts() { + [ "$TERMUX_PKG_METAPACKAGE" = "true" ] && return + + cd "$TERMUX_PKG_SRCDIR" + find . -name config.sub -exec chmod u+w '{}' \; -exec cp "$TERMUX_SCRIPTDIR/scripts/config.sub" '{}' \; + find . -name config.guess -exec chmod u+w '{}' \; -exec cp "$TERMUX_SCRIPTDIR/scripts/config.guess" '{}' \; +} diff --git a/scripts/build/termux_step_setup_build_folders.sh b/scripts/build/termux_step_setup_build_folders.sh new file mode 100644 index 000000000..da3a1e7c9 --- /dev/null +++ b/scripts/build/termux_step_setup_build_folders.sh @@ -0,0 +1,39 @@ +termux_step_setup_build_folders() { + # Following directories may contain files with read-only + # permissions which makes them undeletable. We need to fix + # that. + [ -d "$TERMUX_PKG_BUILDDIR" ] && chmod +w -R "$TERMUX_PKG_BUILDDIR" || true + [ -d "$TERMUX_PKG_SRCDIR" ] && chmod +w -R "$TERMUX_PKG_SRCDIR" || true + if [ "$TERMUX_SKIP_DEPCHECK" = false ] && \ + [ "$TERMUX_INSTALL_DEPS" = true ] && \ + [ "$TERMUX_PKG_METAPACKAGE" = false ] && \ + [ "$TERMUX_NO_CLEAN" = false ] && \ + [ "$TERMUX_ON_DEVICE_BUILD" = false ]; then + # Remove all previously extracted/built files from + # $TERMUX_PREFIX: + rm -rf $TERMUX_PREFIX + rm -f $TERMUX_BUILT_PACKAGES_DIRECTORY/* + fi + + # Cleanup old build state: + rm -Rf "$TERMUX_PKG_BUILDDIR" \ + "$TERMUX_PKG_SRCDIR" + + # Cleanup old packaging state: + rm -Rf "$TERMUX_PKG_PACKAGEDIR" \ + "$TERMUX_PKG_TMPDIR" \ + "$TERMUX_PKG_MASSAGEDIR" + + # Ensure folders present (but not $TERMUX_PKG_SRCDIR, it will + # be created in build) + mkdir -p "$TERMUX_COMMON_CACHEDIR" \ + "$TERMUX_COMMON_CACHEDIR-$TERMUX_ARCH" \ + "$TERMUX_COMMON_CACHEDIR-all" \ + "$TERMUX_OUTPUT_DIR" \ + "$TERMUX_PKG_BUILDDIR" \ + "$TERMUX_PKG_PACKAGEDIR" \ + "$TERMUX_PKG_TMPDIR" \ + "$TERMUX_PKG_CACHEDIR" \ + "$TERMUX_PKG_MASSAGEDIR" \ + $TERMUX_PREFIX/{bin,etc,lib,libexec,share,share/LICENSES,tmp,include} +} diff --git a/scripts/build/termux_step_setup_toolchain.sh b/scripts/build/termux_step_setup_toolchain.sh new file mode 100644 index 000000000..c6e160888 --- /dev/null +++ b/scripts/build/termux_step_setup_toolchain.sh @@ -0,0 +1,221 @@ +termux_step_setup_toolchain() { + [ "$TERMUX_PKG_METAPACKAGE" = "true" ] && return + + export CFLAGS="" + export CPPFLAGS="" + export LDFLAGS="-L${TERMUX_PREFIX}/lib" + + export AS=$TERMUX_HOST_PLATFORM-clang + export CC=$TERMUX_HOST_PLATFORM-clang + export CXX=$TERMUX_HOST_PLATFORM-clang++ + export CPP=$TERMUX_HOST_PLATFORM-cpp + export LD=ld.lld + export AR=llvm-ar + export OBJCOPY=llvm-objcopy + export OBJDUMP=llvm-objdump + export RANLIB=llvm-ranlib + export READELF=llvm-readelf + export STRIP=llvm-strip + export NM=llvm-nm + + export TERMUX_HASKELL_LLVM_BACKEND="-fllvm --ghc-option=-fllvm" + if [ "${TERMUX_ARCH}" = "i686" ]; then + TERMUX_HASKELL_LLVM_BACKEND="" + fi + + export TERMUX_HASKELL_OPTIMISATION="-O" + if [ "${TERMUX_DEBUG_BUILD}" = true ]; then + TERMUX_HASKELL_OPTIMISATION="-O0" + fi + + if [ "$TERMUX_ON_DEVICE_BUILD" = "false" ]; then + export PATH=$TERMUX_STANDALONE_TOOLCHAIN/bin:$PATH + export CC_FOR_BUILD=gcc + export PKG_CONFIG=$TERMUX_STANDALONE_TOOLCHAIN/bin/pkg-config + export PKGCONFIG=$PKG_CONFIG + export CCTERMUX_HOST_PLATFORM=$TERMUX_HOST_PLATFORM$TERMUX_PKG_API_LEVEL + if [ $TERMUX_ARCH = arm ]; then + CCTERMUX_HOST_PLATFORM=armv7a-linux-androideabi$TERMUX_PKG_API_LEVEL + fi + LDFLAGS+=" -Wl,-rpath=$TERMUX_PREFIX/lib" + else + export CC_FOR_BUILD=$CC + # Some build scripts use environment variable 'PKG_CONFIG', so + # using this for on-device builds too. + export PKG_CONFIG=pkg-config + fi + export PKG_CONFIG_LIBDIR="$TERMUX_PKG_CONFIG_LIBDIR" + + if [ "$TERMUX_ARCH" = "arm" ]; then + # https://developer.android.com/ndk/guides/standalone_toolchain.html#abi_compatibility: + # "We recommend using the -mthumb compiler flag to force the generation of 16-bit Thumb-2 instructions". + # With r13 of the ndk ruby 2.4.0 segfaults when built on arm with clang without -mthumb. + CFLAGS+=" -march=armv7-a -mfpu=neon -mfloat-abi=softfp -mthumb" + LDFLAGS+=" -march=armv7-a" + export GOARCH=arm + export GOARM=7 + elif [ "$TERMUX_ARCH" = "i686" ]; then + # From $NDK/docs/CPU-ARCH-ABIS.html: + CFLAGS+=" -march=i686 -msse3 -mstackrealign -mfpmath=sse" + # i686 seem to explicitly require -fPIC, see + # https://github.com/termux/termux-packages/issues/7215#issuecomment-906154438 + CFLAGS+=" -fPIC" + export GOARCH=386 + export GO386=sse2 + elif [ "$TERMUX_ARCH" = "aarch64" ]; then + export GOARCH=arm64 + elif [ "$TERMUX_ARCH" = "x86_64" ]; then + export GOARCH=amd64 + else + termux_error_exit "Invalid arch '$TERMUX_ARCH' - support arches are 'arm', 'i686', 'aarch64', 'x86_64'" + fi + + # -static-openmp requires -fopenmp in LDFLAGS to work; hopefully this won't be problematic + # even when we don't have -fopenmp in CFLAGS / when we don't want to enable OpenMP + # We might also want to consider shipping libomp.so instead; since r21 + LDFLAGS+=" -fopenmp -static-openmp" + + # Android 7 started to support DT_RUNPATH (but not DT_RPATH). + LDFLAGS+=" -Wl,--enable-new-dtags" + + # Avoid linking extra (unneeded) libraries. + LDFLAGS+=" -Wl,--as-needed" + + # Basic hardening. + CFLAGS+=" -fstack-protector-strong" + LDFLAGS+=" -Wl,-z,relro,-z,now" + + if [ "$TERMUX_DEBUG_BUILD" = "true" ]; then + CFLAGS+=" -g3 -O1" + CPPFLAGS+=" -D_FORTIFY_SOURCE=2 -D__USE_FORTIFY_LEVEL=2" + else + CFLAGS+=" -Oz" + fi + + export CXXFLAGS="$CFLAGS" + export CPPFLAGS+=" -I${TERMUX_PREFIX}/include" + + # If libandroid-support is declared as a dependency, link to it explicitly: + if [ "$TERMUX_PKG_DEPENDS" != "${TERMUX_PKG_DEPENDS/libandroid-support/}" ]; then + LDFLAGS+=" -Wl,--no-as-needed,-landroid-support,--as-needed" + fi + + export GOOS=android + export CGO_ENABLED=1 + export GO_LDFLAGS="-extldflags=-pie" + export CGO_LDFLAGS="${LDFLAGS/-Wl,-z,relro,-z,now/}" + CGO_LDFLAGS="${LDFLAGS/-static-openmp/}" + export CGO_CFLAGS="-I$TERMUX_PREFIX/include" + export RUSTFLAGS="-C link-arg=-Wl,-rpath=$TERMUX_PREFIX/lib -C link-arg=-Wl,--enable-new-dtags" + + export ac_cv_func_getpwent=no + export ac_cv_func_endpwent=yes + export ac_cv_func_getpwnam=no + export ac_cv_func_getpwuid=no + export ac_cv_func_sigsetmask=no + export ac_cv_c_bigendian=no + + termux_setup_standalone_toolchain + + # On Android 7, libutil functionality is provided by libc. + # But many programs still may search for libutil. + if [ ! -f $TERMUX_PREFIX/lib/libutil.so ]; then + mkdir -p "$TERMUX_PREFIX/lib" + echo 'INPUT(-lc)' > $TERMUX_PREFIX/lib/libutil.so + fi +} + +termux_setup_standalone_toolchain() { + if [ "$TERMUX_ON_DEVICE_BUILD" = "true" ] || [ -d $TERMUX_STANDALONE_TOOLCHAIN ]; then + return + fi + + # Do not put toolchain in place until we are done with setup, to avoid having a half setup + # toolchain left in place if something goes wrong (or process is just aborted): + local _TERMUX_TOOLCHAIN_TMPDIR=${TERMUX_STANDALONE_TOOLCHAIN}-tmp + rm -Rf $_TERMUX_TOOLCHAIN_TMPDIR + + local _NDK_ARCHNAME=$TERMUX_ARCH + if [ "$TERMUX_ARCH" = "aarch64" ]; then + _NDK_ARCHNAME=arm64 + elif [ "$TERMUX_ARCH" = "i686" ]; then + _NDK_ARCHNAME=x86 + fi + cp $NDK/toolchains/llvm/prebuilt/linux-x86_64 $_TERMUX_TOOLCHAIN_TMPDIR -r + + # Remove android-support header wrapping not needed on android-21: + rm -Rf $_TERMUX_TOOLCHAIN_TMPDIR/sysroot/usr/local + + for HOST_PLAT in aarch64-linux-android armv7a-linux-androideabi i686-linux-android x86_64-linux-android; do + cp $_TERMUX_TOOLCHAIN_TMPDIR/bin/$HOST_PLAT$TERMUX_PKG_API_LEVEL-clang \ + $_TERMUX_TOOLCHAIN_TMPDIR/bin/$HOST_PLAT-clang + cp $_TERMUX_TOOLCHAIN_TMPDIR/bin/$HOST_PLAT$TERMUX_PKG_API_LEVEL-clang++ \ + $_TERMUX_TOOLCHAIN_TMPDIR/bin/$HOST_PLAT-clang++ + + cp $_TERMUX_TOOLCHAIN_TMPDIR/bin/$HOST_PLAT$TERMUX_PKG_API_LEVEL-clang \ + $_TERMUX_TOOLCHAIN_TMPDIR/bin/$HOST_PLAT-cpp + sed -i 's/clang/clang -E/' \ + $_TERMUX_TOOLCHAIN_TMPDIR/bin/$HOST_PLAT-cpp + + cp $_TERMUX_TOOLCHAIN_TMPDIR/bin/$HOST_PLAT-clang \ + $_TERMUX_TOOLCHAIN_TMPDIR/bin/$HOST_PLAT-gcc + cp $_TERMUX_TOOLCHAIN_TMPDIR/bin/$HOST_PLAT-clang++ \ + $_TERMUX_TOOLCHAIN_TMPDIR/bin/$HOST_PLAT-g++ + done + + cp $_TERMUX_TOOLCHAIN_TMPDIR/bin/armv7a-linux-androideabi$TERMUX_PKG_API_LEVEL-clang \ + $_TERMUX_TOOLCHAIN_TMPDIR/bin/arm-linux-androideabi-clang + cp $_TERMUX_TOOLCHAIN_TMPDIR/bin/armv7a-linux-androideabi$TERMUX_PKG_API_LEVEL-clang++ \ + $_TERMUX_TOOLCHAIN_TMPDIR/bin/arm-linux-androideabi-clang++ + cp $_TERMUX_TOOLCHAIN_TMPDIR/bin/armv7a-linux-androideabi-cpp \ + $_TERMUX_TOOLCHAIN_TMPDIR/bin/arm-linux-androideabi-cpp + + # Create a pkg-config wrapper. We use path to host pkg-config to + # avoid picking up a cross-compiled pkg-config later on. + local _HOST_PKGCONFIG + _HOST_PKGCONFIG=$(command -v pkg-config) + mkdir -p "$PKG_CONFIG_LIBDIR" + cat > $_TERMUX_TOOLCHAIN_TMPDIR/bin/pkg-config <<-HERE + #!/bin/sh + export PKG_CONFIG_DIR= + export PKG_CONFIG_LIBDIR=$PKG_CONFIG_LIBDIR + exec $_HOST_PKGCONFIG "\$@" + HERE + chmod +x $_TERMUX_TOOLCHAIN_TMPDIR/bin/pkg-config + + cd $_TERMUX_TOOLCHAIN_TMPDIR/sysroot + for f in $TERMUX_SCRIPTDIR/ndk-patches/*.patch; do + echo "Applying ndk-patch: $(basename $f)" + sed "s%\@TERMUX_PREFIX\@%${TERMUX_PREFIX}%g" "$f" | \ + sed "s%\@TERMUX_HOME\@%${TERMUX_ANDROID_HOME}%g" | \ + patch --silent -p1; + done + # libintl.h: Inline implementation gettext functions. + # langinfo.h: Inline implementation of nl_langinfo(). + cp "$TERMUX_SCRIPTDIR"/ndk-patches/{libintl.h,langinfo.h} usr/include + + # Remove because it is provided by libcap. + # Remove from the NDK in favour of that from the libandroid-shmem. + # Remove as it doesn't work for non-root. + # Remove as we currently provide it from libandroid-glob. + # Remove as it's provided by libiconv. + # Remove as it's only for future (later than android-27). + # Remove and as we build our own zlib. + # Remove unicode headers provided by libicu. + # Remove KRH/khrplatform.h provided by mesa. + rm usr/include/{sys/{capability,shm,sem},{glob,iconv,spawn,zlib,zconf},KHR/khrplatform}.h + rm usr/include/unicode/{char16ptr,platform,ptypes,putil,stringoptions,ubidi,ubrk,uchar,uconfig,ucpmap,udisplaycontext,uenum,uldnames,ulocdata,uloc,umachine,unorm2,urename,uscript,ustring,utext,utf16,utf8,utf,utf_old,utypes,uvernum,uversion}.h + + sed -i "s/define __ANDROID_API__ __ANDROID_API_FUTURE__/define __ANDROID_API__ $TERMUX_PKG_API_LEVEL/" \ + usr/include/android/api-level.h + + $TERMUX_ELF_CLEANER usr/lib/*/*/*.so + for dir in usr/lib/*; do + # This seem to be needed when building rust + # packages + echo 'INPUT(-lunwind)' > $dir/libgcc.a + done + + grep -lrw $_TERMUX_TOOLCHAIN_TMPDIR/sysroot/usr/include/c++/v1 -e '' | xargs -n 1 sed -i 's//\"version\"/g' + mv $_TERMUX_TOOLCHAIN_TMPDIR $TERMUX_STANDALONE_TOOLCHAIN +} diff --git a/scripts/build/termux_step_setup_variables.sh b/scripts/build/termux_step_setup_variables.sh new file mode 100644 index 000000000..a1c1a824b --- /dev/null +++ b/scripts/build/termux_step_setup_variables.sh @@ -0,0 +1,146 @@ +termux_step_setup_variables() { + : "${TERMUX_ARCH:="aarch64"}" # arm, aarch64, i686 or x86_64. + : "${TERMUX_OUTPUT_DIR:="${TERMUX_SCRIPTDIR}/output"}" + : "${TERMUX_DEBUG_BUILD:="false"}" + : "${TERMUX_FORCE_BUILD:="false"}" + : "${TERMUX_INSTALL_DEPS:="false"}" + : "${TERMUX_MAKE_PROCESSES:="$(nproc)"}" + : "${TERMUX_NO_CLEAN:="false"}" + : "${TERMUX_PKG_API_LEVEL:="24"}" + : "${TERMUX_CONTINUE_BUILD:="false"}" + : "${TERMUX_QUIET_BUILD:="false"}" + : "${TERMUX_SKIP_DEPCHECK:="false"}" + : "${TERMUX_TOPDIR:="$HOME/.termux-build"}" + : "${TERMUX_PACMAN_PACKAGE_COMPRESSION:="xz"}" + + if [ -z "${TERMUX_PACKAGE_FORMAT-}" ]; then + if [ "$TERMUX_ON_DEVICE_BUILD" = "true" ] && [ -n "${TERMUX_APP_PACKAGE_MANAGER-}" ]; then + TERMUX_PACKAGE_FORMAT="$([ "${TERMUX_APP_PACKAGE_MANAGER-}" = "apt" ] && echo "debian" || echo "${TERMUX_APP_PACKAGE_MANAGER-}")" + else + TERMUX_PACKAGE_FORMAT="debian" + fi + fi + + case "${TERMUX_PACKAGE_FORMAT-}" in + debian) TERMUX_PACKAGE_MANAGER="apt";; + pacman) TERMUX_PACKAGE_MANAGER="pacman";; + *) termux_error_exit "Unsupported package format \"${TERMUX_PACKAGE_FORMAT-}\". Only 'debian' and 'pacman' formats are supported";; + esac + + if [ "$TERMUX_ON_DEVICE_BUILD" = "true" ]; then + # For on-device builds cross-compiling is not supported so we can + # store information about built packages under $TERMUX_TOPDIR. + TERMUX_BUILT_PACKAGES_DIRECTORY="$TERMUX_TOPDIR/.built-packages" + TERMUX_NO_CLEAN="true" + + # On-device builds without termux-exec are unsupported. + if ! grep -q "${TERMUX_PREFIX}/lib/libtermux-exec.so" <<< "${LD_PRELOAD-x}"; then + termux_error_exit "On-device builds without termux-exec are not supported." + fi + else + TERMUX_BUILT_PACKAGES_DIRECTORY="/data/data/.built-packages" + fi + + # TERMUX_PKG_MAINTAINER should be explicitly set in build.sh of the package. + : "${TERMUX_PKG_MAINTAINER:="default"}" + + TERMUX_REPO_URL=( + https://packages-cf.termux.dev/apt/termux-main + https://packages-cf.termux.dev/apt/termux-root + https://packages-cf.termux.dev/apt/termux-x11 + ) + + TERMUX_REPO_DISTRIBUTION=( + stable + root + x11 + ) + + TERMUX_REPO_COMPONENT=( + main + stable + main + ) + + if [ "x86_64" = "$TERMUX_ARCH" ] || [ "aarch64" = "$TERMUX_ARCH" ]; then + TERMUX_ARCH_BITS=64 + else + TERMUX_ARCH_BITS=32 + fi + + TERMUX_HOST_PLATFORM="${TERMUX_ARCH}-linux-android" + if [ "$TERMUX_ARCH" = "arm" ]; then TERMUX_HOST_PLATFORM="${TERMUX_HOST_PLATFORM}eabi"; fi + + if [ "$TERMUX_ON_DEVICE_BUILD" = "false" ] && [ ! -d "$NDK" ]; then + termux_error_exit 'NDK not pointing at a directory!' + fi + + if [ "$TERMUX_ON_DEVICE_BUILD" = "false" ] && ! grep -s -q "Pkg.Revision = $TERMUX_NDK_VERSION_NUM" "$NDK/source.properties"; then + termux_error_exit "Wrong NDK version - we need $TERMUX_NDK_VERSION" + fi + + # The build tuple that may be given to --build configure flag: + TERMUX_BUILD_TUPLE=$(sh "$TERMUX_SCRIPTDIR/scripts/config.guess") + + # We do not put all of build-tools/$TERMUX_ANDROID_BUILD_TOOLS_VERSION/ into PATH + # to avoid stuff like arm-linux-androideabi-ld there to conflict with ones from + # the standalone toolchain. + TERMUX_D8=$ANDROID_HOME/build-tools/$TERMUX_ANDROID_BUILD_TOOLS_VERSION/d8 + + TERMUX_COMMON_CACHEDIR="$TERMUX_TOPDIR/_cache" + TERMUX_ELF_CLEANER=$TERMUX_COMMON_CACHEDIR/termux-elf-cleaner + + export prefix=${TERMUX_PREFIX} + export PREFIX=${TERMUX_PREFIX} + + if [ "${TERMUX_PACKAGES_OFFLINE-false}" = "true" ]; then + # In "offline" mode store/pick cache from directory with + # build.sh script. + TERMUX_PKG_CACHEDIR=$TERMUX_PKG_BUILDER_DIR/cache + else + TERMUX_PKG_CACHEDIR=$TERMUX_TOPDIR/$TERMUX_PKG_NAME/cache + fi + TERMUX_CMAKE_BUILD=Ninja # Which cmake generator to use + TERMUX_PKG_BREAKS="" # https://www.debian.org/doc/debian-policy/ch-relationships.html#s-binarydeps + TERMUX_PKG_BUILDDIR=$TERMUX_TOPDIR/$TERMUX_PKG_NAME/build + TERMUX_PKG_BUILD_DEPENDS="" + TERMUX_PKG_BUILD_IN_SRC=false + TERMUX_PKG_CONFFILES="" + TERMUX_PKG_CONFLICTS="" # https://www.debian.org/doc/debian-policy/ch-relationships.html#s-conflicts + TERMUX_PKG_DEPENDS="" + TERMUX_PKG_DESCRIPTION="FIXME:Add description" + TERMUX_PKG_ESSENTIAL=false + TERMUX_PKG_EXTRA_CONFIGURE_ARGS="" + TERMUX_PKG_EXTRA_HOSTBUILD_CONFIGURE_ARGS="" + TERMUX_PKG_EXTRA_MAKE_ARGS="" + TERMUX_PKG_FORCE_CMAKE=false # if the package has autotools as well as cmake, then set this to prefer cmake + TERMUX_PKG_GIT_BRANCH="" # branch defaults to 'v$TERMUX_PKG_VERSION' unless this variable is defined + TERMUX_PKG_HAS_DEBUG=true # set to false if debug build doesn't exist or doesn't work, for example for python based packages + TERMUX_PKG_HOMEPAGE="" + TERMUX_PKG_HOSTBUILD=false # Set if a host build should be done in TERMUX_PKG_HOSTBUILD_DIR: + TERMUX_PKG_HOSTBUILD_DIR=$TERMUX_TOPDIR/$TERMUX_PKG_NAME/host-build + TERMUX_PKG_LICENSE_FILE="" # Relative path from $TERMUX_PKG_SRCDIR to LICENSE file. It is installed to $TERMUX_PREFIX/share/$TERMUX_PKG_NAME. + TERMUX_PKG_MASSAGEDIR=$TERMUX_TOPDIR/$TERMUX_PKG_NAME/massage + TERMUX_PKG_METAPACKAGE=false + TERMUX_PKG_NO_ELF_CLEANER=false # set this to true to disable running of termux-elf-cleaner on built binaries + TERMUX_PKG_NO_STATICSPLIT=false + TERMUX_PKG_STATICSPLIT_EXTRA_PATTERNS="" + TERMUX_PKG_PACKAGEDIR=$TERMUX_TOPDIR/$TERMUX_PKG_NAME/package + TERMUX_PKG_PLATFORM_INDEPENDENT=false + TERMUX_PKG_PRE_DEPENDS="" + TERMUX_PKG_PROVIDES="" #https://www.debian.org/doc/debian-policy/#virtual-packages-provides + TERMUX_PKG_RECOMMENDS="" # https://www.debian.org/doc/debian-policy/ch-relationships.html#s-binarydeps + TERMUX_PKG_REPLACES="" + TERMUX_PKG_REVISION="0" # http://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Version + TERMUX_PKG_RM_AFTER_INSTALL="" + TERMUX_PKG_SHA256="" + TERMUX_PKG_SRCDIR=$TERMUX_TOPDIR/$TERMUX_PKG_NAME/src + TERMUX_PKG_SUGGESTS="" + TERMUX_PKG_TMPDIR=$TERMUX_TOPDIR/$TERMUX_PKG_NAME/tmp + TERMUX_PKG_SERVICE_SCRIPT=() # Fill with entries like: ("daemon name" 'script to execute'). Script is echoed with -e so can contain \n for multiple lines + 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. + + unset CFLAGS CPPFLAGS LDFLAGS CXXFLAGS +} diff --git a/scripts/build/termux_step_start_build.sh b/scripts/build/termux_step_start_build.sh new file mode 100644 index 000000000..f279bfd39 --- /dev/null +++ b/scripts/build/termux_step_start_build.sh @@ -0,0 +1,98 @@ +termux_step_start_build() { + TERMUX_STANDALONE_TOOLCHAIN="$TERMUX_COMMON_CACHEDIR/android-r${TERMUX_NDK_VERSION}-api-${TERMUX_PKG_API_LEVEL}" + # Bump the below version if a change is made in toolchain setup to ensure + # that everyone gets an updated toolchain: + TERMUX_STANDALONE_TOOLCHAIN+="-v0" + + # shellcheck source=/dev/null + source "$TERMUX_PKG_BUILDER_SCRIPT" + # Path to hostbuild marker, for use if package has hostbuild step + TERMUX_HOSTBUILD_MARKER="$TERMUX_PKG_HOSTBUILD_DIR/TERMUX_BUILT_FOR_$TERMUX_PKG_VERSION" + + if [ "$TERMUX_PKG_METAPACKAGE" = "true" ]; then + # Metapackage has no sources and therefore platform-independent. + TERMUX_PKG_SKIP_SRC_EXTRACT=true + TERMUX_PKG_PLATFORM_INDEPENDENT=true + fi + + if [ -n "${TERMUX_PKG_BLACKLISTED_ARCHES:=""}" ] && [ "$TERMUX_PKG_BLACKLISTED_ARCHES" != "${TERMUX_PKG_BLACKLISTED_ARCHES/$TERMUX_ARCH/}" ]; then + echo "Skipping building $TERMUX_PKG_NAME for arch $TERMUX_ARCH" + exit 0 + fi + + TERMUX_PKG_FULLVERSION=$TERMUX_PKG_VERSION + if [ "$TERMUX_PKG_REVISION" != "0" ] || [ "$TERMUX_PKG_FULLVERSION" != "${TERMUX_PKG_FULLVERSION/-/}" ]; then + # "0" is the default revision, so only include it if the upstream versions contains "-" itself + TERMUX_PKG_FULLVERSION+="-$TERMUX_PKG_REVISION" + fi + # full format version for pacman + local TERMUX_PKG_VERSION_EDITED=${TERMUX_PKG_VERSION//-/.} + local INCORRECT_SYMBOLS=$(echo $TERMUX_PKG_VERSION_EDITED | grep -o '[0-9][a-z]') + if [ -n "$INCORRECT_SYMBOLS" ]; then + local TERMUX_PKG_VERSION_EDITED=${TERMUX_PKG_VERSION_EDITED//${INCORRECT_SYMBOLS:0:1}${INCORRECT_SYMBOLS:1:1}/${INCORRECT_SYMBOLS:0:1}.${INCORRECT_SYMBOLS:1:1}} + fi + TERMUX_PKG_FULLVERSION_FOR_PACMAN="${TERMUX_PKG_VERSION_EDITED}" + if [ -n "$TERMUX_PKG_REVISION" ]; then + TERMUX_PKG_FULLVERSION_FOR_PACMAN+="-${TERMUX_PKG_REVISION}" + else + TERMUX_PKG_FULLVERSION_FOR_PACMAN+="-0" + fi + + if [ "$TERMUX_DEBUG_BUILD" = "true" ]; then + if [ "$TERMUX_PKG_HAS_DEBUG" = "true" ]; then + DEBUG="-dbg" + else + echo "Skipping building debug build for $TERMUX_PKG_NAME" + exit 0 + fi + else + DEBUG="" + fi + + if [ "$TERMUX_DEBUG_BUILD" = "false" ] && [ "$TERMUX_FORCE_BUILD" = "false" ]; then + if [ -e "$TERMUX_BUILT_PACKAGES_DIRECTORY/$TERMUX_PKG_NAME" ] && + [ "$(cat "$TERMUX_BUILT_PACKAGES_DIRECTORY/$TERMUX_PKG_NAME")" = "$TERMUX_PKG_FULLVERSION" ]; then + echo "$TERMUX_PKG_NAME@$TERMUX_PKG_FULLVERSION built - skipping (rm $TERMUX_BUILT_PACKAGES_DIRECTORY/$TERMUX_PKG_NAME to force rebuild)" + exit 0 + elif [ "$TERMUX_ON_DEVICE_BUILD" = "true" ] && + ([[ "$TERMUX_APP_PACKAGE_MANAGER" = "apt" && "$(dpkg-query -W -f '${db:Status-Status} ${Version}\n' "$TERMUX_PKG_NAME" 2>/dev/null)" = "installed $TERMUX_PKG_FULLVERSION" ]] || + [[ "$TERMUX_APP_PACKAGE_MANAGER" = "pacman" && "$(pacman -Q $TERMUX_PKG_NAME 2>/dev/null)" = "$TERMUX_PKG_NAME $TERMUX_PKG_FULLVERSION_FOR_PACMAN" ]]); then + echo "$TERMUX_PKG_NAME@$TERMUX_PKG_FULLVERSION installed - skipping" + exit 0 + fi + fi + + echo "termux - building $TERMUX_PKG_NAME for arch $TERMUX_ARCH..." + test -t 1 && printf "\033]0;%s...\007" "$TERMUX_PKG_NAME" + + # Avoid exporting PKG_CONFIG_LIBDIR until after termux_step_host_build. + export TERMUX_PKG_CONFIG_LIBDIR=$TERMUX_PREFIX/lib/pkgconfig + + if [ "$TERMUX_PKG_BUILD_IN_SRC" = "true" ]; then + echo "Building in src due to TERMUX_PKG_BUILD_IN_SRC being set to true" > "$TERMUX_PKG_BUILDDIR/BUILDING_IN_SRC.txt" + TERMUX_PKG_BUILDDIR=$TERMUX_PKG_SRCDIR + fi + + if [ "$TERMUX_CONTINUE_BUILD" == "true" ]; then + # If the package has a hostbuild step, verify that it has been built + if [ "$TERMUX_PKG_HOSTBUILD" == "true" ] && [ ! -f "$TERMUX_HOSTBUILD_MARKER" ]; then + termux_error_exit "Cannot continue this build, hostbuilt tools are missing" + fi + + # The rest in this function can be skipped when doing + # a continued build + return + fi + + local TERMUX_ELF_CLEANER_SRC=$TERMUX_COMMON_CACHEDIR/termux-elf-cleaner.cpp + local TERMUX_ELF_CLEANER_VERSION + TERMUX_ELF_CLEANER_VERSION=$(bash -c ". $TERMUX_SCRIPTDIR/packages/termux-elf-cleaner/build.sh; echo \$TERMUX_PKG_VERSION") + termux_download \ + "https://raw.githubusercontent.com/termux/termux-elf-cleaner/v$TERMUX_ELF_CLEANER_VERSION/termux-elf-cleaner.cpp" \ + "$TERMUX_ELF_CLEANER_SRC" \ + 022197c19129c4e57a37515bd4adcc19e05f9aa7f9ba4fbcab85a20210c39632 + if [ "$TERMUX_ELF_CLEANER_SRC" -nt "$TERMUX_ELF_CLEANER" ]; then + g++ -std=c++11 -Wall -Wextra -pedantic -Os -D__ANDROID_API__=$TERMUX_PKG_API_LEVEL \ + "$TERMUX_ELF_CLEANER_SRC" -o "$TERMUX_ELF_CLEANER" + fi +} diff --git a/scripts/buildorder.py b/scripts/buildorder.py new file mode 100755 index 000000000..0795373a1 --- /dev/null +++ b/scripts/buildorder.py @@ -0,0 +1,290 @@ +#!/usr/bin/env python3 +"Script to generate a build order respecting package dependencies." + +import json, os, re, sys + +from itertools import filterfalse + +def unique_everseen(iterable, key=None): + """List unique elements, preserving order. Remember all elements ever seen. + See https://docs.python.org/3/library/itertools.html#itertools-recipes + Examples: + unique_everseen('AAAABBBCCDAABBB') --> A B C D + unique_everseen('ABBCcAD', str.lower) --> A B C D""" + seen = set() + seen_add = seen.add + if key is None: + for element in filterfalse(seen.__contains__, iterable): + seen_add(element) + yield element + else: + for element in iterable: + k = key(element) + if k not in seen: + seen_add(k) + yield element + +def die(msg): + "Exit the process with an error message." + sys.exit('ERROR: ' + msg) + +def parse_build_file_dependencies(path): + "Extract the dependencies of a build.sh or *.subpackage.sh file." + dependencies = [] + + with open(path, encoding="utf-8") as build_script: + for line in build_script: + if line.startswith( ('TERMUX_PKG_DEPENDS', 'TERMUX_PKG_BUILD_DEPENDS', 'TERMUX_SUBPKG_DEPENDS', 'TERMUX_PKG_DEVPACKAGE_DEPENDS') ): + dependencies_string = line.split('DEPENDS=')[1] + for char in "\"'\n": + dependencies_string = dependencies_string.replace(char, '') + + # Split also on '|' to dependencies with '|', as in 'nodejs | nodejs-current': + for dependency_value in re.split(',|\\|', dependencies_string): + # Replace parenthesis to ignore version qualifiers as in "gcc (>= 5.0)": + dependency_value = re.sub(r'\(.*?\)', '', dependency_value).strip() + + dependencies.append(dependency_value) + + return set(dependencies) + +class TermuxPackage(object): + "A main package definition represented by a directory with a build.sh file." + def __init__(self, dir_path, fast_build_mode): + self.dir = dir_path + self.name = os.path.basename(self.dir) + + # search package build.sh + build_sh_path = os.path.join(self.dir, 'build.sh') + if not os.path.isfile(build_sh_path): + raise Exception("build.sh not found for package '" + self.name + "'") + + self.deps = parse_build_file_dependencies(build_sh_path) + + if os.getenv('TERMUX_ON_DEVICE_BUILD') == "true": + always_deps = ['libc++'] + for dependency_name in always_deps: + if dependency_name not in self.deps and self.name not in always_deps: + self.deps.add(dependency_name) + + # search subpackages + self.subpkgs = [] + + for filename in os.listdir(self.dir): + if not filename.endswith('.subpackage.sh'): + continue + subpkg = TermuxSubPackage(self.dir + '/' + filename, self) + + self.subpkgs.append(subpkg) + self.deps.add(subpkg.name) + self.deps |= subpkg.deps + + subpkg = TermuxSubPackage(self.dir + '/' + self.name + '-static' + '.subpackage.sh', self, virtual=True) + self.subpkgs.append(subpkg) + + # Do not depend on itself + self.deps.discard(self.name) + # Do not depend on any sub package + if not fast_build_mode: + self.deps.difference_update([subpkg.name for subpkg in self.subpkgs]) + + self.needed_by = set() # Populated outside constructor, reverse of deps. + + def __repr__(self): + return "<{} '{}'>".format(self.__class__.__name__, self.name) + + def recursive_dependencies(self, pkgs_map): + "All the dependencies of the package, both direct and indirect." + result = [] + for dependency_name in sorted(self.deps): + dependency_package = pkgs_map[dependency_name] + result += dependency_package.recursive_dependencies(pkgs_map) + result += [dependency_package] + return unique_everseen(result) + +class TermuxSubPackage: + "A sub-package represented by a ${PACKAGE_NAME}.subpackage.sh file." + def __init__(self, subpackage_file_path, parent, virtual=False): + if parent is None: + raise Exception("SubPackages should have a parent") + + self.name = os.path.basename(subpackage_file_path).split('.subpackage.sh')[0] + self.parent = parent + self.deps = set([parent.name]) + if not virtual: + self.deps |= parse_build_file_dependencies(subpackage_file_path) + self.dir = parent.dir + + self.needed_by = set() # Populated outside constructor, reverse of deps. + + def __repr__(self): + return "<{} '{}' parent='{}'>".format(self.__class__.__name__, self.name, self.parent) + + def recursive_dependencies(self, pkgs_map): + """All the dependencies of the subpackage, both direct and indirect. + Only relevant when building in fast-build mode""" + result = [] + for dependency_name in sorted(self.deps): + if dependency_name == self.parent.name: + self.parent.deps.discard(self.name) + dependency_package = pkgs_map[dependency_name] + if dependency_package not in self.parent.subpkgs: + result += dependency_package.recursive_dependencies(pkgs_map) + result += [dependency_package] + return unique_everseen(result) + +def read_packages_from_directories(directories, fast_build_mode, full_buildmode): + """Construct a map from package name to TermuxPackage. + Subpackages are mapped to the parent package if fast_build_mode is false.""" + pkgs_map = {} + all_packages = [] + + if full_buildmode: + # Ignore directories and get all folders from repo.json file + with open ('repo.json') as f: + data = json.load(f) + directories = [d for d in data.keys()] + + for package_dir in directories: + for pkgdir_name in sorted(os.listdir(package_dir)): + dir_path = package_dir + '/' + pkgdir_name + if os.path.isfile(dir_path + '/build.sh'): + new_package = TermuxPackage(package_dir + '/' + pkgdir_name, fast_build_mode) + + if new_package.name in pkgs_map: + die('Duplicated package: ' + new_package.name) + else: + pkgs_map[new_package.name] = new_package + all_packages.append(new_package) + + for subpkg in new_package.subpkgs: + if subpkg.name in pkgs_map: + die('Duplicated package: ' + subpkg.name) + elif fast_build_mode: + pkgs_map[subpkg.name] = subpkg + else: + pkgs_map[subpkg.name] = new_package + all_packages.append(subpkg) + + for pkg in all_packages: + for dependency_name in pkg.deps: + if dependency_name not in pkgs_map: + die('Package %s depends on non-existing package "%s"' % (pkg.name, dependency_name)) + dep_pkg = pkgs_map[dependency_name] + if fast_build_mode or not isinstance(pkg, TermuxSubPackage): + dep_pkg.needed_by.add(pkg) + return pkgs_map + +def generate_full_buildorder(pkgs_map): + "Generate a build order for building all packages." + build_order = [] + + # List of all TermuxPackages without dependencies + leaf_pkgs = [pkg for name, pkg in pkgs_map.items() if not pkg.deps] + + if not leaf_pkgs: + die('No package without dependencies - where to start?') + + # Sort alphabetically: + pkg_queue = sorted(leaf_pkgs, key=lambda p: p.name) + + # Topological sorting + visited = set() + + # Tracks non-visited deps for each package + remaining_deps = {} + for name, pkg in pkgs_map.items(): + remaining_deps[name] = set(pkg.deps) + for subpkg in pkg.subpkgs: + remaining_deps[subpkg.name] = set(subpkg.deps) + + while pkg_queue: + pkg = pkg_queue.pop(0) + if pkg.name in visited: + continue + + # print("Processing {}:".format(pkg.name), pkg.needed_by) + visited.add(pkg.name) + build_order.append(pkg) + + for other_pkg in sorted(pkg.needed_by, key=lambda p: p.name): + # Remove this pkg from deps + remaining_deps[other_pkg.name].discard(pkg.name) + # ... and all its subpackages + remaining_deps[other_pkg.name].difference_update( + [subpkg.name for subpkg in pkg.subpkgs] + ) + + if not remaining_deps[other_pkg.name]: # all deps were already appended? + pkg_queue.append(other_pkg) # should be processed + + if set(pkgs_map.values()) != set(build_order): + print("ERROR: Cycle exists. Remaining: ") + for name, pkg in pkgs_map.items(): + if pkg not in build_order: + print(name, remaining_deps[name]) + + sys.exit(1) + + return build_order + +def generate_target_buildorder(target_path, pkgs_map, fast_build_mode): + "Generate a build order for building the dependencies of the specified package." + if target_path.endswith('/'): + target_path = target_path[:-1] + + package_name = os.path.basename(target_path) + package = pkgs_map[package_name] + # Do not depend on any sub package + if fast_build_mode: + package.deps.difference_update([subpkg.name for subpkg in package.subpkgs]) + return package.recursive_dependencies(pkgs_map) + +def main(): + "Generate the build order either for all packages or a specific one." + import argparse + + parser = argparse.ArgumentParser(description='Generate order in which to build dependencies for a package. Generates') + parser.add_argument('-i', default=False, action='store_true', + help='Generate dependency list for fast-build mode. This includes subpackages in output since these can be downloaded.') + parser.add_argument('package', nargs='?', + help='Package to generate dependency list for.') + parser.add_argument('package_dirs', nargs='*', + help='Directories with packages. Can for example point to "../community-packages/packages". Note that the packages suffix is no longer added automatically if not present.') + args = parser.parse_args() + fast_build_mode = args.i + package = args.package + packages_directories = args.package_dirs + + if not package: + full_buildorder = True + else: + full_buildorder = False + + if fast_build_mode and full_buildorder: + die('-i mode does not work when building all packages') + + if not full_buildorder: + for path in packages_directories: + if not os.path.isdir(path): + die('Not a directory: ' + path) + + if package: + if package[-1] == "/": + package = package[:-1] + if not os.path.isdir(package): + die('Not a directory: ' + package) + if not os.path.relpath(os.path.dirname(package), '.') in packages_directories: + packages_directories.insert(0, os.path.dirname(package)) + pkgs_map = read_packages_from_directories(packages_directories, fast_build_mode, full_buildorder) + + if full_buildorder: + build_order = generate_full_buildorder(pkgs_map) + else: + build_order = generate_target_buildorder(package, pkgs_map, fast_build_mode) + + for pkg in build_order: + print("%-30s %s" % (pkg.name, pkg.dir)) + +if __name__ == '__main__': + main() diff --git a/scripts/check-built-packages.py b/scripts/check-built-packages.py new file mode 100755 index 000000000..61bc06654 --- /dev/null +++ b/scripts/check-built-packages.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python3 + +import urllib.request +from subprocess import Popen, PIPE + +version_map = {} +any_error = False + +pipe = Popen('./scripts/list-versions.sh', stdout=PIPE) +for line in pipe.stdout: + (name, version) = line.decode().strip().split('=') + version_map[name] = version + +def check_manifest(arch, manifest): + current_package = {} + for line in manifest: + if line.isspace(): + package_name = current_package['Package'] + package_version = current_package['Version'] + if not package_name in version_map: + # Skip sub-package + continue + latest_version = version_map[package_name] + if package_version != latest_version: + print(f'{package_name}@{arch}: Expected {latest_version}, but was {package_version}') + current_package.clear() + elif not line.decode().startswith(' '): + parts = line.decode().split(':', 1) + current_package[parts[0].strip()] = parts[1].strip() + +for arch in ['all', 'aarch64', 'arm', 'i686', 'x86_64']: + manifest_url = f'https://termux.dev/packages/dists/stable/main/binary-{arch}/Packages' + with urllib.request.urlopen(manifest_url) as manifest: + check_manifest(arch, manifest) diff --git a/scripts/check-versions.sh b/scripts/check-versions.sh new file mode 100755 index 000000000..359ee2767 --- /dev/null +++ b/scripts/check-versions.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +# check-versions.sh - script to open packages in a browser for checking their versions + +OPEN=xdg-open +if [ $(uname) = Darwin ]; then OPEN=open; fi + +check_package() { # path + local path=$1 + local pkg=$(basename $path) + . $path/build.sh + echo -n "$pkg - $TERMUX_PKG_VERSION" + read + $OPEN $TERMUX_PKG_HOMEPAGE +} + +# Run each package in separate process since we include their environment variables: +for path in packages/*; do +( + check_package $path +) +done diff --git a/scripts/config.guess b/scripts/config.guess new file mode 100755 index 000000000..bbd48b60e --- /dev/null +++ b/scripts/config.guess @@ -0,0 +1,1462 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright 1992-2017 Free Software Foundation, Inc. + +timestamp='2017-01-01' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). +# +# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. +# +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess +# +# Please send patches to . + + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright 1992-2017 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +case "${UNAME_SYSTEM}" in +Linux|GNU|GNU/*) + # If the system lacks a compiler, then just pick glibc. + # We could probably try harder. + LIBC=gnu + + eval $set_cc_for_build + cat <<-EOF > $dummy.c + #include + #if defined(__UCLIBC__) + LIBC=uclibc + #elif defined(__dietlibc__) + LIBC=dietlibc + #else + LIBC=gnu + #endif + EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` + ;; +esac + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ + /sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || \ + echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + earmv*) + arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'` + machine=${arch}${endian}-unknown + ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently (or will in the future) and ABI. + case "${UNAME_MACHINE_ARCH}" in + earm*) + os=netbsdelf + ;; + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # Determine ABI tags. + case "${UNAME_MACHINE_ARCH}" in + earm*) + expr='s/^earmv[0-9]/-eabi/;s/eb$//' + abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"` + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}${abi}" + exit ;; + *:Bitrig:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:LibertyBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:Sortix:*:*) + echo ${UNAME_MACHINE}-unknown-sortix + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE=alpha ;; + "EV4.5 (21064)") + UNAME_MACHINE=alpha ;; + "LCA4 (21066/21068)") + UNAME_MACHINE=alpha ;; + "EV5 (21164)") + UNAME_MACHINE=alphaev5 ;; + "EV5.6 (21164A)") + UNAME_MACHINE=alphaev56 ;; + "EV5.6 (21164PC)") + UNAME_MACHINE=alphapca56 ;; + "EV5.7 (21164PC)") + UNAME_MACHINE=alphapca57 ;; + "EV6 (21264)") + UNAME_MACHINE=alphaev6 ;; + "EV6.7 (21264A)") + UNAME_MACHINE=alphaev67 ;; + "EV6.8CB (21264C)") + UNAME_MACHINE=alphaev68 ;; + "EV6.8AL (21264B)") + UNAME_MACHINE=alphaev68 ;; + "EV6.8CX (21264D)") + UNAME_MACHINE=alphaev68 ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE=alphaev69 ;; + "EV7 (21364)") + UNAME_MACHINE=alphaev7 ;; + "EV7.9 (21364A)") + UNAME_MACHINE=alphaev79 ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + exitcode=$? + trap '' 0 + exit $exitcode ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm*:riscos:*:*|arm*:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH=i386 + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH=x86_64 + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[4567]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/lslpp ] ; then + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 + 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH=hppa2.0n ;; + 64) HP_ARCH=hppa2.0w ;; + '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS="" $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = hppa2.0w ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH=hppa2.0w + else + HP_ARCH=hppa64 + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + UNAME_PROCESSOR=`/usr/bin/uname -p` + case ${UNAME_PROCESSOR} in + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW64*:*) + echo ${UNAME_MACHINE}-pc-mingw64 + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + *:MSYS*:*) + echo ${UNAME_MACHINE}-pc-msys + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + aarch64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC=gnulibc1 ; fi + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arc:Linux:*:* | arceb:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi + else + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf + fi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + cris:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + crisv32:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + e2k:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + frv:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + hexagon:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:Linux:*:*) + echo ${UNAME_MACHINE}-pc-linux-${LIBC} + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + k1om:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } + ;; + mips64el:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + openrisc*:Linux:*:*) + echo or1k-unknown-linux-${LIBC} + exit ;; + or32:Linux:*:* | or1k*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-${LIBC} + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-${LIBC} + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; + PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; + *) echo hppa-unknown-linux-${LIBC} ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-${LIBC} + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-${LIBC} + exit ;; + ppc64le:Linux:*:*) + echo powerpc64le-unknown-linux-${LIBC} + exit ;; + ppcle:Linux:*:*) + echo powerpcle-unknown-linux-${LIBC} + exit ;; + riscv32:Linux:*:* | riscv64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux-${LIBC} + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + tile*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-${LIBC} + exit ;; + x86_64:Linux:*:*) + echo ${UNAME_MACHINE}-pc-linux-${LIBC} + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configure will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + x86_64:Haiku:*:*) + echo x86_64-unknown-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + SX-ACE:SUPER-UX:*:*) + echo sxace-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + eval $set_cc_for_build + if test "$UNAME_PROCESSOR" = unknown ; then + UNAME_PROCESSOR=powerpc + fi + if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + case $UNAME_PROCESSOR in + i386) UNAME_PROCESSOR=x86_64 ;; + powerpc) UNAME_PROCESSOR=powerpc64 ;; + esac + fi + fi + elif test "$UNAME_PROCESSOR" = i386 ; then + # Avoid executing cc on OS X 10.9, as it ships with a stub + # that puts up a graphical alert prompting to install + # developer tools. Any system running Mac OS X 10.7 or + # later (Darwin 11 and later) is required to have a 64-bit + # processor. This is not true of the ARM version of Darwin + # that Apple uses in portable devices. + UNAME_PROCESSOR=x86_64 + fi + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = x86; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NEO-?:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk${UNAME_RELEASE} + exit ;; + NSE-*:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = 386; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'` + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; + x86_64:VMkernel:*:*) + echo ${UNAME_MACHINE}-unknown-esx + exit ;; + amd64:Isilon\ OneFS:*:*) + echo x86_64-unknown-onefs + exit ;; +esac + +cat >&2 </dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/scripts/config.sub b/scripts/config.sub new file mode 100755 index 000000000..7e792b4ae --- /dev/null +++ b/scripts/config.sub @@ -0,0 +1,1828 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright 1992-2017 Free Software Foundation, Inc. + +timestamp='2017-01-01' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). + + +# Please send patches to . +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright 1992-2017 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ + linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ + kopensolaris*-gnu* | cloudabi*-eabi* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + android-linux) + os=-linux-android + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray | -microblaze*) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*178) + os=-lynxos178 + ;; + -lynx*5) + os=-lynxos5 + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | aarch64 | aarch64_be \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arceb \ + | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ + | avr | avr32 \ + | ba \ + | be32 | be64 \ + | bfin \ + | c4x | c8051 | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | e2k | epiphany \ + | fido | fr30 | frv | ft32 \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | k1om \ + | le32 | le64 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa32r6 | mipsisa32r6el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64r6 | mipsisa64r6el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipsr5900 | mipsr5900el \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nds32 | nds32le | nds32be \ + | nios | nios2 | nios2eb | nios2el \ + | ns16k | ns32k \ + | open8 | or1k | or1knd | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle \ + | pru \ + | pyramid \ + | riscv32 | riscv64 \ + | rl78 | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu \ + | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ + | visium \ + | we32k \ + | x86 | xc16x | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + c54x) + basic_machine=tic54x-unknown + ;; + c55x) + basic_machine=tic55x-unknown + ;; + c6x) + basic_machine=tic6x-unknown + ;; + leon|leon[3-9]) + basic_machine=sparc-$basic_machine + ;; + m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + strongarm | thumb | xscale) + basic_machine=arm-unknown + ;; + xgate) + basic_machine=$basic_machine-unknown + os=-none + ;; + xscaleeb) + basic_machine=armeb-unknown + ;; + + xscaleel) + basic_machine=armel-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | aarch64-* | aarch64_be-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | ba-* \ + | be32-* | be64-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* \ + | c8051-* | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | e2k-* | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | hexagon-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | k1om-* \ + | le32-* | le64-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ + | microblaze-* | microblazeel-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa32r6-* | mipsisa32r6el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64r6-* | mipsisa64r6el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipsr5900-* | mipsr5900el-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nds32-* | nds32le-* | nds32be-* \ + | nios-* | nios2-* | nios2eb-* | nios2el-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | open8-* \ + | or1k*-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | pru-* \ + | pyramid-* \ + | riscv32-* | riscv64-* \ + | rl78-* | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ + | tahoe-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tile*-* \ + | tron-* \ + | ubicom32-* \ + | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ + | vax-* \ + | visium-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + asmjs) + basic_machine=asmjs-unknown + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c54x-*) + basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c55x-*) + basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c6x-*) + basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16 | cr16-*) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + e500v[12]) + basic_machine=powerpc-unknown + os=$os"spe" + ;; + e500v[12]-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + os=$os"spe" + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + leon-*|leon[3-9]-*) + basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + microblaze*) + basic_machine=microblaze-xilinx + ;; + mingw64) + basic_machine=x86_64-pc + os=-mingw64 + ;; + mingw32) + basic_machine=i686-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + moxiebox) + basic_machine=moxie-unknown + os=-moxiebox + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + msys) + basic_machine=i686-pc + os=-msys + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + nacl) + basic_machine=le32-unknown + os=-nacl + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + neo-tandem) + basic_machine=neo-tandem + ;; + nse-tandem) + basic_machine=nse-tandem + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc | ppcbe) basic_machine=powerpc-unknown + ;; + ppc-* | ppcbe-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos | rdos64) + basic_machine=x86_64-pc + os=-rdos + ;; + rdos32) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + strongarm-* | thumb-*) + basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tile*) + basic_machine=$basic_machine-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + xscale-* | xscalee[bl]-*) + basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* | -plan9* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* | -cloudabi* | -sortix* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* | -glidix* \ + | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-musl* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ + | -onefs* | -tirtos* | -phoenix* | -fuchsia* | -redox*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -nacl*) + ;; + -ios) + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + c8051-*) + os=-elf + ;; + hexagon-*) + os=-elf + ;; + tic54x-*) + os=-coff + ;; + tic55x-*) + os=-coff + ;; + tic6x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + pru-*) + os=-elf + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/scripts/generate-bootstraps.sh b/scripts/generate-bootstraps.sh new file mode 100755 index 000000000..354fea6a7 --- /dev/null +++ b/scripts/generate-bootstraps.sh @@ -0,0 +1,484 @@ +#!/usr/bin/env bash +## +## Script for generating bootstrap archives. +## + +set -e + +. $(dirname "$(realpath "$0")")/properties.sh +BOOTSTRAP_TMPDIR=$(mktemp -d "${TMPDIR:-/tmp}/bootstrap-tmp.XXXXXXXX") +trap 'rm -rf $BOOTSTRAP_TMPDIR' EXIT + +# By default, bootstrap archives are compatible with Android >=7.0 +# and <10. +BOOTSTRAP_ANDROID10_COMPATIBLE=false + +# By default, bootstrap archives will be built for all architectures +# supported by Termux application. +# Override with option '--architectures'. +TERMUX_ARCHITECTURES=("aarch64" "arm" "i686" "x86_64") + +# The supported termux package managers. +TERMUX_PACKAGE_MANAGERS=("apt" "pacman") + +# The repository base urls mapping for package managers. +declare -A REPO_BASE_URLS=( + ["apt"]="https://packages-cf.termux.dev/apt/termux-main" + ["pacman"]="https://s3.amazonaws.com/termux-main.pacman" +) + +# The package manager that will be installed in bootstrap. +# The default is 'apt'. Can be changed by using the '--pm' option. +TERMUX_PACKAGE_MANAGER="apt" + +# The repository base url for package manager. +# Can be changed by using the '--repository' option. +REPO_BASE_URL="${REPO_BASE_URLS[${TERMUX_PACKAGE_MANAGER}]}" + +# A list of non-essential packages. By default it is empty, but can +# be filled with option '--add'. +declare -a ADDITIONAL_PACKAGES + +# Check for some important utilities that may not be available for +# some reason. +for cmd in ar awk curl grep gzip find sed tar xargs xz zip; do + if [ -z "$(command -v $cmd)" ]; then + echo "[!] Utility '$cmd' is not available in PATH." + exit 1 + fi +done + +# Download package lists from remote repository. +# Actually, there 2 lists can be downloaded: one architecture-independent and +# one for architecture specified as '$1' argument. That depends on repository. +# If repository has been created using "aptly", then architecture-independent +# list is not available. +read_package_list_deb() { + local architecture + for architecture in all "$1"; do + if [ ! -e "${BOOTSTRAP_TMPDIR}/packages.${architecture}" ]; then + echo "[*] Downloading package list for architecture '${architecture}'..." + if ! curl --fail --location \ + --output "${BOOTSTRAP_TMPDIR}/packages.${architecture}" \ + "${REPO_BASE_URL}/dists/stable/main/binary-${architecture}/Packages"; then + if [ "$architecture" = "all" ]; then + echo "[!] Skipping architecture-independent package list as not available..." + continue + fi + fi + echo >> "${BOOTSTRAP_TMPDIR}/packages.${architecture}" + fi + + echo "[*] Reading package list for '${architecture}'..." + while read -r -d $'\xFF' package; do + if [ -n "$package" ]; then + local package_name + package_name=$(echo "$package" | grep -i "^Package:" | awk '{ print $2 }') + + if [ -z "${PACKAGE_METADATA["$package_name"]}" ]; then + PACKAGE_METADATA["$package_name"]="$package" + else + local prev_package_ver cur_package_ver + cur_package_ver=$(echo "$package" | grep -i "^Version:" | awk '{ print $2 }') + prev_package_ver=$(echo "${PACKAGE_METADATA["$package_name"]}" | grep -i "^Version:" | awk '{ print $2 }') + + # If package has multiple versions, make sure that our metadata + # contains the latest one. + if [ "$(echo -e "${prev_package_ver}\n${cur_package_ver}" | sort -rV | head -n1)" = "${cur_package_ver}" ]; then + PACKAGE_METADATA["$package_name"]="$package" + fi + fi + fi + done < <(sed -e "s/^$/\xFF/g" "${BOOTSTRAP_TMPDIR}/packages.${architecture}") + done +} + +read_package_list_pac() { + if [ ! -e "${BOOTSTRAP_TMPDIR}/main_${1}.db" ]; then + echo "[*] Downloading package list for architecture '${1}'..." + curl --fail --location \ + --output "${BOOTSTRAP_TMPDIR}/main_${1}.db" \ + "${REPO_BASE_URL}/${1}/main.db" + fi + + echo "[*] Reading package list for '${1}'..." + mkdir -p "${BOOTSTRAP_TMPDIR}/packages" + tar -xf "${BOOTSTRAP_TMPDIR}/main_${1}.db" -C "${BOOTSTRAP_TMPDIR}/packages" + local packages_name=($(grep -h -A 1 "%NAME%" "${BOOTSTRAP_TMPDIR}"/packages/*/desc | sed 's/%NAME%//g; s/--//g')) + local packages_filename=($(grep -h -A 1 "%FILENAME%" "${BOOTSTRAP_TMPDIR}"/packages/*/desc | sed 's/%FILENAME%//g; s/--//g')) + for i in $(seq 0 $((${#packages_name[@]}-1))); do + PACKAGE_METADATA["${packages_name[$i]}"]="${1}/${packages_filename[$i]}" + done +} + +# Download specified package, its depenencies and then extract *.deb or *.pkg.tar.xz files to +# the bootstrap root. +pull_package() { + local package_name=$1 + local package_tmpdir="${BOOTSTRAP_PKGDIR}/${package_name}" + mkdir -p "$package_tmpdir" + + if [ ${TERMUX_PACKAGE_MANAGER} = "apt" ]; then + local package_url + package_url="$REPO_BASE_URL/$(echo "${PACKAGE_METADATA[${package_name}]}" | grep -i "^Filename:" | awk '{ print $2 }')" + if [ "${package_url}" = "$REPO_BASE_URL" ] || [ "${package_url}" = "${REPO_BASE_URL}/" ]; then + echo "[!] Failed to determine URL for package '$package_name'." + exit 1 + fi + + local package_dependencies + package_dependencies=$( + while read -r token; do + echo "$token" | cut -d'|' -f1 | sed -E 's@\(.*\)@@' + done < <(echo "${PACKAGE_METADATA[${package_name}]}" | grep -i "^Depends:" | sed -E 's@^[Dd]epends:@@' | tr ',' '\n') + ) + + # Recursively handle dependencies. + if [ -n "$package_dependencies" ]; then + local dep + for dep in $package_dependencies; do + if [ ! -e "${BOOTSTRAP_PKGDIR}/${dep}" ]; then + pull_package "$dep" + fi + done + unset dep + fi + + if [ ! -e "$package_tmpdir/package.deb" ]; then + echo "[*] Downloading '$package_name'..." + curl --fail --location --output "$package_tmpdir/package.deb" "$package_url" + + echo "[*] Extracting '$package_name'..." + (cd "$package_tmpdir" + ar x package.deb + + # data.tar may have extension different from .xz + if [ -f "./data.tar.xz" ]; then + data_archive="data.tar.xz" + elif [ -f "./data.tar.gz" ]; then + data_archive="data.tar.gz" + else + echo "No data.tar.* found in '$package_name'." + exit 1 + fi + + # Do same for control.tar. + if [ -f "./control.tar.xz" ]; then + control_archive="control.tar.xz" + elif [ -f "./control.tar.gz" ]; then + control_archive="control.tar.gz" + else + echo "No control.tar.* found in '$package_name'." + exit 1 + fi + + # Extract files. + tar xf "$data_archive" -C "$BOOTSTRAP_ROOTFS" + + if ! ${BOOTSTRAP_ANDROID10_COMPATIBLE}; then + # Register extracted files. + tar tf "$data_archive" | sed -E -e 's@^\./@/@' -e 's@^/$@/.@' -e 's@^([^./])@/\1@' > "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/var/lib/dpkg/info/${package_name}.list" + + # Generate checksums (md5). + tar xf "$data_archive" + find data -type f -print0 | xargs -0 -r md5sum | sed 's@^\.$@@g' > "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/var/lib/dpkg/info/${package_name}.md5sums" + + # Extract metadata. + tar xf "$control_archive" + { + cat control + echo "Status: install ok installed" + echo + } >> "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/var/lib/dpkg/status" + + # Additional data: conffiles & scripts + for file in conffiles postinst postrm preinst prerm; do + if [ -f "${PWD}/${file}" ]; then + cp "$file" "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/var/lib/dpkg/info/${package_name}.${file}" + fi + done + fi + ) + fi + else + local package_desc=$(grep -l $(echo ${PACKAGE_METADATA[${package_name}]} | awk -F "/" '{printf $2}') "${BOOTSTRAP_TMPDIR}"/packages/${package_name}*/desc | head -1) + local package_dependencies + local i=0 + package_dependencies=$( + while [[ -n $(grep -A ${i} %DEPENDS% ${package_desc} | tail -1) ]]; do + i=$((${i}+1)) + echo $(grep -A ${i} %DEPENDS% ${package_desc} | tail -1 | sed 's// /g; s/=/ /g' | awk '{printf $1}') + done + ) + + if [ -n "$package_dependencies" ]; then + local dep + for dep in $package_dependencies; do + if [ ! -e "${BOOTSTRAP_PKGDIR}/${dep}" ]; then + pull_package "$dep" + fi + done + unset dep + fi + + if [ ! -e "$package_tmpdir/package.pkg.tar.xz" ]; then + echo "[*] Downloading '$package_name'..." + curl --fail --location --output "$package_tmpdir/package.pkg.tar.xz" "${REPO_BASE_URL}/${PACKAGE_METADATA[${package_name}]}" + + echo "[*] Extracting '$package_name'..." + (cd "$package_tmpdir" + tar xJf package.pkg.tar.xz + if [ -d ./data ]; then + cp -r ./data "$BOOTSTRAP_ROOTFS" + fi + local metadata_package_sp=(${PACKAGE_METADATA[${package_name}]//// }) + if [ $(echo "${metadata_package_sp[1]}" | grep "any.") ]; then + local local_dir_sp=(${metadata_package_sp[1]//-any/ }) + else + local local_dir_sp=(${metadata_package_sp[1]//-${metadata_package_sp[0]}/ }) + fi + if [ $(echo "${package_name}" | grep "+") ]; then + local package_name_in_host="${package_name//+/0}" + local_dir_sp[0]="${local_dir_sp[0]//${package_name_in_host}/${package_name}}" + fi + mkdir -p "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/var/lib/pacman/local/${local_dir_sp[0]}" + cp -r .MTREE "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/var/lib/pacman/local/${local_dir_sp[0]}/mtree" + cp -r "${package_desc}" "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/var/lib/pacman/local/${local_dir_sp[0]}/desc" + if [ -f .INSTALL ]; then + cp -r .INSTALL "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/var/lib/pacman/local/${local_dir_sp[0]}/install" + fi + { + echo "%FILES%" + if [ -d ./data ]; then + find data + fi + } >> "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/var/lib/pacman/local/${local_dir_sp[0]}/files" + ) + fi + fi +} + +# Final stage: generate bootstrap archive and place it to current +# working directory. +# Information about symlinks is stored in file SYMLINKS.txt. +create_bootstrap_archive() { + echo "[*] Creating 'bootstrap-${1}.zip'..." + (cd "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}" + # Do not store symlinks in bootstrap archive. + # Instead, put all information to SYMLINKS.txt + while read -r -d '' link; do + echo "$(readlink "$link")←${link}" >> SYMLINKS.txt + rm -f "$link" + done < <(find . -type l -print0) + + zip -r9 "${BOOTSTRAP_TMPDIR}/bootstrap-${1}.zip" ./* + ) + + mv -f "${BOOTSTRAP_TMPDIR}/bootstrap-${1}.zip" ./ + echo "[*] Finished successfully (${1})." +} + +show_usage() { + echo + echo "Usage: generate-bootstraps.sh [options]" + echo + echo "Generate bootstrap archives for Termux application." + echo + echo "Options:" + echo + echo " -h, --help Show this help." + echo + echo " --android10 Generate bootstrap archives for Android 10." + echo + echo " -a, --add PKG_LIST Specify one or more additional packages" + echo " to include into bootstrap archive." + echo " Multiple packages should be passed as" + echo " comma-separated list." + echo + echo " --pm MANAGER Set up a package manager in bootstrap." + echo " It can only be pacman or apt (the default is apt)." + echo + echo " --architectures ARCH_LIST Override default list of architectures" + echo " for which bootstrap archives will be" + echo " created." + echo " Multiple architectures should be passed" + echo " as comma-separated list." + echo + echo " -r, --repository URL Specify URL for APT repository from" + echo " which packages will be downloaded." + echo " This must be passed after '--pm' option." + echo + echo "Architectures: ${TERMUX_ARCHITECTURES[*]}" + echo "Repository Base Url: ${REPO_BASE_URL}" + echo "Prefix: ${TERMUX_PREFIX}" + echo "Package manager: ${TERMUX_PACKAGE_MANAGER}" + echo +} + +while (($# > 0)); do + case "$1" in + -h|--help) + show_usage + exit 0 + ;; + --android10) + BOOTSTRAP_ANDROID10_COMPATIBLE=true + ;; + -a|--add) + if [ $# -gt 1 ] && [ -n "$2" ] && [[ $2 != -* ]]; then + for pkg in $(echo "$2" | tr ',' ' '); do + ADDITIONAL_PACKAGES+=("$pkg") + done + unset pkg + shift 1 + else + echo "[!] Option '--add' requires an argument." + show_usage + exit 1 + fi + ;; + --pm) + if [ $# -gt 1 ] && [ -n "$2" ] && [[ $2 != -* ]]; then + TERMUX_PACKAGE_MANAGER="$2" + REPO_BASE_URL="${REPO_BASE_URLS[${TERMUX_PACKAGE_MANAGER}]}" + shift 1 + else + echo "[!] Option '--pm' requires an argument." 1>&2 + show_usage + exit 1 + fi + ;; + --architectures) + if [ $# -gt 1 ] && [ -n "$2" ] && [[ $2 != -* ]]; then + TERMUX_ARCHITECTURES=() + for arch in $(echo "$2" | tr ',' ' '); do + TERMUX_ARCHITECTURES+=("$arch") + done + unset arch + shift 1 + else + echo "[!] Option '--architectures' requires an argument." + show_usage + exit 1 + fi + ;; + -r|--repository) + if [ $# -gt 1 ] && [ -n "$2" ] && [[ $2 != -* ]]; then + REPO_BASE_URL="$2" + shift 1 + else + echo "[!] Option '--repository' requires an argument." + show_usage + exit 1 + fi + ;; + *) + echo "[!] Got unknown option '$1'" + show_usage + exit 1 + ;; + esac + shift 1 +done + +if [[ "$TERMUX_PACKAGE_MANAGER" == *" "* ]] || [[ " ${TERMUX_PACKAGE_MANAGERS[*]} " != *" $TERMUX_PACKAGE_MANAGER "* ]]; then + echo "[!] Invalid package manager '$TERMUX_PACKAGE_MANAGER'" 1>&2 + echo "Supported package managers: '${TERMUX_PACKAGE_MANAGERS[*]}'" 1>&2 + exit 1 +fi + +if [ -z "$REPO_BASE_URL" ]; then + echo "[!] The repository base url is not set." 1>&2 + exit 1 +fi + +for package_arch in "${TERMUX_ARCHITECTURES[@]}"; do + BOOTSTRAP_ROOTFS="$BOOTSTRAP_TMPDIR/rootfs-${package_arch}" + BOOTSTRAP_PKGDIR="$BOOTSTRAP_TMPDIR/packages-${package_arch}" + + # Create initial directories for $TERMUX_PREFIX + if ! ${BOOTSTRAP_ANDROID10_COMPATIBLE}; then + if [ ${TERMUX_PACKAGE_MANAGER} = "apt" ]; then + mkdir -p "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/etc/apt/apt.conf.d" + mkdir -p "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/etc/apt/preferences.d" + mkdir -p "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/var/lib/dpkg/info" + mkdir -p "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/var/lib/dpkg/triggers" + mkdir -p "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/var/lib/dpkg/updates" + mkdir -p "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/var/log/apt" + touch "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/var/lib/dpkg/available" + touch "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/var/lib/dpkg/status" + else + mkdir -p "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/var/lib/pacman/sync" + mkdir -p "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/var/lib/pacman/local" + echo "9" >> "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/var/lib/pacman/local/ALPM_DB_VERSION" + mkdir -p "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/var/cache/pacman/pkg" + mkdir -p "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/var/log" + fi + fi + mkdir -p "${BOOTSTRAP_ROOTFS}/${TERMUX_PREFIX}/tmp" + + # Read package metadata. + unset PACKAGE_METADATA + declare -A PACKAGE_METADATA + if [ ${TERMUX_PACKAGE_MANAGER} = "apt" ]; then + read_package_list_deb "$package_arch" + else + read_package_list_pac "$package_arch" + fi + + # Package manager. + if ! ${BOOTSTRAP_ANDROID10_COMPATIBLE}; then + pull_package ${TERMUX_PACKAGE_MANAGER} + fi + + # Core utilities. + pull_package bash + pull_package bzip2 + if ! ${BOOTSTRAP_ANDROID10_COMPATIBLE}; then + pull_package command-not-found + else + pull_package proot + fi + pull_package coreutils + pull_package curl + pull_package dash + pull_package diffutils + pull_package findutils + pull_package gawk + pull_package grep + pull_package gzip + pull_package less + pull_package procps + pull_package psmisc + pull_package sed + pull_package tar + pull_package termux-exec + if [ ${TERMUX_PACKAGE_MANAGER} = "apt" ]; then + pull_package termux-keyring + fi + pull_package termux-tools + pull_package util-linux + pull_package xz-utils + + # Additional. + pull_package ed + if [ ${TERMUX_PACKAGE_MANAGER} = "apt" ]; then + pull_package debianutils + fi + pull_package dos2unix + pull_package inetutils + pull_package lsof + pull_package nano + pull_package net-tools + pull_package patch + pull_package unzip + + # Handle additional packages. + for add_pkg in "${ADDITIONAL_PACKAGES[@]}"; do + pull_package "$add_pkg" + done + unset add_pkg + + # Create bootstrap archive. + create_bootstrap_archive "$package_arch" +done diff --git a/scripts/get_hash_from_file.py b/scripts/get_hash_from_file.py new file mode 100755 index 000000000..420db8ffc --- /dev/null +++ b/scripts/get_hash_from_file.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 + +import sys + +def get_pkg_hash_from_Packages(Packages_file, package, version, hash="SHA256"): + with open(Packages_file, 'r') as Packages: + package_list = Packages.read().split('\n\n') + for pkg in package_list: + if pkg.split('\n')[0] == "Package: "+package: + for line in pkg.split('\n'): + # Assuming Filename: comes before Version: + if line.startswith('Filename:'): + print(line.split(" ")[1] + " ") + elif line.startswith('Version:'): + if line != 'Version: '+version: + # Seems the repo contains the wrong version, or several versions + # We can't use this one so continue looking + break + elif line.startswith(hash): + print(line.split(" ")[1]) + break + +def get_Packages_hash_from_Release(Release_file, arch, component, hash="SHA256"): + string_to_find = component+'/binary-'+arch+'/Packages' + with open(Release_file, 'r') as Release: + hash_list = Release.readlines() + for i in range(len(hash_list)): + if hash_list[i].startswith(hash+':'): + break + for j in range(i, len(hash_list)): + if string_to_find in hash_list[j].strip(' '): + hash_entry = list(filter(lambda s: s != '', hash_list[j].strip('').split(' '))) + if hash_entry[2].startswith(".work_"): + continue + print(hash_entry[0]) + break + +if __name__ == '__main__': + if len(sys.argv) < 2: + sys.exit('Too few arguments, I need the path to a Packages file, a package name and a version, or an InRelease file, an architecture and a component name. Exiting') + + if sys.argv[1].endswith('Packages'): + get_pkg_hash_from_Packages(sys.argv[1], sys.argv[2], sys.argv[3]) + elif sys.argv[1].endswith(('InRelease', 'Release')): + get_Packages_hash_from_Release(sys.argv[1], sys.argv[2], sys.argv[3]) + else: + sys.exit(sys.argv[1]+' does not seem to be a path to a Packages or InRelease/Release file') diff --git a/scripts/lint-packages.sh b/scripts/lint-packages.sh new file mode 100755 index 000000000..af96695c8 --- /dev/null +++ b/scripts/lint-packages.sh @@ -0,0 +1,461 @@ +#!/usr/bin/env bash + +set -e -u + +REPO_DIR=$(realpath "$(dirname "$0")/../") + +check_package_license() { + local pkg_licenses=$1 + local license + local license_ok=true + + IFS="," + for license in $pkg_licenses; do + license=$(echo "$license" | sed -r 's/^\s*(\S+(\s+\S+)*)\s*$/\1/') + + case "$license" in + AFL-2.1|AFL-3.0|AGPL-V3|APL-1.0|APSL-2.0|Apache-1.0|Apache-1.1);; + Apache-2.0|Artistic-License-2.0|Attribution|BSD|"BSD 2-Clause");; + "BSD 3-Clause"|"BSD New"|"BSD Simplified"|BSL-1.0|Bouncy-Castle);; + CA-TOSL-1.1|CC0-1.0|CDDL-1.0|CDDL-1.1|CPAL-1.0|CPL-1.0|CPOL);; + CPOL-1.02|CUAOFFICE-1.0|CeCILL-1|CeCILL-2|CeCILL-2.1|CeCILL-B);; + CeCILL-C|Codehaus|Copyfree|Day|Day-Addendum|ECL2|EPL-1.0|EPL-2.0);; + EUDATAGRID|EUPL-1.1|EUPL-1.2|Eiffel-2.0|Entessa-1.0);; + Facebook-Platform|Fair|Frameworx-1.0|GPL-2.0|GPL-3.0|GPL-3.0-only);; + GPL-3.0-or-later|Go|HSQLDB|Historical|IBMPL-1.0|IJG|IPAFont-1.0);; + ISC|IU-Extreme-1.1.1|ImageMagick|JA-SIG|JSON|JTidy|LGPL-2.0);; + LGPL-2.1|LGPL-3.0|LPPL-1.0|Libpng|Lucent-1.02|MIT|MPL-2.0|MS-PL);; + MS-RL|MirOS|Motosoto-0.9.1|Mozilla-1.1|Multics|NASA-1.3|NAUMEN);; + NCSA|NOSL-3.0|NTP|NUnit-2.6.3|NUnit-Test-Adapter-2.6.3|Nethack);; + Nokia-1.0a|OCLC-2.0|OSL-3.0|OpenLDAP|OpenSSL|Openfont-1.1);; + Opengroup|PHP-3.0|PHP-3.01|PostgreSQL|"Public Domain"|"Public Domain - SUN");; + PythonPL|PythonSoftFoundation|QTPL-1.0|RPL-1.5|Real-1.0|RicohPL);; + SUNPublic-1.0|Scala|SimPL-2.0|Sleepycat|Sybase-1.0|TMate|UPL-1.0);; + Unicode-DFS-2015|Unlicense|UoI-NCSA|"VIM License"|VovidaPL-1.0|W3C);; + WTFPL|Xnet|ZLIB|ZPL-2.0|wxWindows);; + + *) + license_ok=false + break + ;; + esac + done + IFS=$old_ifs + + if $license_ok; then + return 0 + else + return 1 + fi +} + +lint_package() { + local package_script + local package_name + + package_script=$1 + package_name=$(basename "$(dirname "$package_script")") + + echo "================================================================" + echo + echo "Package: $package_name" + echo + echo -n "Syntax check: " + + local syntax_errors + syntax_errors=$(bash -n "$package_script" 2>&1) + + if [ -n "$syntax_errors" ]; then + echo "FAILED" + echo + echo "$syntax_errors" + echo + + return 1 + else + echo "PASS" + fi + + echo + + # Fields checking is done in subshell since we will source build.sh. + (set +e +u + local pkg_lint_error + + # Certain fields may be API-specific. + # Using API 24 here. + TERMUX_PKG_API_LEVEL=24 + + if [ -f "$REPO_DIR/scripts/properties.sh" ]; then + . "$REPO_DIR/scripts/properties.sh" + fi + + . "$package_script" + + pkg_lint_error=false + + echo -n "TERMUX_PKG_HOMEPAGE: " + if [ -n "$TERMUX_PKG_HOMEPAGE" ]; then + if ! grep -qP '^https://.+' <<< "$TERMUX_PKG_HOMEPAGE"; then + echo "NON-HTTPS (acceptable)" + else + echo "PASS" + fi + else + echo "NOT SET" + pkg_lint_error=true + fi + + echo -n "TERMUX_PKG_DESCRIPTION: " + if [ -n "$TERMUX_PKG_DESCRIPTION" ]; then + str_length=$(($(wc -c <<< "$TERMUX_PKG_DESCRIPTION") - 1)) + + if [ $str_length -gt 100 ]; then + echo "TOO LONG (allowed: 100 characters max)" + else + echo "PASS" + fi + + unset str_length + else + echo "NOT SET" + pkg_lint_error=true + fi + + echo -n "TERMUX_PKG_LICENSE: " + if [ -n "$TERMUX_PKG_LICENSE" ]; then + if [ "$TERMUX_PKG_LICENSE" = "custom" ]; then + echo "CUSTOM" + elif [ "$TERMUX_PKG_LICENSE" = "non-free" ]; then + echo "NON-FREE" + else + if check_package_license "$TERMUX_PKG_LICENSE"; then + echo "PASS" + else + echo "INVALID" + pkg_lint_error=true + fi + fi + else + echo "NOT SET" + pkg_lint_error=true + fi + + echo -n "TERMUX_PKG_MAINTAINER: " + if [ -n "$TERMUX_PKG_MAINTAINER" ]; then + echo "PASS" + else + echo "NOT SET" + pkg_lint_error=true + fi + + if [ -n "$TERMUX_PKG_API_LEVEL" ]; then + echo -n "TERMUX_PKG_API_LEVEL: " + + if grep -qP '^[1-9][0-9]$' <<< "$TERMUX_PKG_API_LEVEL"; then + if [ $TERMUX_PKG_API_LEVEL -lt 24 ] || [ $TERMUX_PKG_API_LEVEL -gt 28 ]; then + echo "INVALID (allowed: number in range 24 - 28)" + pkg_lint_error=true + else + echo "PASS" + fi + else + echo "INVALID (allowed: number in range 24 - 28)" + pkg_lint_error=true + fi + fi + + echo -n "TERMUX_PKG_VERSION: " + if [ -n "$TERMUX_PKG_VERSION" ]; then + if grep -qiP '^([0-9]+\:)?[0-9][0-9a-z+\-\.]*$' <<< "$TERMUX_PKG_VERSION"; then + echo "PASS" + else + echo "INVALID (contains characters that are not allowed)" + pkg_lint_error=true + fi + else + echo "NOT SET" + pkg_lint_error=true + fi + + if [ -n "$TERMUX_PKG_REVISION" ]; then + echo -n "TERMUX_PKG_REVISION: " + + if grep -qP '^[1-9](\d{1,8})?$' <<< "$TERMUX_PKG_REVISION"; then + echo "PASS" + else + echo "INVALID (allowed: number in range 1 - 999999999)" + pkg_lint_error=true + fi + fi + + if [ -n "$TERMUX_PKG_SKIP_SRC_EXTRACT" ]; then + echo -n "TERMUX_PKG_SKIP_SRC_EXTRACT: " + + if [ "$TERMUX_PKG_SKIP_SRC_EXTRACT" = "true" ] || [ "$TERMUX_PKG_SKIP_SRC_EXTRACT" = "false" ]; then + echo "PASS" + else + echo "INVALID (allowed: true / false)" + pkg_lint_error=true + fi + fi + + if [ -n "$TERMUX_PKG_SRCURL" ]; then + echo -n "TERMUX_PKG_SRCURL: " + + urls_ok=true + for url in "${TERMUX_PKG_SRCURL[@]}"; do + if [ -n "$url" ]; then + if ! grep -qP '^https://.+' <<< "$url"; then + echo "NON-HTTPS (acceptable)" + urls_ok=false + break + fi + else + echo "NOT SET (one of the array elements)" + urls_ok=false + pkg_lint_error=true + break + fi + done + unset url + + if $urls_ok; then + echo "PASS" + fi + unset urls_ok + + echo -n "TERMUX_PKG_SHA256: " + if [ -n "$TERMUX_PKG_SHA256" ]; then + if [ "${#TERMUX_PKG_SRCURL[@]}" -eq "${#TERMUX_PKG_SHA256[@]}" ]; then + sha256_ok=true + + for sha256 in "${TERMUX_PKG_SHA256[@]}"; do + if ! grep -qP '^[0-9a-fA-F]{64}$' <<< "${sha256}" && [ "$sha256" != "SKIP_CHECKSUM" ]; then + echo "MALFORMED (SHA-256 should contain 64 hexadecimal numbers)" + sha256_ok=false + pkg_lint_error=true + break + fi + done + unset sha256 + + if $sha256_ok; then + echo "PASS" + fi + unset sha256_ok + else + echo "LENGTHS OF 'TERMUX_PKG_SRCURL' AND 'TERMUX_PKG_SHA256' ARE NOT EQUAL" + pkg_lint_error=true + fi + elif [ "${TERMUX_PKG_SRCURL: -4}" == ".git" ]; then + echo "NOT SET (acceptable since TERMUX_PKG_SRCURL is git repo)" + else + echo "NOT SET" + pkg_lint_error=true + fi + else + if [ "$TERMUX_PKG_SKIP_SRC_EXTRACT" != "true" ] && ! declare -F termux_step_extract_package > /dev/null 2>&1; then + echo "TERMUX_PKG_SRCURL: NOT SET (set TERMUX_PKG_SKIP_SRC_EXTRACT to 'true' if no sources downloaded)" + pkg_lint_error=true + fi + fi + + if [ -n "$TERMUX_PKG_METAPACKAGE" ]; then + echo -n "TERMUX_PKG_METAPACKAGE: " + + if [ "$TERMUX_PKG_METAPACKAGE" = "true" ] || [ "$TERMUX_PKG_METAPACKAGE" = "false" ]; then + echo "PASS" + else + echo "INVALID (allowed: true / false)" + pkg_lint_error=true + fi + fi + + if [ -n "$TERMUX_PKG_ESSENTIAL" ]; then + echo -n "TERMUX_PKG_ESSENTIAL: " + if [ "$TERMUX_PKG_ESSENTIAL" = "true" ] || [ "$TERMUX_PKG_ESSENTIAL" = "false" ]; then + echo "PASS" + else + echo "INVALID (allowed: true / false)" + pkg_lint_error=true + fi + fi + + if [ -n "$TERMUX_PKG_NO_STATICSPLIT" ]; then + echo -n "TERMUX_PKG_NO_STATICSPLIT: " + + if [ "$TERMUX_PKG_NO_STATICSPLIT" = "true" ] || [ "$TERMUX_PKG_NO_STATICSPLIT" = "false" ]; then + echo "PASS" + else + echo "INVALID (allowed: true / false)" + pkg_lint_error=true + fi + fi + + if [ -n "$TERMUX_PKG_BUILD_IN_SRC" ]; then + echo -n "TERMUX_PKG_BUILD_IN_SRC: " + + if [ "$TERMUX_PKG_BUILD_IN_SRC" = "true" ] || [ "$TERMUX_PKG_BUILD_IN_SRC" = "false" ]; then + echo "PASS" + else + echo "INVALID (allowed: true / false)" + pkg_lint_error=true + fi + fi + + if [ -n "$TERMUX_PKG_HAS_DEBUG" ]; then + echo -n "TERMUX_PKG_HAS_DEBUG: " + + if [ "$TERMUX_PKG_HAS_DEBUG" = "true" ] || [ "$TERMUX_PKG_HAS_DEBUG" = "false" ]; then + echo "PASS" + else + echo "INVALID (allowed: true / false)" + pkg_lint_error=true + fi + fi + + if [ -n "$TERMUX_PKG_PLATFORM_INDEPENDENT" ]; then + echo -n "TERMUX_PKG_PLATFORM_INDEPENDENT: " + + if [ "$TERMUX_PKG_PLATFORM_INDEPENDENT" = "true" ] || [ "$TERMUX_PKG_PLATFORM_INDEPENDENT" = "false" ]; then + echo "PASS" + else + echo "INVALID (allowed: true / false)" + pkg_lint_error=true + fi + fi + + if [ -n "$TERMUX_PKG_HOSTBUILD" ]; then + echo -n "TERMUX_PKG_HOSTBUILD: " + + if [ "$TERMUX_PKG_HOSTBUILD" = "true" ] || [ "$TERMUX_PKG_HOSTBUILD" = "false" ]; then + echo "PASS" + else + echo "INVALID (allowed: true / false)" + pkg_lint_error=true + fi + fi + + if [ -n "$TERMUX_PKG_FORCE_CMAKE" ]; then + echo -n "TERMUX_PKG_FORCE_CMAKE: " + + if [ "$TERMUX_PKG_FORCE_CMAKE" = "true" ] || [ "$TERMUX_PKG_FORCE_CMAKE" = "false" ]; then + echo "PASS" + else + echo "INVALID (allowed: true / false)" + pkg_lint_error=true + fi + fi + + if [ -n "$TERMUX_PKG_RM_AFTER_INSTALL" ]; then + echo -n "TERMUX_PKG_RM_AFTER_INSTALL: " + file_path_ok=true + + while read -r file_path; do + [ -z "$file_path" ] && continue + + if grep -qP '^(\.\.)?/' <<< "$file_path"; then + echo "INVALID (file path should be relative to prefix)" + file_path_ok=false + pkg_lint_error=true + break + fi + done <<< "$TERMUX_PKG_RM_AFTER_INSTALL" + unset file_path + + if $file_path_ok; then + echo "PASS" + fi + unset file_path_ok + fi + + if [ -n "$TERMUX_PKG_CONFFILES" ]; then + echo -n "TERMUX_PKG_CONFFILES: " + file_path_ok=true + + while read -r file_path; do + [ -z "$file_path" ] && continue + + if grep -qP '^(\.\.)?/' <<< "$file_path"; then + echo "INVALID (file path should be relative to prefix)" + file_path_ok=false + pkg_lint_error=true + break + fi + done <<< "$TERMUX_PKG_CONFFILES" + unset file_path + + if $file_path_ok; then + echo "PASS" + fi + unset file_path_ok + fi + + if [ -n "$TERMUX_PKG_SERVICE_SCRIPT" ]; then + echo -n "TERMUX_PKG_SERVICE_SCRIPT: " + array_length=${#TERMUX_PKG_SERVICE_SCRIPT[@]} + if [ $(( $array_length & 1 )) -eq 1 ]; then + echo "INVALID (TERMUX_PKG_SERVICE_SCRIPT has to be an array of even length)" + pkg_lint_error=true + else + echo "PASS" + fi + fi + + if $pkg_lint_error; then + exit 1 + else + exit 0 + fi + ) + + local ret=$? + + echo + + return "$ret" +} + +linter_main() { + local package_counter=0 + local problems_found=false + local package_script + + for package_script in "$@"; do + if ! lint_package "$package_script"; then + problems_found=true + break + fi + + package_counter=$((package_counter + 1)) + done + + if $problems_found; then + echo "================================================================" + echo + echo "A problem has been found in '$(realpath --relative-to="$REPO_DIR" "$package_script")'." + echo "Checked $package_counter packages before the first error was detected." + echo + echo "================================================================" + + return 1 + else + echo "================================================================" + echo + echo "Checked $package_counter packages." + echo "Everything seems ok." + echo + echo "================================================================" + fi + + return 0 +} + +if [ $# -eq 0 ]; then + for repo_dir in $(jq --raw-output 'keys | .[]' $REPO_DIR/repo.json); do + linter_main $repo_dir/*/build.sh + done || exit 1 +else + linter_main "$@" || exit 1 +fi diff --git a/scripts/list-packages.sh b/scripts/list-packages.sh new file mode 100755 index 000000000..1ff8665ac --- /dev/null +++ b/scripts/list-packages.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# list-packages.sh - tool to list all package with home pages and descriptions + +show_package() { + . $1/build.sh + local pkg=$(basename $1) + echo "$pkg($TERMUX_PKG_VERSION): $TERMUX_PKG_HOMEPAGE" + echo " $TERMUX_PKG_DESCRIPTION" +} + +for path in packages/*; do + ( show_package $path ) +done diff --git a/scripts/list-versions.sh b/scripts/list-versions.sh new file mode 100755 index 000000000..31d6ce9cf --- /dev/null +++ b/scripts/list-versions.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +SCRIPT_DIR=$(dirname "$(realpath "$0")") +. "$SCRIPT_DIR"/properties.sh + +check_package() { # path + local path=$1 + local pkg=$(basename "$path") + TERMUX_PKG_REVISION=0 + TERMUX_ARCH=aarch64 + . "$path"/build.sh + if [ "$TERMUX_PKG_REVISION" != "0" ] || [ "$TERMUX_PKG_VERSION" != "${TERMUX_PKG_VERSION/-/}" ]; then + TERMUX_PKG_VERSION+="-$TERMUX_PKG_REVISION" + fi + echo "$pkg=$TERMUX_PKG_VERSION" +} + +for path in "${SCRIPT_DIR}"/../packages/*; do +( + check_package "$path" +) +done diff --git a/scripts/profile.json b/scripts/profile.json new file mode 100644 index 000000000..bfb8ec9c2 --- /dev/null +++ b/scripts/profile.json @@ -0,0 +1,770 @@ +{ + "description": "This is a custom seccomp profile which allows the personality system call, based on https://github.com/moby/moby/blob/85eaf23bf46b12827273ab2ff523c753117dbdc7/profiles/seccomp/default.json.", + "defaultAction": "SCMP_ACT_ERRNO", + "defaultErrnoRet": 1, + "archMap": [ + { + "architecture": "SCMP_ARCH_X86_64", + "subArchitectures": [ + "SCMP_ARCH_X86", + "SCMP_ARCH_X32" + ] + }, + { + "architecture": "SCMP_ARCH_AARCH64", + "subArchitectures": [ + "SCMP_ARCH_ARM" + ] + }, + { + "architecture": "SCMP_ARCH_MIPS64", + "subArchitectures": [ + "SCMP_ARCH_MIPS", + "SCMP_ARCH_MIPS64N32" + ] + }, + { + "architecture": "SCMP_ARCH_MIPS64N32", + "subArchitectures": [ + "SCMP_ARCH_MIPS", + "SCMP_ARCH_MIPS64" + ] + }, + { + "architecture": "SCMP_ARCH_MIPSEL64", + "subArchitectures": [ + "SCMP_ARCH_MIPSEL", + "SCMP_ARCH_MIPSEL64N32" + ] + }, + { + "architecture": "SCMP_ARCH_MIPSEL64N32", + "subArchitectures": [ + "SCMP_ARCH_MIPSEL", + "SCMP_ARCH_MIPSEL64" + ] + }, + { + "architecture": "SCMP_ARCH_S390X", + "subArchitectures": [ + "SCMP_ARCH_S390" + ] + } + ], + "syscalls": [ + { + "names": [ + "accept", + "accept4", + "access", + "adjtimex", + "alarm", + "bind", + "brk", + "capget", + "capset", + "chdir", + "chmod", + "chown", + "chown32", + "clock_adjtime", + "clock_adjtime64", + "clock_getres", + "clock_getres_time64", + "clock_gettime", + "clock_gettime64", + "clock_nanosleep", + "clock_nanosleep_time64", + "close", + "close_range", + "connect", + "copy_file_range", + "creat", + "dup", + "dup2", + "dup3", + "epoll_create", + "epoll_create1", + "epoll_ctl", + "epoll_ctl_old", + "epoll_pwait", + "epoll_pwait2", + "epoll_wait", + "epoll_wait_old", + "eventfd", + "eventfd2", + "execve", + "execveat", + "exit", + "exit_group", + "faccessat", + "faccessat2", + "fadvise64", + "fadvise64_64", + "fallocate", + "fanotify_mark", + "fchdir", + "fchmod", + "fchmodat", + "fchown", + "fchown32", + "fchownat", + "fcntl", + "fcntl64", + "fdatasync", + "fgetxattr", + "flistxattr", + "flock", + "fork", + "fremovexattr", + "fsetxattr", + "fstat", + "fstat64", + "fstatat64", + "fstatfs", + "fstatfs64", + "fsync", + "ftruncate", + "ftruncate64", + "futex", + "futex_time64", + "futimesat", + "getcpu", + "getcwd", + "getdents", + "getdents64", + "getegid", + "getegid32", + "geteuid", + "geteuid32", + "getgid", + "getgid32", + "getgroups", + "getgroups32", + "getitimer", + "getpeername", + "getpgid", + "getpgrp", + "getpid", + "getppid", + "getpriority", + "getrandom", + "getresgid", + "getresgid32", + "getresuid", + "getresuid32", + "getrlimit", + "get_robust_list", + "getrusage", + "getsid", + "getsockname", + "getsockopt", + "get_thread_area", + "gettid", + "gettimeofday", + "getuid", + "getuid32", + "getxattr", + "inotify_add_watch", + "inotify_init", + "inotify_init1", + "inotify_rm_watch", + "io_cancel", + "ioctl", + "io_destroy", + "io_getevents", + "io_pgetevents", + "io_pgetevents_time64", + "ioprio_get", + "ioprio_set", + "io_setup", + "io_submit", + "io_uring_enter", + "io_uring_register", + "io_uring_setup", + "ipc", + "kill", + "lchown", + "lchown32", + "lgetxattr", + "link", + "linkat", + "listen", + "listxattr", + "llistxattr", + "_llseek", + "lremovexattr", + "lseek", + "lsetxattr", + "lstat", + "lstat64", + "madvise", + "membarrier", + "memfd_create", + "mincore", + "mkdir", + "mkdirat", + "mknod", + "mknodat", + "mlock", + "mlock2", + "mlockall", + "mmap", + "mmap2", + "mprotect", + "mq_getsetattr", + "mq_notify", + "mq_open", + "mq_timedreceive", + "mq_timedreceive_time64", + "mq_timedsend", + "mq_timedsend_time64", + "mq_unlink", + "mremap", + "msgctl", + "msgget", + "msgrcv", + "msgsnd", + "msync", + "munlock", + "munlockall", + "munmap", + "nanosleep", + "newfstatat", + "_newselect", + "open", + "openat", + "openat2", + "pause", + "personality", + "pidfd_open", + "pidfd_send_signal", + "pipe", + "pipe2", + "poll", + "ppoll", + "ppoll_time64", + "prctl", + "pread64", + "preadv", + "preadv2", + "prlimit64", + "pselect6", + "pselect6_time64", + "pwrite64", + "pwritev", + "pwritev2", + "read", + "readahead", + "readlink", + "readlinkat", + "readv", + "recv", + "recvfrom", + "recvmmsg", + "recvmmsg_time64", + "recvmsg", + "remap_file_pages", + "removexattr", + "rename", + "renameat", + "renameat2", + "restart_syscall", + "rmdir", + "rseq", + "rt_sigaction", + "rt_sigpending", + "rt_sigprocmask", + "rt_sigqueueinfo", + "rt_sigreturn", + "rt_sigsuspend", + "rt_sigtimedwait", + "rt_sigtimedwait_time64", + "rt_tgsigqueueinfo", + "sched_getaffinity", + "sched_getattr", + "sched_getparam", + "sched_get_priority_max", + "sched_get_priority_min", + "sched_getscheduler", + "sched_rr_get_interval", + "sched_rr_get_interval_time64", + "sched_setaffinity", + "sched_setattr", + "sched_setparam", + "sched_setscheduler", + "sched_yield", + "seccomp", + "select", + "semctl", + "semget", + "semop", + "semtimedop", + "semtimedop_time64", + "send", + "sendfile", + "sendfile64", + "sendmmsg", + "sendmsg", + "sendto", + "setfsgid", + "setfsgid32", + "setfsuid", + "setfsuid32", + "setgid", + "setgid32", + "setgroups", + "setgroups32", + "setitimer", + "setpgid", + "setpriority", + "setregid", + "setregid32", + "setresgid", + "setresgid32", + "setresuid", + "setresuid32", + "setreuid", + "setreuid32", + "setrlimit", + "set_robust_list", + "setsid", + "setsockopt", + "set_thread_area", + "set_tid_address", + "setuid", + "setuid32", + "setxattr", + "shmat", + "shmctl", + "shmdt", + "shmget", + "shutdown", + "sigaltstack", + "signalfd", + "signalfd4", + "sigprocmask", + "sigreturn", + "socket", + "socketcall", + "socketpair", + "splice", + "stat", + "stat64", + "statfs", + "statfs64", + "statx", + "symlink", + "symlinkat", + "sync", + "sync_file_range", + "syncfs", + "sysinfo", + "tee", + "tgkill", + "time", + "timer_create", + "timer_delete", + "timer_getoverrun", + "timer_gettime", + "timer_gettime64", + "timer_settime", + "timer_settime64", + "timerfd_create", + "timerfd_gettime", + "timerfd_gettime64", + "timerfd_settime", + "timerfd_settime64", + "times", + "tkill", + "truncate", + "truncate64", + "ugetrlimit", + "umask", + "uname", + "unlink", + "unlinkat", + "utime", + "utimensat", + "utimensat_time64", + "utimes", + "vfork", + "vmsplice", + "wait4", + "waitid", + "waitpid", + "write", + "writev" + ], + "action": "SCMP_ACT_ALLOW" + }, + { + "names": [ + "process_vm_readv", + "process_vm_writev", + "ptrace" + ], + "action": "SCMP_ACT_ALLOW", + "includes": { + "minKernel": "4.8" + } + }, + { + "names": [ + "personality" + ], + "action": "SCMP_ACT_ALLOW", + "args": [ + { + "index": 0, + "value": 0, + "op": "SCMP_CMP_EQ" + } + ] + }, + { + "names": [ + "personality" + ], + "action": "SCMP_ACT_ALLOW", + "args": [ + { + "index": 0, + "value": 8, + "op": "SCMP_CMP_EQ" + } + ] + }, + { + "names": [ + "personality" + ], + "action": "SCMP_ACT_ALLOW", + "args": [ + { + "index": 0, + "value": 131072, + "op": "SCMP_CMP_EQ" + } + ] + }, + { + "names": [ + "personality" + ], + "action": "SCMP_ACT_ALLOW", + "args": [ + { + "index": 0, + "value": 131080, + "op": "SCMP_CMP_EQ" + } + ] + }, + { + "names": [ + "personality" + ], + "action": "SCMP_ACT_ALLOW", + "args": [ + { + "index": 0, + "value": 4294967295, + "op": "SCMP_CMP_EQ" + } + ] + }, + { + "names": [ + "sync_file_range2", + "swapcontext" + ], + "action": "SCMP_ACT_ALLOW", + "includes": { + "arches": [ + "ppc64le" + ] + } + }, + { + "names": [ + "arm_fadvise64_64", + "arm_sync_file_range", + "sync_file_range2", + "breakpoint", + "cacheflush", + "set_tls" + ], + "action": "SCMP_ACT_ALLOW", + "includes": { + "arches": [ + "arm", + "arm64" + ] + } + }, + { + "names": [ + "arch_prctl" + ], + "action": "SCMP_ACT_ALLOW", + "includes": { + "arches": [ + "amd64", + "x32" + ] + } + }, + { + "names": [ + "modify_ldt" + ], + "action": "SCMP_ACT_ALLOW", + "includes": { + "arches": [ + "amd64", + "x32", + "x86" + ] + } + }, + { + "names": [ + "s390_pci_mmio_read", + "s390_pci_mmio_write", + "s390_runtime_instr" + ], + "action": "SCMP_ACT_ALLOW", + "includes": { + "arches": [ + "s390", + "s390x" + ] + } + }, + { + "names": [ + "open_by_handle_at" + ], + "action": "SCMP_ACT_ALLOW", + "includes": { + "caps": [ + "CAP_DAC_READ_SEARCH" + ] + } + }, + { + "names": [ + "bpf", + "clone", + "clone3", + "fanotify_init", + "fsconfig", + "fsmount", + "fsopen", + "fspick", + "lookup_dcookie", + "mount", + "move_mount", + "name_to_handle_at", + "open_tree", + "perf_event_open", + "quotactl", + "setdomainname", + "sethostname", + "setns", + "syslog", + "umount", + "umount2", + "unshare" + ], + "action": "SCMP_ACT_ALLOW", + "includes": { + "caps": [ + "CAP_SYS_ADMIN" + ] + } + }, + { + "names": [ + "clone" + ], + "action": "SCMP_ACT_ALLOW", + "args": [ + { + "index": 0, + "value": 2114060288, + "op": "SCMP_CMP_MASKED_EQ" + } + ], + "excludes": { + "caps": [ + "CAP_SYS_ADMIN" + ], + "arches": [ + "s390", + "s390x" + ] + } + }, + { + "names": [ + "clone" + ], + "action": "SCMP_ACT_ALLOW", + "args": [ + { + "index": 1, + "value": 2114060288, + "op": "SCMP_CMP_MASKED_EQ" + } + ], + "comment": "s390 parameter ordering for clone is different", + "includes": { + "arches": [ + "s390", + "s390x" + ] + }, + "excludes": { + "caps": [ + "CAP_SYS_ADMIN" + ] + } + }, + { + "names": [ + "clone3" + ], + "action": "SCMP_ACT_ERRNO", + "errnoRet": 38, + "excludes": { + "caps": [ + "CAP_SYS_ADMIN" + ] + } + }, + { + "names": [ + "reboot" + ], + "action": "SCMP_ACT_ALLOW", + "includes": { + "caps": [ + "CAP_SYS_BOOT" + ] + } + }, + { + "names": [ + "chroot" + ], + "action": "SCMP_ACT_ALLOW", + "includes": { + "caps": [ + "CAP_SYS_CHROOT" + ] + } + }, + { + "names": [ + "delete_module", + "init_module", + "finit_module" + ], + "action": "SCMP_ACT_ALLOW", + "includes": { + "caps": [ + "CAP_SYS_MODULE" + ] + } + }, + { + "names": [ + "acct" + ], + "action": "SCMP_ACT_ALLOW", + "includes": { + "caps": [ + "CAP_SYS_PACCT" + ] + } + }, + { + "names": [ + "kcmp", + "pidfd_getfd", + "process_madvise", + "process_vm_readv", + "process_vm_writev", + "ptrace" + ], + "action": "SCMP_ACT_ALLOW", + "includes": { + "caps": [ + "CAP_SYS_PTRACE" + ] + } + }, + { + "names": [ + "iopl", + "ioperm" + ], + "action": "SCMP_ACT_ALLOW", + "includes": { + "caps": [ + "CAP_SYS_RAWIO" + ] + } + }, + { + "names": [ + "settimeofday", + "stime", + "clock_settime" + ], + "action": "SCMP_ACT_ALLOW", + "includes": { + "caps": [ + "CAP_SYS_TIME" + ] + } + }, + { + "names": [ + "vhangup" + ], + "action": "SCMP_ACT_ALLOW", + "includes": { + "caps": [ + "CAP_SYS_TTY_CONFIG" + ] + } + }, + { + "names": [ + "get_mempolicy", + "mbind", + "set_mempolicy" + ], + "action": "SCMP_ACT_ALLOW", + "includes": { + "caps": [ + "CAP_SYS_NICE" + ] + } + }, + { + "names": [ + "syslog" + ], + "action": "SCMP_ACT_ALLOW", + "includes": { + "caps": [ + "CAP_SYSLOG" + ] + } + } + ] +} diff --git a/scripts/properties.sh b/scripts/properties.sh new file mode 100644 index 000000000..8c328c8b6 --- /dev/null +++ b/scripts/properties.sh @@ -0,0 +1,35 @@ +# keep repology-metadata in sync with this + +TERMUX_SDK_REVISION=8512546 +TERMUX_ANDROID_BUILD_TOOLS_VERSION=30.0.3 +TERMUX_NDK_VERSION_NUM=23 +TERMUX_NDK_REVISION="c" +TERMUX_NDK_VERSION=$TERMUX_NDK_VERSION_NUM$TERMUX_NDK_REVISION +# when changing the above: +# remove TERMUX_PKG_REVISION in: +# libc++, ndk-multilib, ndk-sysroot, vulkan-loader-android +# update SHA256 sums in scripts/setup-android-sdk.sh +# check all packages build and run correctly and bump if needed + +export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 + +if [ "${TERMUX_PACKAGES_OFFLINE-false}" = "true" ]; then + export ANDROID_HOME=${TERMUX_SCRIPTDIR}/build-tools/android-sdk-$TERMUX_SDK_REVISION + export NDK=${TERMUX_SCRIPTDIR}/build-tools/android-ndk-r${TERMUX_NDK_VERSION} +else + : "${ANDROID_HOME:="${HOME}/lib/android-sdk-$TERMUX_SDK_REVISION"}" + : "${NDK:="${HOME}/lib/android-ndk-r${TERMUX_NDK_VERSION}"}" +fi + +# Termux packages configuration. +TERMUX_APP_PACKAGE="com.termux" +TERMUX_BASE_DIR="/data/data/${TERMUX_APP_PACKAGE}/files" +TERMUX_CACHE_DIR="/data/data/${TERMUX_APP_PACKAGE}/cache" +TERMUX_ANDROID_HOME="${TERMUX_BASE_DIR}/home" +TERMUX_APPS_DIR="${TERMUX_BASE_DIR}/apps" +TERMUX_PREFIX="${TERMUX_BASE_DIR}/usr" + +# Allow to override setup. +if [ -f "$HOME/.termuxrc" ]; then + . "$HOME/.termuxrc" +fi diff --git a/scripts/run-docker.ps1 b/scripts/run-docker.ps1 new file mode 100644 index 000000000..891c978f3 --- /dev/null +++ b/scripts/run-docker.ps1 @@ -0,0 +1,28 @@ +# PowerShell script to build Termux packages with Docker. +# +# Usage example: +# +# .\scripts\run-docker.ps1 ./build-package.sh -a arm libandroid-support + +Set-Variable -Name IMAGE_NAME -Value "termux/package-builder" +Set-Variable -Name CONTAINER_NAME -Value "termux-package-builder" + +Write-Output "Running container ${CONTAINER_NAME} from image ${IMAGE_NAME}..." + +docker start $CONTAINER_NAME 2>&1 | Out-Null + +if (-Not $?) { + Write-Output "Creating new container..." + docker run ` + --detach ` + --name $CONTAINER_NAME ` + --volume "${PWD}:/home/builder/termux-packages" ` + --tty ` + "$IMAGE_NAME" +} + +if ($args.Count -eq 0) { + docker exec --interactive --tty --user builder $CONTAINER_NAME bash +} else { + docker exec --interactive --tty --user builder $CONTAINER_NAME $args +} diff --git a/scripts/run-docker.sh b/scripts/run-docker.sh new file mode 100755 index 000000000..9c5472145 --- /dev/null +++ b/scripts/run-docker.sh @@ -0,0 +1,59 @@ +#!/bin/sh +set -e -u + +CONTAINER_HOME_DIR=/home/builder +UNAME=$(uname) +if [ "$UNAME" = Darwin ]; then + # Workaround for mac readlink not supporting -f. + REPOROOT=$PWD + SEC_OPT="" +else + REPOROOT="$(dirname $(readlink -f $0))/../" + SEC_OPT=" --security-opt seccomp=$REPOROOT/scripts/profile.json" +fi + +: ${TERMUX_BUILDER_IMAGE_NAME:=termux/package-builder} +: ${CONTAINER_NAME:=termux-package-builder} + +USER=builder + +if [ -n "${TERMUX_DOCKER_USE_SUDO-}" ]; then + SUDO="sudo" +else + SUDO="" +fi + +echo "Running container '$CONTAINER_NAME' from image '$TERMUX_BUILDER_IMAGE_NAME'..." + +# Check whether attached to tty and adjust docker flags accordingly. +if [ -t 1 ]; then + DOCKER_TTY=" --tty" +else + DOCKER_TTY="" +fi + +$SUDO docker start $CONTAINER_NAME >/dev/null 2>&1 || { + echo "Creating new container..." + $SUDO docker run \ + --detach \ + --name $CONTAINER_NAME \ + --volume $REPOROOT:$CONTAINER_HOME_DIR/termux-packages \ + $SEC_OPT \ + --tty \ + $TERMUX_BUILDER_IMAGE_NAME + if [ "$UNAME" != Darwin ]; then + if [ $(id -u) -ne 1000 -a $(id -u) -ne 0 ]; then + echo "Changed builder uid/gid... (this may take a while)" + $SUDO docker exec $DOCKER_TTY $CONTAINER_NAME sudo chown -R $(id -u) $CONTAINER_HOME_DIR + $SUDO docker exec $DOCKER_TTY $CONTAINER_NAME sudo chown -R $(id -u) /data + $SUDO docker exec $DOCKER_TTY $CONTAINER_NAME sudo usermod -u $(id -u) builder + $SUDO docker exec $DOCKER_TTY $CONTAINER_NAME sudo groupmod -g $(id -g) builder + fi + fi +} + +if [ "$#" -eq "0" ]; then + $SUDO docker exec --interactive $DOCKER_TTY $CONTAINER_NAME bash +else + $SUDO docker exec --interactive $DOCKER_TTY $CONTAINER_NAME "$@" +fi diff --git a/scripts/setup-android-sdk.sh b/scripts/setup-android-sdk.sh new file mode 100755 index 000000000..bb1cb8384 --- /dev/null +++ b/scripts/setup-android-sdk.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +set -e -u + +: "${TERMUX_PKG_TMPDIR:="/tmp"}" + +# Install desired parts of the Android SDK: +. $(cd "$(dirname "$0")"; pwd)/properties.sh +. $(cd "$(dirname "$0")"; pwd)/build/termux_download.sh + +ANDROID_SDK_FILE=commandlinetools-linux-${TERMUX_SDK_REVISION}_latest.zip +ANDROID_SDK_SHA256=2ccbda4302db862a28ada25aa7425d99dce9462046003c1714b059b5c47970d8 +ANDROID_NDK_FILE=android-ndk-r${TERMUX_NDK_VERSION}-linux.zip +ANDROID_NDK_SHA256=6ce94604b77d28113ecd588d425363624a5228d9662450c48d2e4053f8039242 +if [ ! -d $ANDROID_HOME ]; then + mkdir -p $ANDROID_HOME + cd $ANDROID_HOME/.. + rm -Rf $(basename $ANDROID_HOME) + + # https://developer.android.com/studio/index.html#command-tools + echo "Downloading android sdk..." + termux_download https://dl.google.com/android/repository/${ANDROID_SDK_FILE} \ + tools-$TERMUX_SDK_REVISION.zip \ + $ANDROID_SDK_SHA256 + rm -Rf android-sdk-$TERMUX_SDK_REVISION + unzip -q tools-$TERMUX_SDK_REVISION.zip -d android-sdk-$TERMUX_SDK_REVISION + + # Remove unused parts + rm -Rf android-sdk-$TERMUX_SDK_REVISION/{emulator*,lib*,proguard,templates} +fi + +if [ ! -d $NDK ]; then + mkdir -p $NDK + cd $NDK/.. + rm -Rf $(basename $NDK) + echo "Downloading android ndk..." + termux_download https://dl.google.com/android/repository/${ANDROID_NDK_FILE} \ + ndk-r${TERMUX_NDK_VERSION}.zip \ + $ANDROID_NDK_SHA256 + rm -Rf android-ndk-r$TERMUX_NDK_VERSION + unzip -q ndk-r${TERMUX_NDK_VERSION}.zip + + # Remove unused parts + rm -Rf android-ndk-r$TERMUX_NDK_VERSION/sources/cxx-stl/system +fi + +yes | $ANDROID_HOME/cmdline-tools/bin/sdkmanager --sdk_root=$ANDROID_HOME --licenses + +# The android platforms are used in the ecj and apksigner packages: +yes | $ANDROID_HOME/cmdline-tools/bin/sdkmanager --sdk_root=$ANDROID_HOME \ + "platform-tools" \ + "build-tools;${TERMUX_ANDROID_BUILD_TOOLS_VERSION}" \ + "platforms;android-32" \ + "platforms;android-28" \ + "platforms;android-24" \ + "platforms;android-21" diff --git a/scripts/setup-archlinux.sh b/scripts/setup-archlinux.sh new file mode 100755 index 000000000..d720a143e --- /dev/null +++ b/scripts/setup-archlinux.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash +set -e -u + +PACKAGES="" +PACKAGES+=" asciidoc" +PACKAGES+=" asciidoctor" # Used by weechat for man pages. +PACKAGES+=" automake" +PACKAGES+=" bison" +PACKAGES+=" clang" # Used by golang, useful to have same compiler building. +PACKAGES+=" curl" # Used for fetching sources. +PACKAGES+=" ed" # Used by bc. +PACKAGES+=" expat" # Needed by ghostscript. +PACKAGES+=" flex" +PACKAGES+=" gawk" # Needed by apr-util. +PACKAGES+=" gcc" # Host C/C++ compiler. +PACKAGES+=" gettext" # Provides 'msgfmt'. +PACKAGES+=" git" # Used by the neovim build. +PACKAGES+=" glib2" # Provides 'glib-genmarshal' which the glib build uses. +PACKAGES+=" gnupg" # Needed to verify downloaded debs. +PACKAGES+=" gperf" # Used by the fontconfig build. +PACKAGES+=" help2man" +PACKAGES+=" intltool" # Used by qalc build. +PACKAGES+=" jre8-openjdk-headless" +PACKAGES+=" libjpeg-turbo" # Needed by ghostscript. +PACKAGES+=" libtool" +PACKAGES+=" lua" # Needed to build luarocks package. +PACKAGES+=" lzip" +PACKAGES+=" m4" +PACKAGES+=" openssl" # Needed to build rust. +PACKAGES+=" patch" +PACKAGES+=" pkgconf" +PACKAGES+=" python" +PACKAGES+=" python-docutils" # For rst2man, used by mpv. +PACKAGES+=" python-recommonmark" # Needed for LLVM-8 documentation. +PACKAGES+=" python-setuptools" # Needed by at least asciinema. +PACKAGES+=" python-sphinx" # Needed by notmuch man page generation. +PACKAGES+=" python2" +PACKAGES+=" ruby" # Needed to build ruby. +PACKAGES+=" scdoc" # Needed by aerc. +PACKAGES+=" scons" +PACKAGES+=" tar" +PACKAGES+=" texinfo" +PACKAGES+=" unzip" +PACKAGES+=" xmlto" + +# Do not require sudo if already running as root. +if [ "$(id -u)" = "0" ]; then + SUDO="" +else + SUDO="sudo" +fi +$SUDO pacman -Syq --needed --noconfirm $PACKAGES + +. $(dirname "$(realpath "$0")")/properties.sh +$SUDO mkdir -p $TERMUX_PREFIX +$SUDO chown -R $(whoami) /data + +echo "Please also install ncurses5-compat-libs and makedepend packages from the AUR before continuing" diff --git a/scripts/setup-offline-bundle.sh b/scripts/setup-offline-bundle.sh new file mode 100755 index 000000000..160dfc150 --- /dev/null +++ b/scripts/setup-offline-bundle.sh @@ -0,0 +1,112 @@ +#!/usr/bin/env bash +## +## Download all package sources and install all build tools whether possible, +## so they will be available offline. +## + +set -e -u + +if [ "$(uname -o)" = "Android" ] || [ "$(uname -m)" != "x86_64" ]; then + echo "This script supports only x86_64 GNU/Linux systems." + exit 1 +fi + +export TERMUX_SCRIPTDIR="$(dirname "$(readlink -f "$0")")/../" +mkdir -p "$TERMUX_SCRIPTDIR"/build-tools + +export TERMUX_PACKAGES_OFFLINE=true +export TERMUX_ARCH=aarch64 +export TERMUX_ON_DEVICE_BUILD=false +export TERMUX_PKG_TMPDIR=$TERMUX_SCRIPTDIR/build-tools/_tmp +export TERMUX_COMMON_CACHEDIR=$TERMUX_PKG_TMPDIR +export CC=gcc CXX=g++ LD=ld AR=ar STRIP=strip PKG_CONFIG=pkg-config +export CPPFLAGS="" CFLAGS="" CXXFLAGS="" LDFLAGS="" +mkdir -p "$TERMUX_PKG_TMPDIR" + +# Build tools. +. "$TERMUX_SCRIPTDIR"/scripts/build/termux_download.sh +(. "$TERMUX_SCRIPTDIR"/scripts/build/setup/termux_setup_cmake.sh + termux_setup_cmake +) +# GHC fails. Skipping for now. +#(. "$TERMUX_SCRIPTDIR"/scripts/build/setup/termux_setup_ghc.sh +# termux_setup_ghc +#) +(. "$TERMUX_SCRIPTDIR"/scripts/build/setup/termux_setup_golang.sh + termux_setup_golang +) +( + . "$TERMUX_SCRIPTDIR"/scripts/build/setup/termux_setup_ninja.sh + . "$TERMUX_SCRIPTDIR"/scripts/build/setup/termux_setup_meson.sh + termux_setup_meson +) +(. "$TERMUX_SCRIPTDIR"/scripts/build/setup/termux_setup_protobuf.sh + termux_setup_protobuf +) +(. "$TERMUX_SCRIPTDIR"/scripts/build/setup/termux_setup_python_crossenv.sh + termux_setup_python_crossenv +) +# Offline rust is not supported yet. +#(. "$TERMUX_SCRIPTDIR"/scripts/build/setup/termux_setup_rust.sh +# termux_setup_rust +#) +(. "$TERMUX_SCRIPTDIR"/scripts/build/setup/termux_setup_swift.sh + termux_setup_swift +) +(. "$TERMUX_SCRIPTDIR"/scripts/build/setup/termux_setup_zig.sh + termux_setup_zig +) +rm -rf "${TERMUX_PKG_TMPDIR}" +(test -d "$TERMUX_SCRIPTDIR"/build-tools/android-sdk && test -d "$TERMUX_SCRIPTDIR"/build-tools/android-ndk && exit 0 + "$TERMUX_SCRIPTDIR"/scripts/setup-android-sdk.sh +) + +# Package sources. +for repo_path in $(jq --raw-output 'keys | .[]' $TERMUX_SCRIPTDIR/repo.json); do + for p in "$TERMUX_SCRIPTDIR"/$repo_path/*; do + ( + . "$TERMUX_SCRIPTDIR"/scripts/properties.sh + . "$TERMUX_SCRIPTDIR"/scripts/build/get_source/termux_step_get_source.sh + . "$TERMUX_SCRIPTDIR"/scripts/build/get_source/termux_git_clone_src.sh + . "$TERMUX_SCRIPTDIR"/scripts/build/get_source/termux_download_src_archive.sh + . "$TERMUX_SCRIPTDIR"/scripts/build/get_source/termux_unpack_src_archive.sh + + # Disable archive extraction in termux_step_get_source.sh. + termux_extract_src_archive() { + : + } + + TERMUX_PKG_NAME=$(basename "$p") + TERMUX_PKG_BUILDER_DIR="${p}" + TERMUX_PKG_CACHEDIR="${p}/cache" + TERMUX_PKG_METAPACKAGE=false + + # Set some variables to dummy values to avoid errors. + TERMUX_PKG_TMPDIR="${TERMUX_PKG_CACHEDIR}/.tmp" + TERMUX_PKG_SRCDIR="${TERMUX_PKG_CACHEDIR}/.src" + TERMUX_PKG_BUILDDIR="$TERMUX_PKG_SRCDIR" + TERMUX_PKG_HOSTBUILD_DIR=$TERMUX_PKG_TMPDIR + TERMUX_HOST_PLATFORM=aarch64-linux-android + TERMUX_ARCH_BITS=64 + TERMUX_BUILD_TUPLE=x86_64-pc-linux-gnu + TERMUX_PKG_GIT_BRANCH="" + TERMUX_DEBUG_BUILD=false + TERMUX_MAKE_PROCESSES=1 + + mkdir -p "$TERMUX_PKG_CACHEDIR" "$TERMUX_PKG_TMPDIR" "$TERMUX_PKG_SRCDIR" + cd "$TERMUX_PKG_CACHEDIR" + + . "${p}"/build.sh || true + if ! ${TERMUX_PKG_METAPACKAGE}; then + echo "Downloading sources for '$TERMUX_PKG_NAME'..." + termux_step_get_source + + # Delete dummy src and tmp directories. + rm -rf "$TERMUX_PKG_TMPDIR" "$TERMUX_PKG_SRCDIR" + fi + ) + done +done + +# Mark to tell build-package.sh to enable offline mode. +touch "$TERMUX_SCRIPTDIR"/build-tools/.installed diff --git a/scripts/setup-termux.sh b/scripts/setup-termux.sh new file mode 100755 index 000000000..98be071f3 --- /dev/null +++ b/scripts/setup-termux.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +PACKAGES="" +# Tier 1: requirements for the core build scripts in scripts/build/. +PACKAGES+=" clang" # Required for termux-elf-cleaner and C/C++ packages. +PACKAGES+=" file" # Used in termux_step_massage(). +PACKAGES+=" gnupg" # Used in termux_get_repo_files() and build-package.sh. +PACKAGES+=" lzip" # Used by tar to extract *.tar.lz source archives. +PACKAGES+=" patch" # Used for applying patches on source code. +PACKAGES+=" python" # Used buildorder.py core script. +PACKAGES+=" unzip" # Used to extract *.zip source archives. +PACKAGES+=" jq" # Used for parsing repo.json. +PACKAGES+=" binutils-is-llvm" # Used for checking symbols. + +# Tier 2: requirements for building many other packages. +PACKAGES+=" asciidoc" +PACKAGES+=" asciidoctor" +PACKAGES+=" autoconf" +PACKAGES+=" automake" +PACKAGES+=" bc" +PACKAGES+=" bison" +PACKAGES+=" cmake" +PACKAGES+=" ed" +PACKAGES+=" flex" +PACKAGES+=" gettext" +PACKAGES+=" git" +PACKAGES+=" golang" +PACKAGES+=" gperf" +PACKAGES+=" help2man" +PACKAGES+=" libtool" +PACKAGES+=" m4" +PACKAGES+=" make" # Used for all Makefile-based projects. +PACKAGES+=" ninja" # Used by default to build all CMake projects. +PACKAGES+=" perl" +PACKAGES+=" pkg-config" +PACKAGES+=" protobuf" +PACKAGES+=" python2" +PACKAGES+=" rust" +PACKAGES+=" texinfo" +PACKAGES+=" valac" + +apt update +apt dist-upgrade -y +apt install -y $PACKAGES diff --git a/scripts/setup-ubuntu.sh b/scripts/setup-ubuntu.sh new file mode 100755 index 000000000..887fe242d --- /dev/null +++ b/scripts/setup-ubuntu.sh @@ -0,0 +1,276 @@ +#!/usr/bin/env bash +set -e -u + +PACKAGES="" + +# For en_US.UTF-8 locale. +PACKAGES+=" locales" + +# To provide /usr/bin/python as symlink to /usr/bin/python3 +PACKAGES+=" python-is-python3" + +# Used by build-package.sh and CI/CD scripts. +PACKAGES+=" curl" +PACKAGES+=" gnupg" + +# Used for fetching package sources from Git repositories. +PACKAGES+=" git" + +# Used for extracting package sources. +PACKAGES+=" lzip" +PACKAGES+=" tar" +PACKAGES+=" unzip" + +# Used by common build systems. +PACKAGES+=" autoconf" +PACKAGES+=" autogen" +PACKAGES+=" automake" +PACKAGES+=" autopoint" +PACKAGES+=" bison" +PACKAGES+=" flex" +PACKAGES+=" g++" +PACKAGES+=" g++-multilib" +PACKAGES+=" gawk" +PACKAGES+=" gettext" +PACKAGES+=" gperf" +PACKAGES+=" intltool" +PACKAGES+=" libglib2.0-dev" +PACKAGES+=" libltdl-dev" +PACKAGES+=" libtool-bin" +PACKAGES+=" m4" +PACKAGES+=" pkg-config" +PACKAGES+=" scons" + +# Used to generate package documentation. +PACKAGES+=" asciidoc" +PACKAGES+=" asciidoctor" +PACKAGES+=" groff" +PACKAGES+=" help2man" +PACKAGES+=" pandoc" +PACKAGES+=" python3-docutils" +PACKAGES+=" python3-recommonmark" +PACKAGES+=" python3-sphinx" +PACKAGES+=" scdoc" +PACKAGES+=" texinfo" +PACKAGES+=" xmlto" +PACKAGES+=" xmltoman" + +# Needed by python modules (e.g. asciinema) and some build systems. +PACKAGES+=" python3.9" +PACKAGES+=" python3.10" +PACKAGES+=" python3-pip" +PACKAGES+=" python3-setuptools" +PACKAGES+=" python3.10-venv" + +# Needed by package bc. +PACKAGES+=" ed" + +# Needed by gnunet. +PACKAGES+=" recutils" + +# Provides utility hexdump which is needed by package bitcoin. +PACKAGES+=" bsdmainutils" + +# Needed by package seafile-client. +PACKAGES+=" valac" + +# Needed by package libgcrypt. +PACKAGES+=" fig2dev" + +# Needed by package gimp. +PACKAGES+=" gegl" + +# Needed by package libidn2. +PACKAGES+=" gengetopt" + +# Needed by package proxmark3-git. +PACKAGES+=" swig" + +# Needed by package dbus-glib. +PACKAGES+=" libdbus-1-dev" + +# Needed by package below. +PACKAGES+=" libelf-dev" + +# Needed by package ghostscript. +PACKAGES+=" libexpat1-dev" +PACKAGES+=" libjpeg-dev" + +# Needed by package news-flash-gtk. +PACKAGES+=" libsqlite3-dev" + +# Needed by package vlc. +PACKAGES+=" lua5.2" + +# Needed by package luarocks. +PACKAGES+=" lua5.3" + +# Used bt host build of package mariadb. +PACKAGES+=" libncurses5-dev" + +# Needed by packages mkvtoolnix and ruby. +PACKAGES+=" ruby" + +# Needed by host build of package nodejs. +PACKAGES+=" libc-ares-dev" +PACKAGES+=" libicu-dev" + +# Needed by php. +PACKAGES+=" re2c" + +# Needed by composer. +PACKAGES+=" php" +PACKAGES+=" composer" + +# Needed by package rust. +PACKAGES+=" libssl-dev" # Needed to build Rust +PACKAGES+=" llvm-12-dev" +PACKAGES+=" llvm-12-tools" +PACKAGES+=" clang-12" + +# Needed for package smalltalk. +PACKAGES+=" libsigsegv-dev" +PACKAGES+=" zip" + +# Needed for package sqlcipher. +PACKAGES+=" tcl" + +# Needed by package swi-prolog. +PACKAGES+=" openssl" +PACKAGES+=" zlib1g-dev" +PACKAGES+=" libssl-dev:i386" +PACKAGES+=" zlib1g-dev:i386" + +# For swift. +PACKAGES+=" lld" +PACKAGES+=" patchelf" + +# Needed by wrk. +PACKAGES+=" luajit" + +# Needed by libduktape +PACKAGES+=" bc" + +# Java. +PACKAGES+=" openjdk-8-jdk openjdk-16-jdk" + +# needed by ovmf +PACKAGES+=" libarchive-tools" + +# Needed by cavif-rs +PACKAGES+=" nasm" + +# Needed by dgsh +PACKAGES+=" rsync" + +# Needed by megacmd +PACKAGES+=" wget" + +# Needed by packages in unstable repository. +PACKAGES+=" comerr-dev" +PACKAGES+=" docbook-to-man" +PACKAGES+=" docbook-utils" +PACKAGES+=" erlang-nox" +PACKAGES+=" heimdal-multidev" +PACKAGES+=" libconfig-dev" +PACKAGES+=" libevent-dev" +PACKAGES+=" libgc-dev" +PACKAGES+=" libgmp-dev" +PACKAGES+=" libjansson-dev" +PACKAGES+=" libparse-yapp-perl" +PACKAGES+=" libreadline-dev" +PACKAGES+=" libunistring-dev" +PACKAGES+=" llvm-12-dev" +PACKAGES+=" llvm-12-tools" + +# Needed by packages in X11 repository. +PACKAGES+=" alex" +PACKAGES+=" docbook-xsl-ns" +PACKAGES+=" gnome-common" +PACKAGES+=" gobject-introspection" +PACKAGES+=" gtk-3-examples" +PACKAGES+=" gtk-doc-tools" +PACKAGES+=" happy" +PACKAGES+=" itstool" +PACKAGES+=" libdbus-glib-1-dev-bin" +PACKAGES+=" libgdk-pixbuf2.0-dev" +PACKAGES+=" libwayland-dev" +PACKAGES+=" python-setuptools" +PACKAGES+=" python3-xcbgen" +PACKAGES+=" sassc" +PACKAGES+=" texlive-extra-utils" +PACKAGES+=" wayland-scanner++" +PACKAGES+=" xfce4-dev-tools" +PACKAGES+=" xfonts-utils" +PACKAGES+=" xutils-dev" + +# Needed by packages in science repository +PACKAGES+=" protobuf-c-compiler" +PACKAGES+=" sqlite3" + +# Needed by packages in game repository +PACKAGES+=" cvs" +PACKAGES+=" python3-yaml" + +# Needed by apt. +PACKAGES+=" triehash" + +# Needed by aspell dictionaries. +PACKAGES+=" aspell" + +# Needed by package kphp. +PACKAGES+=" python3-jsonschema" + +# Needed by package lilypond. +PACKAGES+=" fontforge-nox" +PACKAGES+=" guile-2.2" +PACKAGES+=" python3-fontforge" +PACKAGES+=" texlive-metapost" + +# Needed by proxmark3/proxmark3-git +PACKAGES+=" gcc-arm-none-eabi" + +# Needed by pypy +PACKAGES+=" qemu-user-static" + +# For opt, llvm-link, llc not shipped by NDK. +# Required by picolisp (and maybe a few others in future) +PACKAGES+=" llvm-12" + +# Required by cava +PACKAGES+=" xxd" + +# Required by samba +PACKAGES+=" libjson-perl" + +# Required for parsing repo.json +PACKAGES+=" jq" + +# Required by txikijs's hostbuild step +PACKAGES+=" libcurl4-openssl-dev" + +# Do not require sudo if already running as root. +if [ "$(id -u)" = "0" ]; then + SUDO="" +else + SUDO="sudo" +fi + +# Allow 32-bit packages. +$SUDO dpkg --add-architecture i386 +$SUDO apt-get -yq update + +$SUDO env DEBIAN_FRONTEND=noninteractive \ + apt-get install -yq --no-install-recommends $PACKAGES + +# Pip for python2. +curl -L --output /tmp/py2-get-pip.py https://bootstrap.pypa.io/pip/2.7/get-pip.py +$SUDO python2 /tmp/py2-get-pip.py +rm -f /tmp/py2-get-pip.py + +$SUDO locale-gen --purge en_US.UTF-8 +echo -e 'LANG="en_US.UTF-8"\nLANGUAGE="en_US:en"\n' | $SUDO tee -a /etc/default/locale + +. $(dirname "$(realpath "$0")")/properties.sh +$SUDO mkdir -p $TERMUX_PREFIX +$SUDO chown -R $(whoami) /data diff --git a/scripts/test-runner.sh b/scripts/test-runner.sh new file mode 100755 index 000000000..85a9cda0f --- /dev/null +++ b/scripts/test-runner.sh @@ -0,0 +1,42 @@ +#!/data/data/com.termux/files/usr/bin/bash + +if [ $# != 1 ]; then + echo "Specify package to run tests for as only argument" + exit 1 +fi + +PACKAGE=$1 +TEST_DIR=packages/$PACKAGE/tests + +if [ ! -d $TEST_DIR ]; then + echo "ERROR: No tests folder for package $PACKAGE" + exit 1 +fi + +NUM_TESTS=0 +NUM_FAILURES=0 + +for TEST_SCRIPT in $TEST_DIR/*; do + test -t 1 && printf "\033[32m" + echo "Running test ${TEST_SCRIPT}..." + (( NUM_TESTS += 1 )) + test -t 1 && printf "\033[31m" + ( + assert_equals() { + FIRST=$1 + SECOND=$2 + if [ "$FIRST" != "$SECOND" ]; then + echo "assertion failed - expected '$FIRST', got '$SECOND'" + exit 1 + fi + } + set -e -u + . $TEST_SCRIPT + ) + if [ $? != 0 ]; then + (( NUM_FAILURES += 1 )) + fi + test -t 1 && printf "\033[0m" +done + +echo "$NUM_TESTS tests run - $NUM_FAILURES failure(s)" diff --git a/scripts/update-docker.ps1 b/scripts/update-docker.ps1 new file mode 100644 index 000000000..c1bae77c3 --- /dev/null +++ b/scripts/update-docker.ps1 @@ -0,0 +1,21 @@ +# PowerShell script to update Termux Package Builder Docker Image +# +# Usage example: +# +# .\scripts\update-docker.ps1 + +Set-Variable -Name CONTAINER -Value "termux-package-builder" +Set-Variable -Name IMAGE -Value "termux/package-builder" + +docker pull $IMAGE + +Set-Variable -Name LATEST -Value (docker inspect --format "{{.Id}}" $IMAGE) +Set-Variable -Name RUNNING -Value (docker inspect --format "{{.Image}}" $CONTAINER) + +if ($LATEST -eq $RUNNING) { + Write-Output "Image '$IMAGE' used in the container '$CONTAINER' is already up to date" +} else { + Write-Output "Image '$IMAGE' used in the container '$CONTAINER' has been updated - removing the outdated container" + docker stop $CONTAINER + docker rm -f $CONTAINER +} diff --git a/scripts/update-docker.sh b/scripts/update-docker.sh new file mode 100755 index 000000000..0244274dd --- /dev/null +++ b/scripts/update-docker.sh @@ -0,0 +1,19 @@ +#!/bin/sh +set -e -u + +CONTAINER=termux-package-builder +IMAGE=termux/package-builder + +docker pull $IMAGE + +LATEST=$(docker inspect --format "{{.Id}}" $IMAGE) +RUNNING=$(docker inspect --format "{{.Image}}" $CONTAINER) + +if [ $LATEST = $RUNNING ]; then + echo "Image '$IMAGE' used in the container '$CONTAINER' is already up to date" +else + echo "Image '$IMAGE' used in the container '$CONTAINER' has been updated - removing the outdated container" + docker stop $CONTAINER + docker rm -f $CONTAINER +fi + diff --git a/scripts/updates/api/dump-repology-data b/scripts/updates/api/dump-repology-data new file mode 100755 index 000000000..b8dc0c8e4 --- /dev/null +++ b/scripts/updates/api/dump-repology-data @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 + +# The MIT License (MIT) + +# Copyright (c) 2022 Aditya Alok (aka. @MrAdityaAlok) + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +from requests import get as requests_get + + +def get_repology_data(last_project): + repology_data = requests_get( + f"https://repology.org/api/v1/projects/{last_project}?inrepo=termux&outdated=True&families_newest=2-" + ).json() # NOTE: We are using 2- so that api will return a package as outdated if it is so in 2 or more + # repo family. This helps us avoid false positives. + + return repology_data + + +def get_outdated_packages(): + termux_outdated_packages = {} + last_project = "" + + while True: + repology_data = get_repology_data(last_project) + last_project = sorted(repology_data.keys())[ + -1 + ] # This used to query repology for next set of packages. + # Quoting repology documentation: "You may iterate through + # all projects by using the last project name in the next request" + # For more info, visit https://repology.org/api + # NOTE: next response to request will include the last_project given. + if len(repology_data) <= 1: + # Break the loop now. Since api returned only one package, it + # must be the last_project, which was already included in previous iteration. + break + + for package_name, package_data in repology_data.items(): + if package_name in termux_outdated_packages: + # Skip if package is already in the dict. + continue + newest_stable = None + newest_devel = None + for repo_data in package_data: + if repo_data.get("status", "") == "newest": + newest_stable = repo_data["version"] + # If we found stable version, break the loop. + break + elif repo_data.get("status", "") == "devel": + # Do not break the loop if we found devel version as there may be stable version later. + newest_devel = repo_data["version"] + + if newest_stable: + termux_outdated_packages[package_name] = newest_stable + elif newest_devel: + termux_outdated_packages[package_name] = newest_devel + else: + # If we don't find any version, skip the package. + continue + + return termux_outdated_packages + + +if __name__ == "__main__": + import json + import sys + + try: + output_file = sys.argv[1] + except IndexError: + sys.exit("Please provide an output file") + + with open(output_file, "w") as f: + json.dump(get_outdated_packages(), f) diff --git a/scripts/updates/api/termux_github_api_get_tag.sh b/scripts/updates/api/termux_github_api_get_tag.sh new file mode 100644 index 000000000..9a36ea8fb --- /dev/null +++ b/scripts/updates/api/termux_github_api_get_tag.sh @@ -0,0 +1,135 @@ +# shellcheck shell=bash +termux_github_api_get_tag() { + if [[ -z "$1" ]]; then + termux_error_exit <<-EndOfUsage + Usage: ${FUNCNAME[0]} PKG_SRCURL [TAG_TYPE] + Returns the latest tag of the given package. + EndOfUsage + fi + + if [[ -z "${GITHUB_TOKEN:-}" ]]; then + # Needed to use graphql API. + termux_error_exit "ERROR: GITHUB_TOKEN environment variable not set." + fi + + local PKG_SRCURL="$1" + local TAG_TYPE="${2:-}" + + local project + project="$(echo "${PKG_SRCURL}" | cut -d'/' -f4-5)" + project="${project%.git}" + + if [[ -z "${TAG_TYPE}" ]]; then # If not set, then decide on the basis of url. + if [[ "${PKG_SRCURL: -4}" == ".git" ]]; then + # Get newest tag. + TAG_TYPE="newest-tag" + else + # Get the latest release tag. + TAG_TYPE="latest-release-tag" + fi + fi + + local jq_filter + local api_url="https://api.github.com" + local -a curl_opts=( + --silent + --location + --retry 10 + --retry-delay 1 + -H "Authorization: token ${GITHUB_TOKEN}" + -H "Accept: application/vnd.github.v3+json" + --write-out '|%{http_code}' + ) + + if [[ "${TAG_TYPE}" == "newest-tag" ]]; then + api_url="${api_url}/graphql" + jq_filter='.data.repository.refs.edges[0].node.name' + curl_opts+=(-X POST) + curl_opts+=( + -d "$( + cat <<-EOF | tr '\n' ' ' + { + "query": "query { + repository(owner: \"${project%/*}\", name: \"${project##*/}\") { + refs(refPrefix: \"refs/tags/\", first: 1, orderBy: { + field: TAG_COMMIT_DATE, direction: DESC + }) + { + edges { + node { + name + } + } + } + } + }" + } + EOF + )" + ) + + elif [[ "${TAG_TYPE}" == "latest-release-tag" ]]; then + api_url="${api_url}/repos/${project}/releases/latest" + jq_filter=".tag_name" + else + termux_error_exit <<-EndOfError + ERROR: Invalid TAG_TYPE: '${TAG_TYPE}'. + Allowed values: 'newest-tag', 'latest-release-tag'. + EndOfError + fi + + local response + response="$(curl "${curl_opts[@]}" "${api_url}")" + + local http_code + http_code="${response##*|}" + # Why printf "%s\n"? Because echo interpolates control characters, which jq does not like. + response="$(printf "%s\n" "${response%|*}")" + + local tag_name + if [[ "${http_code}" == "200" ]]; then + if jq --exit-status --raw-output "${jq_filter}" <<<"${response}" >/dev/null; then + tag_name="$(jq --exit-status --raw-output "${jq_filter}" <<<"${response}")" + else + termux_error_exit "ERROR: Failed to parse tag name from: '${response}'" + fi + elif [[ "${http_code}" == "404" ]]; then + if jq --exit-status "has(\"message\") and .message == \"Not Found\"" <<<"${response}"; then + termux_error_exit <<-EndOfError + ERROR: No '${TAG_TYPE}' found (${api_url}). + Try using '$( + if [ ${TAG_TYPE} = "newest-tag" ]; then + echo "latest-release-tag" + else + echo "newest-tag" + fi + )'. + EndOfError + else + termux_error_exit <<-EndOfError + ERROR: Failed to get '${TAG_TYPE}'(${api_url})'. + Response: + ${response} + EndOfError + fi + else + termux_error_exit <<-EndOfError + ERROR: Failed to get '${TAG_TYPE}'(${api_url})'. + HTTP code: ${http_code} + Response: + ${response} + EndOfError + fi + + # If program control reached here and still no tag_name, then something went wrong. + if [[ -z "${tag_name:-}" ]] || [[ "${tag_name}" == "null" ]]; then + termux_error_exit <<-EndOfError + ERROR: JQ could not find '${TAG_TYPE}'(${api_url})'. + Response: + ${response} + Please report this as bug. + EndOfError + fi + + echo "${tag_name#v}" # Remove leading 'v' which is common in version tag. +} diff --git a/scripts/updates/api/termux_gitlab_api_get_tag.sh b/scripts/updates/api/termux_gitlab_api_get_tag.sh new file mode 100644 index 000000000..6a4b5c24b --- /dev/null +++ b/scripts/updates/api/termux_gitlab_api_get_tag.sh @@ -0,0 +1,112 @@ +# shellcheck shell=bash +termux_gitlab_api_get_tag() { + if [[ -z "$1" ]]; then + termux_error_exit <<-EndOfUsage + Usage: ${FUNCNAME[0]} PKG_SRCURL [TAG_TYPE] [API_HOST] + Returns the latest tag of the given package. + EndOfUsage + + fi + local PKG_SRCURL="$1" + local TAG_TYPE="${2:-}" + local API_HOST="${3:-gitlab.com}" + + local project + project="$(echo "${PKG_SRCURL}" | cut -d'/' -f4-5)" + project="${project%.git}" + + if [[ -z "${TAG_TYPE}" ]]; then # If not set, then decide on the basis of url. + if [[ "${PKG_SRCURL: -4}" == ".git" ]]; then + # Get newest tag. + TAG_TYPE="newest-tag" + else + # Get the latest release tag. + TAG_TYPE="latest-release-tag" + fi + fi + + local jq_filter + local api_path + + case "${TAG_TYPE}" in + latest-release-tag) + api_path="/releases" + jq_filter=".[0].tag_name" + ;; + newest-tag) + api_path="/repository/tags" + jq_filter=".[0].name" + ;; + *) + termux_error_exit <<-EndOfError + ERROR: Invalid TAG_TYPE: '${TAG_TYPE}'. + Allowed values: 'newest-tag', 'latest-release-tag'. + EndOfError + ;; + esac + + # Replace slash '/' with '%2F' in project name. It is required for Gitlab API. + local api_url="https://${API_HOST}/api/v4/projects/${project//\//%2F}${api_path}" + # Api can be accessed without authentication if the repository is publicly accessible. + # Default rate limit for gitlab.com is 300 requests per minute for unauthenticated users + # and non-protected paths which should be enough for most use cases. + # see: https://docs.gitlab.com/ee/user/gitlab_com/index.html#gitlabcom-specific-rate-limits + local response + response="$( + curl --silent --location --retry 10 --retry-delay 1 \ + --write-out '|%{http_code}' \ + "${api_url}" + )" + + local http_code + http_code="${response##*|}" + # Why printf "%s\n"? Because echo interpolates control characters, which jq does not like. + response="$(printf "%s\n" "${response%|*}")" + + local tag_name + if [[ "${http_code}" == "200" ]]; then + if jq --exit-status --raw-output "${jq_filter}" <<<"${response}" >/dev/null; then + tag_name="$(jq --exit-status --raw-output "${jq_filter}" <<<"${response}")" + else + termux_error_exit "ERROR: Failed to parse tag name from: '${response}'" + fi + elif [[ "${http_code}" == "404" ]]; then + if jq --exit-status "has(\"message\") and .message == \"Not Found\"" <<<"${response}"; then + termux_error_exit <<-EndOfError + ERROR: No '${TAG_TYPE}' found. (${api_url}) + Try using '$( + if [ ${TAG_TYPE} = "newest-tag" ]; then + echo "latest-release-tag" + else + echo "newest-tag" + fi + )'. + EndOfError + else + termux_error_exit <<-EndOfError + ERROR: Failed to get '${TAG_TYPE}' (${api_url}). + Response: + ${response} + EndOfError + fi + else + termux_error_exit <<-EndOfError + ERROR: Failed to get '${TAG_TYPE}' (${api_url}). + HTTP code: ${http_code} + Response: + ${response} + EndOfError + fi + + # If program control reached here and still no tag_name, then something is not right. + if [[ -z "${tag_name:-}" ]] || [[ "${tag_name}" == "null" ]]; then + termux_error_exit <<-EndOfError + ERROR: JQ could not find '${TAG_TYPE}' (${api_url}). + Response: + ${response} + Please report this as bug. + EndOfError + fi + + echo "${tag_name#v}" # Strip leading 'v'. +} diff --git a/scripts/updates/api/termux_repology_api_get_latest_version.sh b/scripts/updates/api/termux_repology_api_get_latest_version.sh new file mode 100644 index 000000000..fd841baa5 --- /dev/null +++ b/scripts/updates/api/termux_repology_api_get_latest_version.sh @@ -0,0 +1,29 @@ +# shellcheck shell=bash + +# NOTE: Repology sometimes returns "1.0-1" as the latest version even if "1.0" is latest. +# This happens when any of the repositories tracked by repology has specified +# "1.0-1" as the latest. +# +# For example: +# latest lua:lpeg version (as of 2021-11-20T12:21:31) is "1.0.2" but MacPorts specifies as "1.0.2-1". +# Hence repology returns "1.0.2-1" as the latest. +# +# But hopefully, all this can be avoided if TERMUX_PKG_UPDATE_VERSION_REGEXP is set. +# +termux_repology_api_get_latest_version() { + if [[ -z "$1" ]]; then + termux_error_exit "Usage: ${FUNCNAME[0]} PKG_NAME" + fi + + if [[ ! -s "${TERMUX_REPOLOGY_DATA_FILE}" ]]; then + pip3 install bs4 requests >/dev/null # Install python dependencies. + python3 "${TERMUX_SCRIPTDIR}"/scripts/updates/api/dump-repology-data \ + "${TERMUX_REPOLOGY_DATA_FILE}" >/dev/null + fi + + local PKG_NAME="$1" + local version + # Why `--arg`? See: https://stackoverflow.com/a/54674832/15086226 + version="$(jq -r --arg packageName "$PKG_NAME" '.[$packageName]' <"${TERMUX_REPOLOGY_DATA_FILE}")" + echo "${version#v}" +} diff --git a/scripts/updates/internal/termux_github_auto_update.sh b/scripts/updates/internal/termux_github_auto_update.sh new file mode 100644 index 000000000..1404c4603 --- /dev/null +++ b/scripts/updates/internal/termux_github_auto_update.sh @@ -0,0 +1,13 @@ +# shellcheck shell=bash +# Default algorithm to use for packages hosted on github.com +termux_github_auto_update() { + local latest_tag + latest_tag="$( + termux_github_api_get_tag "${TERMUX_PKG_SRCURL}" "${TERMUX_PKG_UPDATE_TAG_TYPE}" + )" + + if [[ -z "${latest_tag}" ]]; then + termux_error_exit "ERROR: Unable to get tag from ${TERMUX_PKG_SRCURL}" + fi + termux_pkg_upgrade_version "${latest_tag}" +} diff --git a/scripts/updates/internal/termux_gitlab_auto_update.sh b/scripts/updates/internal/termux_gitlab_auto_update.sh new file mode 100644 index 000000000..0534a0a0a --- /dev/null +++ b/scripts/updates/internal/termux_gitlab_auto_update.sh @@ -0,0 +1,13 @@ +# shellcheck shell=bash +# Default algorithm to use for packages hosted on hosts using gitlab-ci. +termux_gitlab_auto_update() { + local latest_tag + latest_tag="$( + termux_gitlab_api_get_tag \ + "${TERMUX_PKG_SRCURL}" "${TERMUX_PKG_UPDATE_TAG_TYPE}" "${TERMUX_GITLAB_API_HOST}" + )" + if [[ -z "${latest_tag}" ]]; then + termux_error_exit "ERROR: Unable to get tag from ${TERMUX_PKG_SRCURL}" + fi + termux_pkg_upgrade_version "${latest_tag}" +} diff --git a/scripts/updates/internal/termux_repology_auto_update.sh b/scripts/updates/internal/termux_repology_auto_update.sh new file mode 100644 index 000000000..107f2a077 --- /dev/null +++ b/scripts/updates/internal/termux_repology_auto_update.sh @@ -0,0 +1,12 @@ +# shellcheck shell=bash +termux_repology_auto_update() { + local latest_version + latest_version="$(termux_repology_api_get_latest_version "${TERMUX_PKG_NAME}")" + # Repology api returns null if package is not tracked by repology or is already upto date. + if [[ "${latest_version}" == "null" ]]; then + echo "INFO: Already up to date." # Since we exclude unique to termux packages from auto-update, + # this package should be tracked by repology and be already up to date. + return 0 + fi + termux_pkg_upgrade_version "${latest_version}" +} diff --git a/scripts/updates/termux_pkg_auto_update.sh b/scripts/updates/termux_pkg_auto_update.sh new file mode 100644 index 000000000..835da8587 --- /dev/null +++ b/scripts/updates/termux_pkg_auto_update.sh @@ -0,0 +1,44 @@ +# shellcheck shell=bash +termux_pkg_auto_update() { + local project_host + project_host="$(echo "${TERMUX_PKG_SRCURL}" | cut -d"/" -f3)" + + if [[ -z "${TERMUX_PKG_UPDATE_METHOD}" ]]; then + if [[ "${project_host}" == "github.com" ]]; then + TERMUX_PKG_UPDATE_METHOD="github" + elif [[ "${project_host}" == "gitlab.com" ]]; then + TERMUX_PKG_UPDATE_METHOD="gitlab" + else + TERMUX_PKG_UPDATE_METHOD="repology" + fi + fi + + local _err_msg="ERROR: source url's hostname is not ${TERMUX_PKG_UPDATE_METHOD}.com, but has been +configured to use ${TERMUX_PKG_UPDATE_METHOD}'s method." + + case "${TERMUX_PKG_UPDATE_METHOD}" in + github) + if [[ "${project_host}" != "${TERMUX_PKG_UPDATE_METHOD}.com" ]]; then + termux_error_exit "${_err_msg}" + else + termux_github_auto_update + fi + ;; + gitlab) + if [[ "${project_host}" != "${TERMUX_PKG_UPDATE_METHOD}.com" ]]; then + termux_error_exit "${_err_msg}" + else + termux_gitlab_auto_update + fi + ;; + repology) + termux_repology_auto_update + ;; + *) + termux_error_exit <<-EndOfError + ERROR: wrong value '${TERMUX_PKG_UPDATE_METHOD}' for TERMUX_PKG_UPDATE_METHOD. + Can be 'github', 'gitlab' or 'repology' + EndOfError + ;; + esac +} diff --git a/scripts/updates/utils/termux_error_exit.sh b/scripts/updates/utils/termux_error_exit.sh new file mode 100644 index 000000000..28425b6cc --- /dev/null +++ b/scripts/updates/utils/termux_error_exit.sh @@ -0,0 +1,10 @@ +# shellcheck shell=bash +termux_error_exit() { + if [ "$#" -eq 0 ]; then + # Read from stdin. + printf '%s\n' "$(cat)" >&2 + else + printf '%s\n' "$*" >&2 + fi + exit 1 +} diff --git a/scripts/updates/utils/termux_pkg_is_update_needed.sh b/scripts/updates/utils/termux_pkg_is_update_needed.sh new file mode 100755 index 000000000..a70415b1b --- /dev/null +++ b/scripts/updates/utils/termux_pkg_is_update_needed.sh @@ -0,0 +1,65 @@ +#!/bin/bash +termux_pkg_is_update_needed() { + # USAGE: termux_pkg_is_update_needed + if [[ -z "$1" ]] || [[ -z "$2" ]]; then + termux_error_exit "${BASH_SOURCE[0]}: at least 2 arguments expected" + fi + + local CURRENT_VERSION="$1" + local LATEST_VERSION="$2" + + # Compare versions. + # shellcheck disable=SC2091 + if $( + cat <<-EOF | python3 - + import sys + + from pkg_resources import parse_version + + if parse_version("${CURRENT_VERSION}") < parse_version("${LATEST_VERSION}"): + sys.exit(0) + else: + sys.exit(1) + EOF + ); then + return 0 # true. Update needed. + fi + return 1 # false. Update not needed. +} + +# Make it also usable as command line tool. `scripts/bin/apt-compare-versions` is symlinked to this file. +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + declare -f termux_error_exit >/dev/null || + . "$(dirname "$(realpath "${BASH_SOURCE[0]}")")/termux_error_exit.sh" # realpath is used to resolve symlinks. + + if [[ "${1}" == "--help" ]]; then + cat <<-EOF + Usage: $(basename "${BASH_SOURCE[0]}") [--help] ] [version-regex] + --help - show this help message and exit + - first version to compare + - second version to compare + [version-regex] - optional regular expression to filter version numbers from given versions + EOF + fi + + # Print in human readable format. + first_version="$1" + second_version="$2" + version_regexp="${3:-}" + if [[ -n "${version_regexp}" ]]; then + first_version="$(grep -oP "${version_regexp}" <<<"${first_version}")" + second_version="$(grep -oP "${version_regexp}" <<<"${second_version}")" + if [[ -z "${first_version}" ]] || [[ -z "${second_version}" ]]; then + termux_error_exit "ERROR: Unable to parse version numbers using regexp '${version_regexp}'" + fi + fi + if [[ "${first_version}" == "${second_version}" ]]; then + echo "${first_version} = ${second_version}" + else + if termux_pkg_is_update_needed "${first_version}" "${second_version}"; then + echo "${first_version} < ${second_version}" + else + echo "${first_version} > ${second_version}" + fi + fi +fi diff --git a/scripts/updates/utils/termux_pkg_upgrade_version.sh b/scripts/updates/utils/termux_pkg_upgrade_version.sh new file mode 100755 index 000000000..c78a04a71 --- /dev/null +++ b/scripts/updates/utils/termux_pkg_upgrade_version.sh @@ -0,0 +1,99 @@ +# shellcheck shell=bash +termux_pkg_upgrade_version() { + if [[ "$#" -lt 1 ]]; then + termux_error_exit <<-EndUsage + Usage: ${FUNCNAME[0]} LATEST_VERSION [--skip-version-check] + EndUsage + fi + + local LATEST_VERSION="$1" + local SKIP_VERSION_CHECK="${2:-}" + local EPOCH + EPOCH="${TERMUX_PKG_VERSION%%:*}" # If there is no epoch, this will be the full version. + # Check if it isn't the full version and add ':'. + if [[ "${EPOCH}" != "${TERMUX_PKG_VERSION}" ]]; then + EPOCH="${EPOCH}:" + else + EPOCH="" + fi + + # If needed, filter version numbers using regexp. + if [[ -n "${TERMUX_PKG_UPDATE_VERSION_REGEXP}" ]]; then + # Extract version numbers. + LATEST_VERSION="$(grep -oP "${TERMUX_PKG_UPDATE_VERSION_REGEXP}" <<<"${LATEST_VERSION}" || true)" + if [[ -z "${LATEST_VERSION}" ]]; then + termux_error_exit <<-EndOfError + ERROR: failed to filter version numbers using regexp '${TERMUX_PKG_UPDATE_VERSION_REGEXP}'. + Ensure that it is works correctly with ${LATEST_VERSION}. + EndOfError + fi + fi + + # Translate "_" into ".": some packages use underscores to seperate + # version numbers, but we require them to be separated by dots. + LATEST_VERSION="${LATEST_VERSION//_/.}" + + if [[ "${SKIP_VERSION_CHECK}" != "--skip-version-check" ]]; then + if ! termux_pkg_is_update_needed \ + "${TERMUX_PKG_VERSION}" "${EPOCH}${LATEST_VERSION}"; then + echo "INFO: No update needed. Already at version '${LATEST_VERSION}'." + return 0 + fi + fi + + if [[ "${BUILD_PACKAGES}" == "false" ]]; then + echo "INFO: package needs to be updated to ${LATEST_VERSION}." + else + echo "INFO: package being updated to ${LATEST_VERSION}." + + sed -i \ + "s/^\(TERMUX_PKG_VERSION=\)\(.*\)\$/\1\"${EPOCH}${LATEST_VERSION}\"/g" \ + "${TERMUX_PKG_BUILDER_DIR}/build.sh" + sed -i \ + "/TERMUX_PKG_REVISION=/d" \ + "${TERMUX_PKG_BUILDER_DIR}/build.sh" + + # Update checksum + if [[ "${TERMUX_PKG_SHA256[*]}" != "SKIP_CHECKSUM" ]] && [[ "${TERMUX_PKG_SRCURL: -4}" != ".git" ]]; then + echo n | "${TERMUX_SCRIPTDIR}/scripts/bin/update-checksum" "${TERMUX_PKG_NAME}" || { + git checkout -- "${TERMUX_PKG_BUILDER_DIR}" + git pull --rebase + termux_error_exit "ERROR: failed to update checksum." + } + fi + + echo "INFO: Trying to build package." + if "${TERMUX_SCRIPTDIR}/scripts/run-docker.sh" ./build-package.sh -a "${TERMUX_ARCH}" -I "${TERMUX_PKG_NAME}"; then + if [[ "${GIT_COMMIT_PACKAGES}" == "true" ]]; then + echo "INFO: Committing package." + stderr="$( + git add "${TERMUX_PKG_BUILDER_DIR}" 2>&1 >/dev/null + git commit -m "${TERMUX_PKG_NAME}: update to ${LATEST_VERSION}" \ + -m "This commit has been automatically submitted by Github Actions." 2>&1 >/dev/null + )" || { + termux_error_exit <<-EndOfError + ERROR: git commit failed. See below for details. + ${stderr} + EndOfError + } + fi + + if [[ "${GIT_PUSH_PACKAGES}" == "true" ]]; then + echo "INFO: Pushing package." + stderr="$( + git pull --rebase 2>&1 >/dev/null + git push 2>&1 >/dev/null + )" || { + termux_error_exit <<-EndOfError + ERROR: git push failed. See below for details. + ${stderr} + EndOfError + } + fi + else + git checkout -- "${TERMUX_PKG_BUILDER_DIR}" + termux_error_exit "ERROR: failed to build." + fi + + fi +}