diff options
-rwxr-xr-x | gen_compile.sh | 183 | ||||
-rwxr-xr-x | gen_determineargs.sh | 11 | ||||
-rwxr-xr-x | gen_funcs.sh | 217 | ||||
-rwxr-xr-x | gen_worker.sh | 3 | ||||
-rw-r--r-- | worker_modules/gkbuild.sh | 705 |
5 files changed, 1119 insertions, 0 deletions
diff --git a/gen_compile.sh b/gen_compile.sh index 90f5a429..25a5871a 100755 --- a/gen_compile.sh +++ b/gen_compile.sh @@ -1048,3 +1048,186 @@ compile_gpg() { return 0 fi } + +populate_binpkg() { + [[ ${#} -gt 2 ]] \ + && gen_die "$(get_useful_function_stack "${FUNCNAME}")Invalid usage of ${FUNCNAME}(): Function takes at most two arguments (${#} given)!" + + [[ ${#} -lt 1 ]] \ + && gen_die "$(get_useful_function_stack "${FUNCNAME}")Invalid usage of ${FUNCNAME}(): Function takes at least one argument (${#} given)!" + + local PN=${1} + [[ -z "${PN}" ]] \ + && gen_die "$(get_useful_function_stack "${FUNCNAME}")Invalid usage of ${FUNCNAME}(): No package specified!" + + local PV=$(get_gkpkg_version "${PN}") + local P=${PN}-${PV} + + local BINPKG=$(get_gkpkg_binpkg "${PN}") + + local -a GKBUILD_CANDIDATES=( "${GK_SHARE}"/gkbuilds/${P}.gkbuild ) + GKBUILD_CANDIDATES+=( "${GK_SHARE}"/gkbuilds/${PN}.gkbuild ) + + if [[ ${#} -eq 1 ]] + then + local CHECK_LEVEL_CURRENT=0 + local CHECK_LEVEL_PARENT=0 + local CHECK_LEVEL_NEXT=${CHECK_LEVEL_CURRENT} + else + local CHECK_LEVEL_PARENT=${2} + local CHECK_LEVEL_CURRENT=$[${CHECK_LEVEL_PARENT}+1] + local CHECK_LEVEL_NEXT=${CHECK_LEVEL_CURRENT} + fi + + local REQUIRED_BINPKGS_PARENT_VARNAME="CHECK_L${CHECK_LEVEL_PARENT}_REQUIRED_BINPKGS" + local REQUIRED_BINPKGS_CURRENT_VARNAME="CHECK_L${CHECK_LEVEL_CURRENT}_REQUIRED_BINPKGS" + local REQUIRED_BINPKGS_CURRENT_VARNAME_SEPARATE_WORD="${REQUIRED_BINPKGS_CURRENT_VARNAME}[@]" + local REQUIRED_BINPKGS_CURRENT_VARNAME_SINGLE_WORD="${REQUIRED_BINPKGS_CURRENT_VARNAME}[*]" + + # Make sure we start with an empty array just in case ... + eval declare -ga ${REQUIRED_BINPKGS_CURRENT_VARNAME}=\(\) + + local CHECK_LEVEL_PREFIX= + local i=0 + while [[ ${i} < ${CHECK_LEVEL_CURRENT} ]] + do + CHECK_LEVEL_PREFIX="${CHECK_LEVEL_PREFIX% }> " + i=$[${i}+1] + done + unset i + + local -a pkg_deps=( $(get_gkpkg_deps "${PN}") ) + if [[ ${#pkg_deps[@]} -gt 0 ]] + then + print_info 3 "${CHECK_LEVEL_PREFIX}Checking for binpkg(s) required for ${P} (L${CHECK_LEVEL_CURRENT}) ..." + + local pkg_dep= + for pkg_dep in "${pkg_deps[@]}" + do + populate_binpkg ${pkg_dep} ${CHECK_LEVEL_NEXT} + done + unset pkg_dep + else + print_info 3 "${CHECK_LEVEL_PREFIX}${P} has no dependencies. (L${CHECK_LEVEL_CURRENT})" + fi + unset pkg_deps + + if [[ "${PN}" == 'busybox' ]] + then + determine_busybox_config_file + + # Apply config-based tweaks to the busybox config. + # This needs to be done before cache validation. + cp "${BUSYBOX_CONFIG}" "${TEMP}/busybox-config" \ + || gen_die "Failed to copy '${BUSYBOX_CONFIG}' to '${TEMP}/busybox-config'!" + + # If you want mount.nfs to work on older than 2.6.something, you might need to turn this on. + #isTrue "${NFS}" && nfs_opt='y' + local nfs_opt='n' + kconfig_set_opt "${TEMP}/busybox-config" CONFIG_FEATURE_MOUNT_NFS ${nfs_opt} + + # Delete cache if stored config's MD5 does not match one to be used + # This exactly just the .config.gk_orig file, and compares it again the + # current .config. + if [[ -f "${BINPKG}" ]] + then + local oldconfig_md5="$(tar -xaf "${BINPKG}" -O ./configs/.config.gk_orig 2>/dev/null | md5sum)" + local newconfig_md5="$(md5sum < "${TEMP}"/busybox-config)" + if [[ "${oldconfig_md5}" != "${newconfig_md5}" ]] + then + print_info 3 "$(get_indent 2)${PN}: >> Busybox config has changed since binpkg was created; Removing stale ${P} binpkg ..." + rm "${BINPKG}" \ + || gen_die "Failed to remove stale binpkg '${BINPKG}'!" + fi + fi + fi + + if [[ -f "${BINPKG}" ]] + then + local GKBUILD= + for GKBUILD in "${GKBUILD_CANDIDATES[@]}" + do + if [[ ! -f "${GKBUILD}" ]] + then + print_info 3 "${CHECK_LEVEL_PREFIX}GKBUILD '${GKBUILD}' does NOT exist; Skipping ..." + continue + fi + + if [[ "${BINPKG}" -ot "${GKBUILD}" ]] + then + print_info 3 "${CHECK_LEVEL_PREFIX}GKBUILD '${GKBUILD}' is newer than us; Removing stale ${P} binpkg ..." + rm "${BINPKG}" || gen_die "Failed to remove stale binpkg '${BINPKG}'!" + break + fi + + print_info 3 "${CHECK_LEVEL_PREFIX}Existing ${P} binpkg is newer than '${GKBUILD}'; Skipping ..." + done + fi + + if [[ -f "${BINPKG}" ]] + then + local required_binpkg= + for required_binpkg in "${!REQUIRED_BINPKGS_CURRENT_VARNAME_SEPARATE_WORD}" + do + # Create shorter variable value so we do not clutter output + local required_binpkg_filename=$(basename "${required_binpkg}") + + if [[ "${BINPKG}" -ot "${required_binpkg}" ]] + then + print_info 3 "${CHECK_LEVEL_PREFIX}Required binpkg '${required_binpkg_filename}' is newer than us; Removing stale ${P} binpkg ..." + rm "${BINPKG}" || gen_die "Failed to remove stale binpkg '${BINPKG}'!" + break + fi + + print_info 3 "${CHECK_LEVEL_PREFIX}Existing ${P} binpkg is newer than '${required_binpkg_filename}'; Skipping ..." + done + unset required_binpkg REQUIRED_BINPKGS_CURRENT_VARNAME_SEPARATE_WORD required_binpkg_filename + fi + + if [[ -f "${BINPKG}" ]] + then + local patchdir="${GK_SHARE}/patches/${PN}/${PV}" + local patch + for patch in "${patchdir}"/*{diff,patch} + do + [ -f "${patch}" ] || continue + if [[ "${BINPKG}" -ot "${patch}" ]] + then + print_info 3 "${CHECK_LEVEL_PREFIX}Patch '${patch}' is newer than us; Removing stale ${P} binpkg ..." + rm "${BINPKG}" || gen_die "Failed to remove stale binpkg '${BINPKG}'!" + break + fi + + print_info 3 "${CHECK_LEVEL_PREFIX}Existing ${P} binpkg is newer than '${patch}'; Skipping ..." + done + unset patch patchdir + fi + + if [[ ! -f "${BINPKG}" ]] + then + print_info 3 "${CHECK_LEVEL_PREFIX}Binpkg '${BINPKG}' does NOT exist; Need to build ${P} ..." + gkbuild \ + ${PN} \ + ${PV} \ + $(get_gkpkg_srcdir "${PN}") \ + $(get_gkpkg_srctar "${PN}") \ + "${BINPKG}" \ + "${!REQUIRED_BINPKGS_CURRENT_VARNAME_SINGLE_WORD}" + else + print_info 3 "${CHECK_LEVEL_PREFIX}Can keep using existing ${P} binpkg from '${BINPKG}'!" + [[ ${CHECK_LEVEL_CURRENT} -eq 0 ]] && print_info 2 "$(get_indent 2)${PN}: >> Using ${P} binpkg ..." + fi + + if [[ ${CHECK_LEVEL_CURRENT} -eq 0 ]] + then + # Fertig + # REQUIRED_BINPKGS_PARENT_VARNAME + unset CHECK_L${CHECK_LEVEL_PARENT}_REQUIRED_BINPKGS + else + print_info 3 "${CHECK_LEVEL_PREFIX}Binpkg of ${P} is ready; Adding to list '${REQUIRED_BINPKGS_PARENT_VARNAME}' ..." + eval ${REQUIRED_BINPKGS_PARENT_VARNAME}+=\( "${BINPKG}" \) + fi + + # REQUIRED_BINPKGS_CURRENT_VARNAME + unset CHECK_L${CHECK_LEVEL_CURRENT}_REQUIRED_BINPKGS +} diff --git a/gen_determineargs.sh b/gen_determineargs.sh index 187cd66d..9851fae2 100755 --- a/gen_determineargs.sh +++ b/gen_determineargs.sh @@ -295,6 +295,17 @@ determine_real_args() { eval "$v='$(cache_replace "${!v}")'" done + declare -gA GKPKG_LOOKUP_TABLE= + local pn_varname= pn= + for v in "${pkg_prefixes[@]}" + do + pn_varname="${v}_PN" + pn=${!pn_varname} + + GKPKG_LOOKUP_TABLE[${pn}]=${v} + done + unset v pn pn_varname pkg_prefixes + if [ -n "${CMD_BOOTLOADER}" ] then BOOTLOADER="${CMD_BOOTLOADER}" diff --git a/gen_funcs.sh b/gen_funcs.sh index eddaf8ed..b2d24758 100755 --- a/gen_funcs.sh +++ b/gen_funcs.sh @@ -566,6 +566,88 @@ get_chost_libdir() { echo "${libdir}" } +_get_gkpkg_var_value() { + [[ ${#} -ne 2 ]] \ + && gen_die "$(get_useful_function_stack "${FUNCNAME}")Invalid usage of ${FUNCNAME}(): Function takes exactly two arguments (${#} given)!" + + local VARNAME=${1} + case "${VARNAME}" in + BINPKG|DEPS|PN|PV|SRCDIR|SRCTAR) + ;; + *) + # Let's make variable support explicit + gen_die "$(get_useful_function_stack)Variable '${VARNAME}' is not supported by ${FUNCNAME}()!" + ;; + esac + + local PN=${2} + [[ -z "${PN}" ]] \ + && gen_die "$(get_useful_function_stack "${FUNCNAME}")Invalid usage of ${FUNCNAME}(): No package specified!" + + [[ -z "${GKPKG_LOOKUP_TABLE[${PN}]}" ]] \ + && gen_die "$(get_useful_function_stack)Internal error: Package '${PN}' is unknown! Was package added to software.sh?" + + local REQUESTED_VARNAME="${GKPKG_LOOKUP_TABLE[${PN}]}_${VARNAME}" + local REQUESTED_VALUE="${!REQUESTED_VARNAME}" + [[ ${VARNAME} != 'DEPS' && -z "${REQUESTED_VALUE}" ]] \ + && gen_die "$(get_useful_function_stack)Internal error: Variable '${REQUESTED_VARNAME}' is not set!" + + echo "${REQUESTED_VALUE}" +} + +get_gkpkg_binpkg() { + [[ ${#} -ne 1 ]] \ + && gen_die "$(get_useful_function_stack "${FUNCNAME}")Invalid usage of ${FUNCNAME}(): Function takes exactly one argument (${#} given)!" + + local PN=${1} + + _get_gkpkg_var_value BINPKG ${PN} +} + +get_gkpkg_deps() { + [[ ${#} -ne 1 ]] \ + && gen_die "$(get_useful_function_stack "${FUNCNAME}")Invalid usage of ${FUNCNAME}(): Function takes exactly one argument (${#} given)!" + + local PN=${1} + [[ -z "${PN}" ]] \ + && gen_die "$(get_useful_function_stack "${FUNCNAME}")Invalid usage of ${FUNCNAME}(): No package specified!" + + _get_gkpkg_var_value DEPS ${PN} +} + +get_gkpkg_srcdir() { + [[ ${#} -ne 1 ]] \ + && gen_die "$(get_useful_function_stack "${FUNCNAME}")Invalid usage of ${FUNCNAME}(): Function takes exactly one argument (${#} given)!" + + local PN=${1} + [[ -z "${PN}" ]] \ + && gen_die "$(get_useful_function_stack "${FUNCNAME}")Invalid usage of ${FUNCNAME}(): No package specified!" + + _get_gkpkg_var_value SRCDIR ${PN} +} + +get_gkpkg_srctar() { + [[ ${#} -ne 1 ]] \ + && gen_die "$(get_useful_function_stack "${FUNCNAME}")Invalid usage of ${FUNCNAME}(): Function takes exactly one argument (${#} given)!" + + local PN=${1} + [[ -z "${PN}" ]] \ + && gen_die "$(get_useful_function_stack "${FUNCNAME}")Invalid usage of ${FUNCNAME}(): No package specified!" + + _get_gkpkg_var_value SRCTAR ${PN} +} + +get_gkpkg_version() { + [[ ${#} -ne 1 ]] \ + && gen_die "$(get_useful_function_stack "${FUNCNAME}")Invalid usage of ${FUNCNAME}(): Function takes exactly one argument (${#} given)!" + + local PN=${1} + [[ -z "${PN}" ]] \ + && gen_die "$(get_useful_function_stack "${FUNCNAME}")Invalid usage of ${FUNCNAME}(): No package specified!" + + _get_gkpkg_var_value PV ${PN} +} + # @FUNCTION: get_tar_cmd # @USAGE: <ARCHIVE> # @DESCRIPTION: @@ -825,6 +907,141 @@ trap_cleanup() { exit 1 } +# @FUNCTION: gkbuild +# @USAGE: <PKG> <PKG_VERSION> <PKG_SRCDIR> <PKG_SRCTAR> <PKG_BINCACHE> [<PKG_DEPS>] +# @DESCRIPTION: +# Builds a package for genkernel's initramfs, with cross-compile support. +# +# Genkernel's initramfs uses various utilities like Busybox, LVM, +# MDADM, cryptsetup or others. gkbuild() will run an ebuild-like script +# to build such utilities in sandbox environment with cross-compile +# support (requires existing cross-compile toolchain!). +# +# For developers: +# Any package you want to build using gkbuild() must be correctly added to +# ${GK_SHARE}/software.sh file, check_distfiles() and determine_real_args() +# function. +# +# For users: +# Any package you want to add must have set same (initialized!) variables +# like you can see in ${GK_SHARE}/software.sh. +# +# <PKG> Name of the package (as used in ${GK_SHARE}/patches). +# +# <PKG_VERSION> Version of the package. +# +# <PKG_SRCDIR> Source directory when unpacked. +# +# <PKG_SRCTAR> Source file. Only archives supported by `tar -xaf` are +# supported. +# +# <PKG_BINCACHE> File where genkernel will store the package's image. +# +# <PKG_DEPS> Single word string of required package's PKG_BINCACHE. +gkbuild() { + [[ ${#} -lt 5 ]] \ + && gen_die "$(get_useful_function_stack "${FUNCNAME}")Invalid usage of ${FUNCNAME}(): Function takes at least five arguments (${#} given)!" + [[ ${#} -gt 7 ]] \ + && gen_die "$(get_useful_function_stack "${FUNCNAME}")Invalid usage of ${FUNCNAME}(): Function takes at most six arguments (${#} given)!" + + if ! hash sandbox &>/dev/null + then + gen_die "Sandbox not found. Please install sys-apps/sandbox!" + fi + + local PKG=${1} + local VERSION=${2} + local SRCDIR=${3} + local SRCTAR=${4} + local BINPKG=${5} + + if [[ "$#" -eq '6' ]] + then + local DEPS=${6} + else + local DEPS="" + fi + + if [ -z "${PKG}" ] + then + gen_die "$(get_useful_function_stack "${FUNCNAME}")Invalid usage of ${FUNCNAME}(): PKG is not set!" + elif [ -z "${VERSION}" ] + then + gen_die "$(get_useful_function_stack "${FUNCNAME}")Invalid usage of ${FUNCNAME}(): VERSION is not set!" + elif [ -z "${SRCDIR}" ] + then + gen_die "$(get_useful_function_stack "${FUNCNAME}")Invalid usage of ${FUNCNAME}(): SRCDIR is not set!" + elif [ -z "${SRCTAR}" ] + then + gen_die "$(get_useful_function_stack "${FUNCNAME}")Invalid usage of ${FUNCNAME}(): SRCTAR is not set!" + elif [ -z "${BINPKG}" ] + then + gen_die "$(get_useful_function_stack "${FUNCNAME}")Invalid usage of ${FUNCNAME}(): BINPKG is not set!" + fi + + local -a envvars=( + GK_SHARE="${GK_SHARE}" + LOGLEVEL="${LOGLEVEL}" + LOGFILE="${LOGFILE}" + NOCOLOR="${NOCOLOR}" + TEMP="${TEMP}" + SANDBOX_WRITE="${LOGFILE}:${TEMP}" + ) + + envvars+=( + GKPKG_PN="${PKG}" + GKPKG_PV="${VERSION}" + GKPKG_SRCDIR="${SRCDIR}" + GKPKG_SRCTAR="${SRCTAR}" + GKPKG_BINPKG="${BINPKG}" + GKPKG_DEPS="${DEPS}" + ) + + envvars+=( + CFLAGS="${CMD_UTILS_CFLAGS}" + CXXFLAGS="${CMD_UTILS_CFLAGS}" + CBUILD="${CBUILD}" + CHOST="${CHOST}" + AR="$(tc-getAR)" + AS="$(tc-getAS)" + CC="$(tc-getCC)" + CPP="$(tc-getCPP)" + CXX="$(tc-getCXX)" + LD="$(tc-getLD)" + NM="$(tc-getNM)" + MAKE="${CMD_UTILS_MAKE}" + OBJCOPY="$(tc-getOBJCOPY)" + OBJDUMP="$(tc-getOBJDUMP)" + RANLIB="$(tc-getRANLIB)" + STRIP="$(tc-getSTRIP)" + ) + + if [ ${NICE} -ne 0 ] + then + NICEOPTS="nice -n${NICE} " + else + NICEOPTS="" + fi + envvars+=( NICEOPTS="${NICEOPTS}" ) + + envvars+=( MAKEOPTS="${MAKEOPTS}" ) + + # set up gkbuild signal handler + local error_msg="gen_worker.sh aborted: Failed to compile ${PKG}-${VERSION}!" + trap "gen_die \"${error_msg}\"" SIGABRT SIGHUP SIGQUIT SIGINT SIGTERM + + env -i \ + "${envvars[@]}" \ + sandbox "${GK_SHARE}"/gen_worker.sh build 2>&1 + + local RET=$? + + # remove gkbuild signal handler + set_default_gk_trap + + [ ${RET} -ne 0 ] && gen_die "$(get_useful_function_stack)Failed to create binpkg of ${PKG}-${VERSION}!" +} + set_default_gk_trap() { trap trap_cleanup SIGABRT SIGHUP SIGQUIT SIGINT SIGTERM } diff --git a/gen_worker.sh b/gen_worker.sh index 71b221fd..fa0251b2 100755 --- a/gen_worker.sh +++ b/gen_worker.sh @@ -137,6 +137,9 @@ then fi case "${1}" in + build) + MODULE="${GK_SHARE}/worker_modules/gkbuild.sh" + ;; *) die "Unknown module '${1}' specified!" ;; diff --git a/worker_modules/gkbuild.sh b/worker_modules/gkbuild.sh new file mode 100644 index 00000000..20de2633 --- /dev/null +++ b/worker_modules/gkbuild.sh @@ -0,0 +1,705 @@ +#!/bin/bash +# Copyright 1999-2019 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +__module_main() { + _gkbuild_main +} + +# Remove occurrences of strings from variable given in $1 +# Strings removed are matched as globs, so for example +# '-O*' would remove -O1, -O2 etc. +_filter-var() { + local f x var=$1 new=() + shift + + for f in ${!var} ; do + for x in "$@" ; do + # Note this should work with globs like -O* + [[ ${f} == ${x} ]] && continue 2 + done + new+=( "${f}" ) + done + export ${var}="${new[*]}" +} + +_gkbuild_main() { + _initialize + + addwrite "${TEMP}" + + local all_phases="src_unpack src_prepare src_configure + src_compile src_install" + local x + + # Set up the default functions + for x in ${all_phases} ; do + case "${x}" in + src_unpack) + default_src_unpack() { _src_unpack; } + ;; + + src_prepare) + default_src_prepare() { _src_prepare; } + ;; + + src_configure) + default_src_configure() { _src_configure; } + ;; + + src_compile) + default_src_compile() { _src_compile; } + ;; + + src_install) + default_src_install() { _src_install; } + ;; + + *) + eval "default_${x}() { + die \"${x}() has no default function!\" + }" + ;; + esac + + if ! declare -F ${x} >/dev/null && declare -F default_${x} >/dev/null + then + eval "${x}() { default; }" + fi + done + + local current_phase= + for current_phase in ${all_phases} + do + export GKBUILD_PHASE=${current_phase} + + # Make sure default() points to the correct phase + eval "default() { + default_${current_phase} + }" + + case "${current_phase}" in + src_compile) + print_info 2 "$(get_indent 2)${P}: >> Compiling source ..." + ;; + + src_configure) + print_info 2 "$(get_indent 2)${P}: >> Configuring source ..." + declare -ga CONFIGUREOPTS + ;; + + src_install) + print_info 2 "$(get_indent 2)${P}: >> Install to DESTDIR ..." + ;; + + src_prepare) + print_info 2 "$(get_indent 2)${P}: >> Preparing source ..." + ;; + + src_unpack) + print_info 2 "$(get_indent 2)${P}: >> Unpacking source ..." + ;; + esac + + ${current_phase} || die "${P} failed in '${current_phase}' phase!" + + # sanity check + [[ "${current_phase}" == "src_unpack" && ! -d "${S}" ]] \ + && die "The source directory '${S}' does NOT exist!" + done + + # We don't use .la files; Let's get rid of them to avoid problems + # due to invalid paths. + find "${D}" -name '*.la' -type f -delete + + local BINCACHEDIR=$(dirname "${GKPKG_BINPKG}") + addwrite "${BINCACHEDIR}" + + print_info 2 "$(get_indent 2)${P}: >> Creating binpkg ..." + cd "${D}" || die "Failed to chdir to '${D}'!" + + if ! hash scanelf &>/dev/null + then + print_warning 3 "'scanelf' not found; Will not ensure that binpkg will not contain dynamically linked binaries." + else + print_info 5 "Scanning for dynamically linked programs ..." + + # Limiting scan to /{bin,sbin,usr/bin,usr/sbin} will allow us to keep + # dynamically linked libs in binpkg which is sometimes required to build + # other packages. + local -a executable_files_to_scan=() + local executable_file_to_scan= + local executable_file_to_scan_wo_broot= pattern_to_ignore= + while IFS= read -r -u 3 -d $'\0' executable_file_to_scan + do + executable_file_to_scan_wo_broot=${executable_file_to_scan#${D}} + + if [[ -n "${QA_IGNORE_DYNAMICALLY_LINKED_PROGRAM}" ]] + then + local pattern_to_ignore= + for pattern_to_ignore in ${QA_IGNORE_DYNAMICALLY_LINKED_PROGRAM} + do + print_info 5 "Using pattern '${pattern_to_ignore}' ..." + if [[ "${executable_file_to_scan_wo_broot}" =~ ${pattern_to_ignore} ]] + then + print_info 5 "Match on '${executable_file_to_scan_wo_broot}'; Will ignore ..." + executable_file_to_scan= + break + else + print_info 5 "No match on '${executable_file_to_scan_wo_broot}'!" + fi + done + else + print_info 5 "QA_IGNORE_DYNAMICALLY_LINKED_PROGRAM is not set; Not checking '${executable_file_to_scan_wo_broot}' for exclusion ..." + fi + + if [[ -n "${executable_file_to_scan}" ]] + then + executable_files_to_scan+=( "${executable_file_to_scan}" ) + fi + done 3< <(find "${D}"/{bin,sbin,usr/bin,usr/sbin} -type f -perm -a+x -print0 2>/dev/null) + IFS="${GK_DEFAULT_IFS}" + unset executable_file_to_scan executable_file_to_scan_wo_broot pattern_to_ignore + + local found_dyn_files= + if [[ -n "${executable_files_to_scan}" ]] + then + found_dyn_files=$(scanelf -E ET_DYN "${executable_files_to_scan[@]}" 2>/dev/null) + fi + + if [[ -n "${found_dyn_files}" ]] + then + print_error 1 "Found the following dynamically linked programs:" + print_error 1 "=================================================================" 1 0 1 + print_error 1 "${found_dyn_files}" 1 0 1 + print_error 1 "=================================================================" 1 0 1 + die "Dynamically linked program(s) found in ${P} image!" + fi + unset found_dyn_files + fi + + tar -caf "${GKPKG_BINPKG}" . \ + || die "Failed to create binpkg of ${P} in '${GKPKG_BINPKG}'!" +} + +_initialize() { + if [[ -z "${GKPKG_PN}" ]] + then + die "Unable to build: GKPKG_PN not set!" + elif [[ -z "${GKPKG_PV}" ]] + then + die "Unable to build '${PN}': GKPKG_PV not set!" + else + declare -gr PN=${GKPKG_PN} + declare -gr PV=${GKPKG_PV} + declare -gr P="${PN}-${PV}" + fi + + if [[ -z "${GKPKG_SRCDIR}" ]] + then + die "Unable to build ${P}: GKPKG_SRCDIR is not set!" + elif [[ -z "${GKPKG_SRCTAR}" ]] + then + die "Unable to build ${P}: GKPKG_SRCTAR is not set!" + elif [[ ! -r "${GKPKG_SRCTAR}" ]] + then + die "Unable to build ${P}: '${GKPKG_SRCTAR}' does NOT exist or is not readable!" + elif [[ -z "${GKPKG_BINPKG}" ]] + then + die "Unable to build ${P}: GKPKG_BINPKG is not set!" + elif ! declare -p GKPKG_DEPS >/dev/null + then + die "Unable to build ${P}: GKPKG_DEPS is not set!" + elif [[ -z "${CBUILD}" ]] + then + die "Unable to build ${P}: CBUILD not set!" + elif [[ -z "${CHOST}" ]] + then + die "Unable to build ${P}: CHOST is not set!" + elif [[ -z "${TEMP}" ]] + then + die "Unable to build ${P}: TEMP is not set!" + fi + + print_info 3 "Trying to determine gkbuild for ${P} ..." + local GKBUILD= f= + local GKBUILD_CANDIDATES=( "${GK_SHARE}/gkbuilds/${P}.gkbuild" ) + GKBUILD_CANDIDATES+=( "${GK_SHARE}/gkbuilds/${PN}.gkbuild" ) + for f in "${GKBUILD_CANDIDATES[@]}" + do + if [[ ! -e "${f}" ]] + then + print_info 3 "'${f}' not found; Skipping ..." + continue + else + print_info 3 "Will use '${f}' to build ${P} ..." + GKBUILD="${f}" + break + fi + done + unset f GKBUILD_CANDIDATES + + if [[ -z "${GKBUILD}" ]] + then + die "Unable to build ${P}: '${GK_SHARE}/gkbuilds/${PN}.gkbuild' does NOT exist!" + fi + + source "${GKBUILD}" \ + || die "Failed to source '${GKBUILD}'!" + + declare -gr WORKDIR=$(mktemp -d -p "${TEMP}" ${PN}.XXXXXXXX 2>/dev/null) + [ -z "${WORKDIR}" ] && die "mktemp failed!" + + declare -gr BROOT="${WORKDIR}/buildroot" + mkdir "${BROOT}" || die "Failed to create '${BROOT}'!" + + declare -gr DESTDIR="${WORKDIR}/image" + mkdir "${DESTDIR}" || die "Failed to create '${DESTDIR}'!" + + declare -gr HOME="${WORKDIR}/home" + mkdir "${HOME}" || die "Failed to create '${HOME}'!" + + # Set up some known variables used in ebuilds for smooth gkbuild + # transition + declare -gr ED=${DESTDIR} + declare -gr D=${DESTDIR} + + local libdir=$(get_chost_libdir) + if [[ "${libdir}" =~ ^/(lib|usr/lib) ]] + then + declare -gr SYSROOT="/" + else + declare -gr SYSROOT="/usr/${CHOST}" + fi + unset libdir + print_info 4 "SYSROOT set to '${SYSROOT}'!" + + declare -gr T="${WORKDIR}/temp" + mkdir "${T}" || die "Failed to create '${T}'!" + + S="${WORKDIR}/${GKPKG_SRCDIR}" + + # Some tools like eltpatch (libtoolize) depend on these variables + export S D + + if [[ -n "${GKPKG_DEPS}" ]] + then + # GKPKG_DEPS is ${ARRAY[*]} value (single word), not ${ARRAY[@]} (separate word)! + GKPKG_DEPS=( ${GKPKG_DEPS} ) + local GKPKG_DEP= + for GKPKG_DEP in "${GKPKG_DEPS[@]}" + do + if [[ ! -r "${GKPKG_DEP}" ]] + then + die "Unable to build ${P}: Required binpkg '${GKPKG_DEP}' does NOT exist or is not readable!" + fi + + print_info 2 "$(get_indent 2)${P}: >> Unpacking required binpkg '${GKPKG_DEP}' ..." + tar -xaf "${GKPKG_DEP}" -C "${BROOT}" \ + || die "Unable to build ${P}: Failed to extract required binpkg '${GKPKG_DEP}' to '${BROOT}'!" + done + unset GKPKG_DEP + + append-cflags -I"${BROOT}"/usr/include + append-cppflags -I"${BROOT}"/usr/include + append-ldflags -L"${BROOT}"/usr/lib + fi + + if [[ ! -d "${BROOT}/usr/bin" ]] + then + mkdir -p "${BROOT}"/usr/bin || die "Failed to create '${BROOT}/usr/bin'!" + fi + + cat >"${BROOT}"/usr/bin/pkg-config-wrapper <<-EOF + #!/bin/sh + + SYSROOT=\$(dirname "\$(dirname "\$(dirname "\$(readlink -fm "\$0")")")") + + # https://git.dereferenced.org/pkgconf/pkgconf/issues/30 + unset PKG_CONFIG_PATH PKG_CONFIG_DIR LIBRARY_PATH + + export PKG_CONFIG_LIBDIR=\${SYSROOT}/usr/lib/pkgconfig + export PKG_CONFIG_SYSROOT_DIR=\${SYSROOT} + + exec pkg-config "\$@" + EOF + + chmod +x "${BROOT}"/usr/bin/pkg-config-wrapper \ + || die "Failed to chmod of '${BROOT}/usr/bin/pkg-config-wrapper'!" + + export PATH="${BROOT}/usr/sbin:${BROOT}/usr/bin:${BROOT}/sbin:${BROOT}/bin:${PATH}" + export PKG_CONFIG="${BROOT}/usr/bin/pkg-config-wrapper" +} + +_src_compile() { + cd "${S}" || die "Failed to chdir to '${S}'!" + + if [ -f Makefile ] || [ -f GNUmakefile ] || [ -f makefile ] + then + gkmake V=1 + fi +} + +_src_configure() { + cd "${S}" || die "Failed to chdir to '${S}'!" + + if [[ -x ${GKCONF_SOURCE:-.}/configure ]] + then + gkconf + fi +} + +_src_install() { + cd "${S}" || die "Failed to chdir to '${S}'!" + + if [ -f Makefile ] || [ -f GNUmakefile ] || [ -f makefile ] + then + gkmake V=1 DESTDIR="${D}" install + fi +} + +_src_prepare() { + cd "${S}" || die "Failed to chdir to '${S}'!" + + # let's try to be smart and run autoreconf only when needed + local want_autoreconf=${WANT_AUTORECONF} + + # by default always run libtoolize + local want_libtoolize=${WANT_LIBTOOLIZE:-yes} + + local patchdir="${GK_SHARE}/patches/${PN}/${PV}" + + uses_autoconf() { + if [[ -f configure.ac || -f configure.in ]] + then + return 0 + fi + + return 1 + } + + at_checksum() { + find '(' -name 'Makefile.am' \ + -o -name 'configure.ac' \ + -o -name 'configure.in' ')' \ + -exec cksum {} + | sort -k2 + } + + if $(uses_autoconf) && ! isTrue "${want_autoreconf}" + then + local checksum=$(at_checksum) + fi + if [[ -d "${patchdir}" ]] + then + local silent="-s " + if [[ "${LOGLEVEL}" -gt 3 ]] + then + silent= + fi + + print_info 2 "$(get_indent 2)${P}: >> Applying patches ..." + local i + for i in "${patchdir}"/*{diff,patch} + do + [ -f "${i}" ] || continue + local patch_success=0 + local j= + for j in $(seq 0 5) + do + patch -p${j} --backup-if-mismatch -f < "${i}" --dry-run >/dev/null \ + && patch ${silent}-p${j} --backup-if-mismatch -f < "${i}" + if [ $? = 0 ] + then + patch_success=1 + break + fi + done + if [ ${patch_success} -eq 1 ] + then + print_info 3 "$(get_indent 3) - $(basename "${i}")" + else + die "Failed to apply patch '${i}' for '${P}'!" + fi + done + unset i j patch_success + else + print_info 2 "$(get_indent 2)${P}: >> No patches found in '$patchdir'; Skipping ..." + fi + + if $(uses_autoconf) && ! isTrue "${want_autoreconf}" + then + if [[ ${checksum} != $(at_checksum) ]] + then + print_info 3 "$(get_indent 2)${P}: >> Will autoreconfigure due applied patches ..." + want_autoreconf=yes + fi + fi + + if $(uses_autoconf) && isTrue "${want_autoreconf}" + then + gkautoreconf + fi + + if isTrue "${want_libtoolize}" + then + gklibtoolize + fi +} + +_src_unpack() { + cd "${WORKDIR}" || die "Failed to chdir to '${WORKDIR}'!" + tar -xaf "${GKPKG_SRCTAR}" \ + || die "Failed to unpack '${GKPKG_SRCTAR}' to '${WORKDIR}'!" +} + +# Return all the flag variables that our high level funcs operate on. +all-flag-vars() { + echo {ADA,C,CPP,CXX,CCAS,F,FC,LD}FLAGS +} + +# @FUNCTION: append-cflags +# @USAGE: <flags> +# @DESCRIPTION: +# Add extra <flags> to the current CFLAGS. If a flag might not be supported +# with different compilers (or versions), then use test-flags-CC like so: +# @CODE +# append-cflags $(test-flags-CC -funky-flag) +# @CODE +append-cflags() { + [[ $# -eq 0 ]] && return 0 + # Do not do automatic flag testing ourselves. #417047 + export CFLAGS+=" $*" + return 0 +} + +# @FUNCTION: append-cppflags +# @USAGE: <flags> +# @DESCRIPTION: +# Add extra <flags> to the current CPPFLAGS. +append-cppflags() { + [[ $# -eq 0 ]] && return 0 + export CPPFLAGS+=" $*" + return 0 +} + +# @FUNCTION: append-cxxflags +# @USAGE: <flags> +# @DESCRIPTION: +# Add extra <flags> to the current CXXFLAGS. If a flag might not be supported +# with different compilers (or versions), then use test-flags-CXX like so: +# @CODE +# append-cxxflags $(test-flags-CXX -funky-flag) +# @CODE +append-cxxflags() { + [[ $# -eq 0 ]] && return 0 + # Do not do automatic flag testing ourselves. #417047 + export CXXFLAGS+=" $*" + return 0 +} + +# @FUNCTION: append-fflags +# @USAGE: <flags> +# @DESCRIPTION: +# Add extra <flags> to the current {F,FC}FLAGS. If a flag might not be supported +# with different compilers (or versions), then use test-flags-F77 like so: +# @CODE +# append-fflags $(test-flags-F77 -funky-flag) +# @CODE +append-fflags() { + [[ $# -eq 0 ]] && return 0 + # Do not do automatic flag testing ourselves. #417047 + export FFLAGS+=" $*" + export FCFLAGS+=" $*" + return 0 +} + +# @FUNCTION: append-flags +# @USAGE: <flags> +# @DESCRIPTION: +# Add extra <flags> to your current {C,CXX,F,FC}FLAGS. +append-flags() { + [[ $# -eq 0 ]] && return 0 + case " $* " in + *' '-[DIU]*) die 'please use append-cppflags for preprocessor flags' ;; + *' '-L*|\ + *' '-Wl,*) die 'please use append-ldflags for linker flags' ;; + esac + append-cflags "$@" + append-cxxflags "$@" + append-fflags "$@" + return 0 +} + +# @FUNCTION: append-ldflags +# @USAGE: <flags> +# @DESCRIPTION: +# Add extra <flags> to the current LDFLAGS. +append-ldflags() { + [[ $# -eq 0 ]] && return 0 + export LDFLAGS="${LDFLAGS} $*" + return 0 +} + +# @FUNCTION: append-lfs-flags +# @DESCRIPTION: +# Add flags that enable Large File Support. +append-lfs-flags() { + [[ $# -ne 0 ]] && die "append-lfs-flags takes no arguments" + # see comments in filter-lfs-flags func for meaning of these + append-cppflags -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE +} + + +# @FUNCTION: filter-flags +# @USAGE: <flags> +# @DESCRIPTION: +# Remove particular <flags> from {C,CPP,CXX,CCAS,F,FC,LD}FLAGS. Accepts shell globs. +filter-flags() { + local v + for v in $(all-flag-vars) ; do + _filter-var ${v} "$@" + done + return 0 +} + +# @FUNCTION: filter-ldflags +# @USAGE: <flags> +# @DESCRIPTION: +# Remove particular <flags> from LDFLAGS. Accepts shell globs. +filter-ldflags() { + _filter-var LDFLAGS "$@" + return 0 +} + +# @FUNCTION: gkautomake +# @USAGE: [<additional-automake-parameter>] +# @DESCRIPTION: +# Wrapper for automake. +# Will die when command will exit with nonzero exit status. +gkautomake() { + if [[ -n "${WANT_AUTOMAKE}" ]] + then + gkexec "WANT_AUTOMAKE=${WANT_AUTOMAKE} automake ${*}" + else + gkexec "automake ${*}" + fi +} + +# @FUNCTION: gkautoreconf +# @USAGE: [<additional-autoreconf-parameter>] +# @DESCRIPTION: +# Wrapper for autoreconf. +# Will die when command will exit with nonzero exit status. +gkautoreconf() { + gkexec "autoreconf --force --install ${*}" +} + +# @FUNCTION: gkconf +# @USAGE: [<additional-configure-parameter>] +# @DESCRIPTION: +# Wrapper for configure. +# Will die when command will exit with nonzero exit status. +gkconf() { + : ${GKCONF_SOURCE:=.} + if [ -x "${GKCONF_SOURCE}/configure" ] + then + local -a conf_args=() + local conf_help=$("${GKCONF_SOURCE}/configure" --help 2>/dev/null) + + if [[ ${conf_help} == *--disable-dependency-tracking* ]]; then + conf_args+=( --disable-dependency-tracking ) + fi + + if [[ ${conf_help} == *--disable-silent-rules* ]]; then + conf_args+=( --disable-silent-rules ) + fi + + if [[ ${conf_help} == *--docdir* ]]; then + conf_args+=( --docdir=/usr/share/doc/${P} ) + fi + + if [[ ${conf_help} == *--htmldir* ]]; then + conf_args+=( --htmldir=/usr/share/doc/${P}/html ) + fi + + if [[ ${conf_help} == *--with-sysroot* ]]; then + conf_args+=( --with-sysroot="${BROOT}/usr:${SYSROOT}" ) + fi + + # Handle arguments containing quoted whitespace (see bug #457136). + eval "local -a EXTRA_ECONF=(${EXTRA_ECONF})" + + set -- \ + --prefix=/usr \ + ${CBUILD:+--build=${CBUILD}} \ + --host=${CHOST} \ + ${CTARGET:+--target=${CTARGET}} \ + --mandir=/usr/share/man \ + --infodir=/usr/share/info \ + --datadir=/usr/share \ + --sysconfdir=/etc \ + --localstatedir=/var/lib \ + "${conf_args[@]}" \ + "$@" \ + "${EXTRA_ECONF[@]}" + + gkexec "${GKCONF_SOURCE}/configure $*" + elif [ -f "${GKCONF_SOURCE}/configure" ]; then + die "configure is not executable" + else + die "no configure script found" + fi +} + +# @FUNCTION: gklibtoolize +# @USAGE: [dirs] [--portage] [--reverse-deps] [--patch-only] [--remove-internal-dep=xxx] [--shallow] [--no-uclibc] +# @DESCRIPTION: +# Apply a smorgasbord of patches to bundled libtool files. This function +# should always be safe to run. If no directories are specified, then +# ${S} will be searched for appropriate files. +# +# If the --shallow option is used, then only ${S}/ltmain.sh will be patched. +# +# The other options should be avoided in general unless you know what's going on. +gklibtoolize() { + type -P eltpatch &>/dev/null || die "eltpatch not found; is app-portage/elt-patches installed?" + + gkexec "ELT_LOGDIR=\"${T}\" LD=\"$(tc-getLD)\" eltpatch ${*}" +} + +# @FUNCTION: gkmake +# @USAGE: [<additional-make-parameter>] +# @DESCRIPTION: +# Wrapper for make. +# Will die when command will exit with nonzero exit status. +gkmake() { + local command=( "${NICEOPTS}${MAKE} ${MAKEOPTS}" ) + command+=( "${@}" ) + + gkexec "${command[*]}" +} + +# @FUNCTION: replace-flags +# @USAGE: <old> <new> +# @DESCRIPTION: +# Replace the <old> flag with <new>. Accepts shell globs for <old>. +replace-flags() { + [[ $# != 2 ]] && die "Usage: replace-flags <old flag> <new flag>" + + local f var new + for var in $(all-flag-vars) ; do + # Looping over the flags instead of using a global + # substitution ensures that we're working with flag atoms. + # Otherwise globs like -O* have the potential to wipe out the + # list of flags. + new=() + for f in ${!var} ; do + # Note this should work with globs like -O* + [[ ${f} == ${1} ]] && f=${2} + new+=( "${f}" ) + done + export ${var}="${new[*]}" + done + + return 0 +} |