diff options
Diffstat (limited to 'subr.ex')
-rw-r--r-- | subr.ex/ex_init.subr | 449 | ||||
-rw-r--r-- | subr.ex/ex_pkg.subr | 320 | ||||
-rw-r--r-- | subr.ex/ex_pkg_depends.subr | 225 | ||||
-rw-r--r-- | subr.ex/ex_pkg_dispatch.subr | 407 | ||||
-rw-r--r-- | subr.ex/ex_pkg_env.subr | 195 | ||||
-rw-r--r-- | subr.ex/ex_pkg_exec.subr | 223 | ||||
-rw-r--r-- | subr.ex/ex_pkg_restart.subr | 324 | ||||
-rw-r--r-- | subr.ex/ex_rtl.subr | 99 | ||||
-rw-r--r-- | subr.ex/ex_rtl_configure.subr | 437 | ||||
-rw-r--r-- | subr.ex/ex_rtl_make.subr | 184 | ||||
-rw-r--r-- | subr.ex/ex_rtl_midipix.subr | 93 | ||||
-rw-r--r-- | subr.ex/ex_rtl_rpm.subr | 270 |
12 files changed, 3226 insertions, 0 deletions
diff --git a/subr.ex/ex_init.subr b/subr.ex/ex_init.subr new file mode 100644 index 00000000..5dc4f857 --- /dev/null +++ b/subr.ex/ex_init.subr @@ -0,0 +1,449 @@ +# +# Copyright (c) 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Lucía Andrea Illanes Albornoz <lucia@luciaillanes.de> +# set +o errexit -o noglob -o nounset is assumed. +# + +exp_setrstatus() { + local _epsrs_rstatus="${1#\$}" _epsrs_status="${2}"; + eval ${_epsrs_rstatus}=\"${_epsrs_status}\"; + return 0; +}; + +# +# ex_init_env() - initialise build environment +# @_rstatus: out reference to variable of status string on failure +# @_rhname: out reference to variable of build hostname +# @_ruser: out reference to variable of build user +# @_name_base: base name for messages and theme file(s) +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +ex_init_env() { + local _eie_rstatus="${1#\$}" _eie_rhname="${2#\$}" _eie_ruser="${3#\$}" \ + _eie_name_base="${4}" \ + _eie_fname="" _eie_lang="${LANG:-C}" _eie_lang_="" _eie_name="" \ + _eie_rc=0; + _eie_lang="${_eie_lang%%_*}"; + + if ! cd "${0%/*}"; then + _eie_rc=1; + exp_setrstatus "${_eie_rstatus}" 'failed to change working directory to \`'"${0%/*}"''\''.'; + elif ! umask 022; then + _eie_rc=1; + exp_setrstatus "${_eie_rstatus}" 'failed to set umask(2).'; + elif ! eval ${_eie_rhname}=\"\$\(hostname\)\"; then + _eie_rc=1; + exp_setrstatus "${_eie_rstatus}" 'failed to obtain hostname.'; + elif ! eval ${_eie_ruser}=\"\$\(id -nu\)\"; then + _eie_rc=1; + exp_setrstatus "${_eie_rstatus}" 'failed to obtain username.'; + else + for _eie_fname in \ + $(find subr.ex -name *.subr) \ + $(find subr.pkg -name *.subr) \ + $(find subr.rtl -name *.subr) \ + "etc/${_eie_name_base}.theme" \ + ; + do + if ! . "${_eie_fname}"; then + _eie_rc=1; + exp_setrstatus "${_eie_rstatus}" 'failed to source \`'"${_eie_fname}"''\''.'; + break; + fi; + done; + + if [ "${_eie_rc}" -eq 0 ]; then + if [ -e "${_eie_name_base}.local" ]; then + if ! . "${_eie_name_base}.local"; then + _eie_rc=1; + exp_setrstatus "${_eie_rstatus}" 'failed to source \`'"${_eie_name_base}"'.local'\''.'; + fi; + fi; + fi; + + if [ "${_eie_rc}" -eq 0 ]; then + for _eie_name in ${_eie_name_base} rtl; do + for _eie_lang_ in ${_eie_lang} C; do + _eie_fname="etc/${_eie_name}.msgs.${_eie_lang_}"; + if [ -e "${_eie_fname}" ]; then + if ! . "${_eie_fname}"; then + _eie_rc=1; + exp_setrstatus "${_eie_rstatus}" 'failed to source \`'"${_eie_fname}"''\''.'; + break; + fi; + + if [ -e "${_eie_fname}.local" ]; then + if ! . "${_eie_fname}.local"; then + _eie_rc=1; + exp_setrstatus "${_eie_rstatus}" 'failed to source \`'"${_eie_fname}"'.local'\''.'; + fi; + fi; + break; + fi; + done; + + if [ "${_eie_rc}" -ne 0 ]; then + break; + fi; + done; + fi; + fi; + export LANG=C LC_ALL=C; + + return "${_eie_rc}"; +}; + +# +# ex_init_getopts() - process command-line arguments +# @_rstatus: out reference to variable of status string on failure +# @_fn: reference to function called to process command-line argument +# @_optstring: getopts(1) optstring +# @...: command-line arguments as "${@}" +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +ex_init_getopts() { + local _eig_rstatus="${1#\$}" _eig_fn="${2}" _eig_optstring="${3}" \ + _eig_arg="" _eig_fn_rc=0 _eig_opt="" _eig_shiftfl=0 \ + OPTARG="" OPTIND=0; + shift 3; + + if ! "${_eig_fn}" init "${_eig_rstatus}"; then + return 1; + fi; + + while [ "${#}" -gt 0 ]; do + case "${1}" in + --*) + "${_eig_fn}" longopt "${_eig_rstatus}" "${1}" ${2:-}; + _eig_fn_rc="${?}"; + + case "${_eig_fn_rc}" in + 0) ;; + 1) return 1; ;; + + *) shift "$((${_eig_fn_rc} - 1))"; + continue; ;; + esac; + ;; + esac; + + OPTIND=0; + if getopts "${_eig_optstring}" _eig_opt; then + "${_eig_fn}" opt "${_eig_rstatus}" "${_eig_opt}" "${OPTARG:-}" "${@}"; + _eig_fn_rc="${?}"; + + case "${_eig_fn_rc}" in + 0) ;; + 1) return 1; ;; + + *) shift "$((${_eig_fn_rc} - 1))"; + continue; ;; + esac; + else + "${_eig_fn}" nonopt "${_eig_rstatus}" "${@}"; + _eig_fn_rc="${?}"; + + case "${_eig_fn_rc}" in + 0) ;; + 1) return 1; ;; + + *) shift "$((${_eig_fn_rc} - 1))"; + continue; ;; + esac; + fi; + done; + + if ! "${_eig_fn}" done "${_eig_rstatus}"; then + return 1; + fi; + + return 0; +}; + +# +# ex_init_help() - display usage screen and exit if requested in command-line arguments +# @_rstatus: out reference to variable of status string on failure +# @_args_long: optional list of long (prefixed with `--') arguments +# @_name_base: base name for usage screen file +# @_optstring: getopts(1) optstring +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +ex_init_help() { + local _eih_rstatus="${1#\$}" _eih_args_long="${2}" \ + _eih_name_base="${3}" _eih_optstring="${4}" \ + _eih_arg_long="" _eih_opt="" _eih_shiftfl=0 \ + OPTIND; + shift 4; + + while [ "${#}" -gt 0 ]; do + case "${1}" in + -h) + if [ -t 1 ]; then + cat "etc/${_eih_name_base}.usage.short"; + else + sed 's/\[[0-9]\+m//g' "etc/${_eih_name_base}.usage.short"; + fi; + exit 0; + ;; + + --help) + if [ -t 1 ]; then + cat "etc/${_eih_name_base}.usage"; + else + sed 's/\[[0-9]\+m//g' "etc/${_eih_name_base}.usage"; + fi; + exit 0; + ;; + + *=*) shift; continue; + ;; + + *) _eih_shiftfl=0; + for _eih_arg_long in ${_eih_args_long}; do + if [ "${_eih_arg_long}" = "${1}" ]; then + _eih_shiftfl=1; + fi; + done; + if [ "${_eih_shiftfl}" = 1 ]; then + shift; continue; + fi; + ;; + esac; + + OPTIND=0; + if getopts "${_eih_optstring}" _eih_opt 2>/dev/null; then + case "${_eih_opt}" in + h) + if [ -t 1 ]; then + cat "etc/${_eih_name_base}.usage.short"; + else + sed 's/\[[0-9]\+m//g' "etc/${_eih_name_base}.usage.short"; + fi; + exit 0; + ;; + esac; + shift $((${OPTIND}-1)); OPTIND=1; + else + shift; + fi; + done; + + return 0; +}; + +# +# ex_init_files() - initialise build files +# @_rstatus: out reference to variable of status string on failure +# @_rclean_builds: in reference to variable of -C argument value +# @_rdist: in reference to variable of -D argument value +# @_build_log_fname: absolute pathname to build log file +# @_build_log_last_fname: absolute pathname to last build log file +# @_build_status_in_progress_fname: absolute pathname to build-in-progress status file +# @_check_path_vars: list of pathname variables to check +# @_clear_env_vars_except: list of environment variables to not unset when clearing the environment +# @_clear_prefix_paths: list of directory pathnames to clear in the top-level prefix +# @_rpm_semaphore: absolute pathname to rpmbuild(1) parallel jobs count semaphore +# @_dlcachedir: absolute pathname to download cache directory +# @_prefix: absolute pathname to top-level prefix +# @_prefix_rpm: absolute pathname to RPM files prefix +# @_workdir: absolute pathname to build-specific temporary directory +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +ex_init_files() { + local _eif_rstatus="${1#\$}" _eif_rclean_builds="${2#\$}" _eif_rdist="${3#\$}" \ + _eif_build_log_fname="${4}" _eif_build_log_last_fname="${5}" \ + _eif_build_status_in_progress_fname="${6}" _eif_check_path_vars="${7}" \ + _eif_clear_env_vars_except="${8}" _eif_clear_prefix_paths="${9}" \ + _eif_rpm_semaphore="${10}" _eif_dlcachedir="${11}" _eif_prefix="${12}" \ + _eif_prefix_rpm="${13}" _eif_workdir="${14}" \ + _eif_log_last_fname="" _eif_log_last_num=1 _eif_rc=0; + + if ! rtl_fileop mkdir "${_eif_dlcachedir}" "${_eif_workdir}"\ + || rtl_lmatch "${_eif_rdist}" "rpm" ","\ + && ! rtl_fileop mkdir "${_eif_prefix_rpm}"; then + _eif_rc=1; + rtl_setrstatus "${_eif_rstatus}" 'cannot create build directories.'; + elif [ -e "${_eif_build_status_in_progress_fname}" ]; then + _eif_rc=1; + rtl_setrstatus "${_eif_rstatus}" 'another build targeting this architecture and build type is currently in progress.'; + elif ! rtl_clean_env "${_eif_clear_env_vars_except}"; then + _eif_rc=1; + rtl_setrstatus "${_eif_rstatus}" 'failed to clean environment.'; + elif ! rtl_check_path_vars "${_eif_rstatus}" "${_eif_check_path_vars}"; then + _eif_rc=1; + else + export LC_ALL="${LC_ALL:-C}"; + export TMP="${_eif_workdir}" TMPDIR="${_eif_workdir}"; + touch "${_eif_build_status_in_progress_fname}"; + + if [ -e "${_eif_build_log_fname}" ]; then + while [ -e "${_eif_build_log_fname}.${_eif_log_last_num}" ]; do + : $((_eif_log_last_num+=1)); + done; + + _eif_log_last_fname="${_eif_build_log_fname}.${_eif_log_last_num}"; + rtl_fileop mv "${_eif_build_log_fname}" "${_eif_log_last_fname}"; + rtl_fileop ln_symbolic "${_eif_log_last_fname}" "${_eif_build_log_last_fname}"; + fi; + + rtl_fileop touch "${_eif_build_log_fname}"; + rtl_log_set_fname "${_eif_build_log_fname}"; + + rtl_fileop rm "${_eif_rpm_semaphore}"; + + if rtl_lmatch "${_eif_rclean_builds}" $"prefix" ","; then + trap "rm -f \"${_eif_build_status_in_progress_fname}\" 2>/dev/null; + + rtl_log_msgV \"fatalexit\" \"${MSG_build_aborted}\"" HUP INT TERM USR1 USR2; + rtl_log_msgV "info" "${MSG_build_clean_prefix}"; + + for _eif_pname in ${_eif_clear_prefix_paths}; do + if ! rtl_fileop rm "${_eif_prefix}/${_eif_pname}"; then + _eif_rc=1; + rtl_setrstatus "${_eif_rstatus}" 'failed to remove \`'"${_eif_prefix:+${_eif_prefix}/}${_eif_pname}'"'.'; + break; + fi; + done; + + trap - HUP INT TERM USR1 USR2; + fi; + + export PATH="${_eif_prefix}/localcross/bin${PATH:+:${PATH}}"; + export PATH="${_eif_prefix}/bin${PATH:+:${PATH}}"; + fi; + + return "${_eif_rc}"; +}; + +# +# ex_init_logging() - initialise build logging +# @_rstatus: out reference to variable of status string on failure +# @_rverbose_tags: in reference to out variable of -V argument value +# @_verbose: -[vV] argument value +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +ex_init_logging() { + local _eil_rstatus="${1#\$}" _eil_rverbose_tags="${2#\$}" _eil_verbose="${3}" \ + _eil_tag="" _eil_tags="" _eil_tags_enable="" _eil_rc=0; + + rtl_log_clear_tags; + case "${_eil_verbose}" in + + 0) if eval [ \"\${#${_eil_rverbose_tags}}\" -eq 0 ]; then + rtl_log_enable_tagsV "${LOG_TAGS_normal}"; + fi; + ;; + + 1) rtl_log_enable_tagsV "${LOG_TAGS_verbose}"; ;; + + *) _eil_rc=1; + rtl_setrstatus "${_eil_rstatus}" 'invalid verbosity level (max. -v)'; + ;; + + esac; + + if [ "${_eil_rc}" -eq 0 ]; then + eval _eil_tags="\${${_eil_rverbose_tags}}"; + case "${_eil_tags}" in + + +*) rtl_log_enable_tagsV "${LOG_TAGS_normal}"; + eval ${_eil_rverbose_tags}="\${${_eil_rverbose_tags}#+}"; + ;; + + *) ;; + + esac; + + rtl_llift2 "${_eil_rverbose_tags}" \$_eil_tags "," " "; + + for _eil_tag in ${_eil_tags}; do + case "${_eil_tag}" in + + all) rtl_log_enable_tagsV "${LOG_TAGS_all}"; ;; + + clear|none) rtl_log_clear_tags; ;; + + normal) rtl_log_enable_tagsV "${LOG_TAGS_normal}"; ;; + + verbose) rtl_log_enable_tagsV "${LOG_TAGS_verbose}"; ;; + + *) rtl_lsearch_patternl2 \$LOG_TAGS_all \$_eil_tags_enable "${_eil_tag}" ","; + if [ "${#_eil_tags_enable}" -gt 0 ]; then + rtl_log_enable_tagsV "${_eil_tags_enable}"; + else + _eil_rc=1; + rtl_setrstatus "${_eil_rstatus}" 'invalid log tag or tag pattern \`'"${_eil_tag}"''\''.'; + break; + fi; + ;; + + esac; + done; + fi; + + return "${_eil_rc}"; +}; + +# +# ex_init_prereqs() - initialise build prerequisite commands +# @_rstatus: out reference to variable of status string on failure +# @_prereqs: list of prerequisite commands +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +ex_init_prereqs() { + local _eip_rstatus="${1#\$}" _eip_prereqs="${2}" \ + _eip_rc=0; + + if ! rtl_check_prereqsV "${_eip_rstatus}" ${_eip_prereqs}; then + _eip_rc=1; + elif ! awk -V 2>/dev/null | grep -q "^GNU Awk "; then + _eip_rc=1; + rtl_setrstatus "${_eip_rstatus}" 'awk(1) in \$PATH must be GNU Awk.'; + elif ! (FNAME="$(mktemp)" && { trap "rm -f \"\${FNAME}\"" EXIT HUP INT TERM USR1 USR2; \ + sed -i'' -e '' "${FNAME}" >/dev/null 2>&1; }); + then + _eip_rc=1; + rtl_setrstatus "${_eip_rstatus}" 'sed(1) in \${PATH} does not support the \`-i'\'' option.'; + fi; + + return "${_eip_rc}"; +}; + +# +# ex_init_theme() - initialise theme +# @_rstatus: out reference to variable of status string on failure +# @_hname: build hostname +# @_name_base: base name for theme file(s) +# @_theme: theme name +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +ex_init_theme() { + local _eit_rstatus="${1#\$}" _eit_hname="${2}" _eit_name_base="${3}" _eit_theme="${4}" \ + _eit_rc=0 _eit_theme_fname=""; + + if [ "${_eit_theme:+1}" = 1 ]; then + _eit_theme_fname="etc/${_eit_name_base}.${_eit_theme}.theme"; + else + _eit_theme_fname="etc/${_eit_name_base}.theme.host.${_eit_hname}"; + if ! [ -e "${_eit_theme_fname}" ]; then + _eit_theme_fname="etc/${_eit_name_base}.theme"; + fi; + fi; + + if ! [ -e "${_eit_theme_fname}" ]; then + _eit_rc=1; + exp_setrstatus "${_eit_rstatus}" 'failed to source \`'"${_eit_theme_fname}"''\''.'; + else + . "${_eit_theme_fname}"; + fi; + + return "${_eit_rc}"; +}; + +# vim:filetype=sh textwidth=0 diff --git a/subr.ex/ex_pkg.subr b/subr.ex/ex_pkg.subr new file mode 100644 index 00000000..2475f447 --- /dev/null +++ b/subr.ex/ex_pkg.subr @@ -0,0 +1,320 @@ +# +# Copyright (c) 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Lucía Andrea Illanes Albornoz <lucia@luciaillanes.de> +# set +o errexit -o noglob -o nounset is assumed. +# + +# +# ex_pkg_copy_group_vars() - copy build group variables into build group +# @_group_name_src: single source build group name +# @_group_name_dst: single destination build group name +# @[_build_vars_default]: optional list of default build variables, defaults to ${DEFAULT_BUILD_VARS} +# +# Returns: zero (0) on success, non-zero (>0) on failure. +# +ex_pkg_copy_group_vars() { + local _epcgv_group_name_src="${1#\$}" _epcgv_group_name_dst="${2#\$}" \ + _epcgv_build_vars_default="${3:-${DEFAULT_BUILD_VARS}}" \ + _epcgv_group_name_dst_uc="" _epcgv_group_name_src_uc="" \ + _epcgv_vname="" _epcgv_vval=""; + rtl_toupper2 \$_epcgv_group_name_dst \$_epcgv_group_name_dst_uc; + rtl_toupper2 \$_epcgv_group_name_src \$_epcgv_group_name_src_uc; + + for _epcgv_vname in ${_epcgv_build_vars_default}; do + if rtl_get_var_unsafe \$_epcgv_vval "${_epcgv_group_name_src_uc}_${_epcgv_vname}"\ + && [ "${_epcgv_vval:+1}" = 1 ]; then + rtl_set_var_unsafe "${_epcgv_group_name_dst_uc}_${_epcgv_vname}" "${_epcgv_vval}"; + fi; + done; + + return 0; +}; + +# +# ex_pkg_find_package() - find build group a single named package belongs to +# @_rgroup_name: out reference to variable of build group name +# @_group_names: build group names +# @_pkg_name: single named package +# +# Returns: zero (0) on success, non-zero (>0) if package not found, group name on stdout if package was found. +# +ex_pkg_find_package() { + local _epfp_rgroup_name="${1#\$}" _epfp_group_names="${2}" _epfp_pkg_name="${3}" \ + _epfp_foundfl=0 _epfp_group_name="" _epfp_pkg_names=""; + + for _epfp_group_name in ${_epfp_group_names}; do + if rtl_get_var_unsafe \$_epfp_pkg_names -u "${_epfp_group_name}_PACKAGES"\ + && [ "${_epfp_pkg_names:+1}" = 1 ]\ + && rtl_lmatch \$_epfp_pkg_names "${_epfp_pkg_name}"; then + _epfp_foundfl=1; break; + fi; + done; + + case "${_epfp_foundfl:-0}" in + 0) eval ${_epfp_rgroup_name}=; + return 1; ;; + + 1) eval ${_epfp_rgroup_name}='${_epfp_group_name}'; + return 0; ;; + esac; +}; + +# +# ex_pkg_get_default() - get single package default value +# @_rdefault: out reference to variable of default value or "" on end of list +# @_default_idx: one-based single default value index +# @_pkg_name: single package name +# @_pkg_version: single package version +# @_ldefault: SP-separated list of default value names (any of: patches, patches_pre, vars_files) +# +# Returns: zero (0) on success, non-zero (>0) on invalid default value name or unknown package. +# +ex_pkg_get_default() { + local _epgd_rdefault="${1#\$}" _epgd_default_idx="${2}" _epgd_pkg_name="${3}" \ + _epgd_pkg_version="${4}" _epgd_ldefault="${5}" \ + _epgd_default="" _epgd_group_name="" _epgd_patch_fname="" \ + _epgd_pkg_name_full="" _epgd_pkg_patches_extra="" _epgd_rc=0; + + set --; + _epgd_pkg_name_full="${_epgd_pkg_name}${_epgd_pkg_version:+-${_epgd_pkg_version}}"; + _epgd_rc=0; + + for _epgd_default in ${_epgd_ldefault}; do + case "${_epgd_default}" in + patches) + rtl_get_var_unsafe \$_epgd_pkg_patches_extra -u "PKG_${_epgd_pkg_name}_PATCHES_EXTRA"; + set +o noglob; + set -- \ + "${@}" \ + "${MIDIPIX_BUILD_PWD}/patches/${_epgd_pkg_name}/"*.patch \ + "${MIDIPIX_BUILD_PWD}/patches/${_epgd_pkg_name_full}.local.patch" \ + "${MIDIPIX_BUILD_PWD}/patches/${_epgd_pkg_name_full}.local@${BUILD_HNAME}.patch" \ + ${_epgd_pkg_patches_extra}; + set -o noglob; + ;; + + patches_pre) + set -- \ + "${@}" \ + "${MIDIPIX_BUILD_PWD}/patches/${_epgd_pkg_name_full}_pre.local.patch" \ + "${MIDIPIX_BUILD_PWD}/patches/${_epgd_pkg_name_full}_pre.local@${BUILD_HNAME}.patch"; + ;; + + vars_files) + rtl_get_var_unsafe \$_epgd_group_name -u "PKG_${_epgd_pkg_name}_GROUP"; + set -- \ + "vars/${_epgd_pkg_name}.vars" \ + "vars.${_epgd_group_name}/${_epgd_pkg_name}.vars"; + ;; + + *) + _epgd_rc=1; break; + ;; + esac; + done; + + if [ "${_epgd_rc}" = 0 ]; then + eval ${_epgd_rdefault}="\${${_epgd_default_idx}:-}"; + fi; + + return "${_epgd_rc}"; +}; + +# +# ex_pkg_get_packages() - get list of packages belonging to single named build group +# @_rpkg_names: out reference to variable of package names +# @_group_name: build group name +# +# Returns: zero (0) on success, non-zero (>0) on failure, list of package names on stdout on success. +# +ex_pkg_get_packages() { + local _epgp_rpkg_names="${1#\$}" _epgp_group_name="${2}" \ + _epgp_pkg_names=""; + + if rtl_get_var_unsafe \$_epgp_pkg_names -u "${_epgp_group_name}_PACKAGES"\ + && [ "${_epgp_pkg_names:+1}" = 1 ]; then + eval ${_epgp_rpkg_names}='${_epgp_pkg_names}'; + return 0; + else + eval ${_epgp_rpkg_names}=; + return 1; + fi; +}; + +# +# ex_pkg_get_package_vars() - get package variable names +# @_rpkg_vnames: out reference to package variable names variable +# @_build_vars_default: list of default build variables +# @_pkg_name: single package name +# +# Returns: zero (0) on success, non-zero (>0) on failure, list of package names on stdout on success. +# +ex_pkg_get_package_vars() { + local _epgpv_rpkg_vnames="${1#\$}" _epgpv_build_vars_default="${2}" _epgpv_pkg_name="${3}" \ + _epgpv_pkg_name_uc="" _epgpv_vname="" _epgpv_vnames=""; + rtl_toupper2 \$_epgpv_pkg_name \$_epgpv_pkg_name_uc; + + for _epgpv_vname in ${_epgpv_build_vars_default}; do + if eval [ \"\${PKG_${_epgpv_pkg_name_uc}_${_epgpv_vname}:+1}\" = 1 ]; then + rtl_lconcat \$_epgpv_vnames "PKG_${_epgpv_pkg_name_uc}_${_epgpv_vname}"; + fi; + done; + + eval ${_epgpv_rpkg_vnames}='${_epgpv_vnames}'; + return 0; +}; + +# +# ex_pkg_load_vars() - load build variables +# @_rstatus: out reference to status string +# @_rbuild_arch: in reference to build architecture +# @_rbuild_kind: in reference to build kind +# +# Returns: zero (0) on success, non-zero (>0) on failure, build variables post-return on success. +# +ex_pkg_load_vars() { + local _eplv_rstatus="${1#\$}" _eplv_rbuild_arch="${2#\$}" _eplv_rbuild_kind="${3#\$}" \ + _eplv_build_arch="" _eplv_rc=0 _eplv_fname=""; + + if ! rtl_lmatch "${_eplv_rbuild_arch}" "nt32 nt64"; then + _eplv_rc=1; + rtl_setrstatus "${_eplv_rstatus}" 'invalid architecture \`${'"${_eplv_rbuild_arch}"'}'\''.'; + elif ! rtl_lmatch "${_eplv_rbuild_kind}" "debug release"; then + _eplv_rc=1; + rtl_setrstatus "${_eplv_rstatus}" 'unknown build type \`${'"${_eplv_rbuild_kind}"'}'\''.'; + else + eval _eplv_build_arch="\${${_eplv_rbuild_arch}}"; + case "${_eplv_build_arch}" in + nt32) DEFAULT_TARGET="i686-nt32-midipix"; ;; + nt64) DEFAULT_TARGET="x86_64-nt64-midipix"; ;; + esac; + + if [ "${PREFIX_ROOT:+1}" ]\ + && [ "${PREFIX_ROOT#/}" = "${PREFIX_ROOT}" ]; then + PREFIX_ROOT="${PWD%/}/${PREFIX_ROOT}"; + fi; + if [ "${PREFIX:+1}" ]\ + && [ "${PREFIX#/}" = "${PREFIX}" ]; then + PREFIX="${PWD%/}/${PREFIX}"; + fi; + + for _eplv_fname in \ + "${HOME}/midipix_build.vars" \ + "${HOME}/.midipix_build.vars" \ + ../midipix_build.vars; + do + if [ -r "${_eplv_fname}" ]; then + rtl_fileop source "${_eplv_fname}"; + fi; + done; + + set +o noglob; + for _eplv_fname in \ + ./vars.env.d/*.env; + do + set -o noglob; + if [ -r "${_eplv_fname}" ]; then + rtl_fileop source "${_eplv_fname}"; + fi; + done; + set -o noglob; + fi; + + return "${_eplv_rc}"; +}; + +# +# ex_pkg_load_groups() - load all available build groups +# @_rgroups: out reference to variable of build groups +# @_rgroups_noauoto: optional out reference to variable of build groups not built automatically +# +# Returns: zero (0) on success, non-zero (>0) on failure. +# +ex_pkg_load_groups() { + local _eplg_rgroups="${1#\$}" _eplg_rgroups_noauto="${2#\$}" \ + _eplg_build_groups="" _eplg_build_groups_noauto="" _eplg_fname=""; + + EXP_PKG_REGISTER_GROUP_RGROUPS="${_eplg_rgroups}"; + EXP_PKG_REGISTER_GROUP_RGROUPS_NOAUTO="${_eplg_rgroups_noauto}"; + for _eplg_fname in $(find ./groups.d -name *.group | sort); do + rtl_fileop source_with_fnamevar "${_eplg_fname}"; + done; + unset EXP_PKG_REGISTER_GROUP_RGROUPS; + unset EXP_PKG_REGISTER_GROUP_RGROUPS_NOAUTO; + + for _eplg_fname in $(find ./groups.d -mindepth 2 -name *.package | sort); do + rtl_fileop source_with_fnamevar "${_eplg_fname}"; + done; + + return 0; +}; + +# +# ex_pkg_register() - register single package +# @_pkg_name: single package name +# @_fname: pathname to file package is defined in, relative to midipix_build root +# @[_group_name]: optional build group name; inferred from @_fname if not specified +# +# Returns: zero (0) on success, non-zero (>0) on failure. +# +ex_pkg_register() { + local _epr_pkg_name="${1}" _epr_fname="${2}" _epr_group_name="${3:-}" \ + _epr_group_name_uc="" _epr_group_noautofl=0; + + if [ "${_epr_group_name:+1}" != 1 ]; then + _epr_group_name="${_epr_fname#./*/}"; + _epr_group_name="${_epr_group_name%%/*}"; + _epr_group_name="${_epr_group_name%.d}"; + _epr_group_name="${_epr_group_name#*.}"; + fi; + + rtl_toupper2 \$_epr_group_name \$_epr_group_name_uc; + rtl_lconcat "\$${_epr_group_name_uc}_PACKAGES" "${_epr_pkg_name}"; + rtl_set_var_unsafe -u "PKG_${_epr_pkg_name}_GROUP" "${_epr_group_name}"; + rtl_set_var_unsafe -u "PKG_${_epr_pkg_name}_GROUP_FNAME" "${_epr_fname}"; + + return 0; +}; + +# +# ex_pkg_register_group() - register single group +# @_group_name: single group name +# @_fname: pathname to file group is defined in, relative to midipix_build root +# @[_ownerfl]: "owner" for groups that own their packages, "copy" for shorthand groups referring to packages from other groups +# @[_autofl]: "auto" for groups to build by default, "noauto" for optional groups only built when requested +# ${EXP_PKG_REGISTER_GROUP_RGROUPS}: inout reference to variable of build groups +# ${EXP_PKG_REGISTER_GROUP_RGROUPS_NOAUTO}: inout reference to variable of build groups only built when requested +# +# Returns: zero (0) on success, non-zero (>0) on failure. +# +ex_pkg_register_group() { + local _eprg_group_name="${1}" _eprg_fname="${2}" \ + _eprg_ownerfl="${3:-owner}" _eprg_autofl="${4:-auto}" \ + _eprg_pkg_name="" _eprg_pkg_names="" _eprg_rgroups=""; + + case "${_eprg_autofl}" in + auto) _eprg_rgroups="${EXP_PKG_REGISTER_GROUP_RGROUPS}"; ;; + noauto) _eprg_rgroups="${EXP_PKG_REGISTER_GROUP_RGROUPS_NOAUTO}"; ;; + *) ;; + esac; + if ! rtl_lmatch "${_eprg_rgroups}" "${_eprg_group_name}"; then + rtl_lconcat "${_eprg_rgroups}" "${_eprg_group_name}"; + fi; + + case "${_eprg_ownerfl}" in + owner) + if rtl_get_var_unsafe \$_eprg_pkg_names -u "${_eprg_group_name}_PACKAGES"\ + && [ "${_eprg_pkg_names:+1}" = 1 ]; then + for _eprg_pkg_name in ${_eprg_pkg_names}; do + rtl_set_var_unsafe -u "PKG_${_eprg_pkg_name}_GROUP" "${_eprg_group_name}"; + rtl_set_var_unsafe -u "PKG_${_eprg_pkg_name}_GROUP_FNAME" "${_eprg_fname}"; + done; + fi; + ;; + copy) ;; + *) ;; + esac; + + return 0; +}; + +# vim:filetype=sh textwidth=0 diff --git a/subr.ex/ex_pkg_depends.subr b/subr.ex/ex_pkg_depends.subr new file mode 100644 index 00000000..6a4f5aae --- /dev/null +++ b/subr.ex/ex_pkg_depends.subr @@ -0,0 +1,225 @@ +# +# Copyright (c) 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Lucía Andrea Illanes Albornoz <lucia@luciaillanes.de> +# set +o errexit -o noglob -o nounset is assumed. +# + +# +# ex_pkg_check_depends() - check single named package for unsatisfied dependencies +# @_checkfl: enable (1) or inhibit (0) dependency expansion +# @_rpkg_disabled: in reference to variable of list of disabled packages +# @_rpkg_finished: in reference to variable of list of finished packages +# @_pkg_name: single package name +# @_rpkg_names: in reference to variable of list of package names +# @_workdir: pathname to build-specific temporary directory +# +# Returns: zero (0) given no outstanding dependencies, non-zero (>0) otherwise +# +ex_pkg_check_depends() { + local _epcd_checkfl="${1}" _epcd_rpkg_disabled="${2}" _epcd_rpkg_finished="${3#\$}" \ + _epcd_pkg_name="${4}" _epcd_rpkg_names="${5#\$}" _epcd_workdir="${6}" \ + _epcd_dependfl=0 _epcd_depends="" _epcd_pkg_name_depend=""; + + if [ "${_epcd_checkfl}" -eq 1 ]\ + && rtl_get_var_unsafe \$_epcd_depends -u "PKG_"${_epcd_pkg_name}"_DEPENDS"\ + && [ "${_epcd_depends:+1}" = 1 ]; then + for _epcd_pkg_name_depend in ${_epcd_depends}; do + if ! rtl_lmatch "${_epcd_rpkg_disabled}" "${_epcd_pkg_name_depend}"\ + && ! ex_pkg_state_test2 "${_epcd_workdir}" "${_epcd_pkg_name_depend}" finish; + then + if ! rtl_lmatch "${_epcd_rpkg_names}" "${_epcd_pkg_name_depend}"; then + rtl_log_msgV "fatalexit" "${MSG_build_unknown_dep}" "${_epcd_pkg_name_depend}" "${_epcd_pkg_name}"; + else + _epcd_dependfl=1; break; + fi; + fi; + done; + fi; + + return "${_epcd_dependfl}"; +}; + +# +# ex_pkg_check_depends_unknown() - check single named package for unknown dependencies +# @_pkg_name: single package name +# @_rpkg_names_set: in reference to variable of set of package names +# @_rpkg_unknown: out reference to variable of list of finished packages +# +# Returns: zero (0) given no unknown dependencies, non-zero (>0) otherwise +# +ex_pkg_check_depends_unknown() { + local _epcdu_pkg_name="${1}" _epcdu_rpkg_names_set="${2#\$}" \ + _epcdu_rpkg_unknown="${3#\$}" \ + _epcdu_defined=0 _epcdu_depends="" _epcdu_pkg_name_depend="" \ + _epcdu_rc=0; + + if rtl_get_var_unsafe \$_epcdu_depends -u "PKG_"${_epcdu_pkg_name}"_DEPENDS"\ + && [ "${_epcdu_depends:+1}" = 1 ]; then + for _epcdu_pkg_name_depend in ${_epcdu_depends}; do + if [ "${_epcdu_pkg_name_depend#*:*}" != "${_epcdu_pkg_name_depend}" ]; then + continue; + elif ! rtl_get_var_unsafe \$_epcdu_defined "${_epcdu_rpkg_names_set}_${_epcdu_pkg_name_depend}"\ + || [ "${_epcdu_defined:-0}" -eq 0 ]; then + rtl_lconcat "${_epcdu_rpkg_unknown}" "${_epcdu_pkg_name_depend}"; + _epcdu_rc=1; + fi; + done; + fi; + + return "${_epcdu_rc}"; +}; + +# +# ex_pkg_unfold_depends() - unfold list of package names into dependency-expanded set of complete, disabled, finished, and outstanding package names +# @_rdisabled: in reference to out variable of disabled packages +# @_rfinished: in reference to out variable of finished packages +# @_rnames: out reference to variable of package names +# @_checkfl: enable (1) or inhibit (0) dependency expansion +# @_forcefl: enable (1) or inhibit (0) forcibly rebuilding finished packages +# @_group_name: build group name +# @_pkg_names: list of package names +# @_restart: optional whitespace-separated list of package names to rebuild +# @_test_finished: only exclude disabled packages (0,) split finished packages +# @_workdir: pathname to build-specific temporary directory +# +# Returns: zero (0) on success, non-zero (>0) on failure. +# +ex_pkg_unfold_depends() { + local _epud_rdisabled="${1#\$}" _epud_rfinished="${2#\$}" _epud_rnames="${3#\$}" \ + _epud_checkfl="${4}" _epud_forcefl="${5}" _epud_group_name="${6}" \ + _epud_pkg_names="${7}" _epud_restart="${8}" _epud_test_finished="${9}" \ + _epud_workdir="${10}" \ + _epud_depends="" _epud_pkg_disabled="" _epud_pkg_force="" _epud_pkg_name="" \ + _epud_pkg_name_depend="" _epud_pkg_names_new="" _epud_pkg_names_set="" \ + _epud_pkg_unknown="" _epud_restartfl=0 _epud_unknown_depends=0; + + if [ "${_epud_restart:+1}" = 1 ]\ + && ! rtl_lmatch \$_epud_restart "ALL LAST"; then + rtl_lsearch \$_epud_pkg_names "${_epud_restart}"; + fi; + if [ "${_epud_restart:+1}" = 1 ]\ + && [ "${_epud_checkfl:-0}" -eq 1 ]; then + rtl_lunfold_dependsV 'PKG_${_rld_name}_DEPENDS' \$_epud_pkg_names ${_epud_pkg_names}; + _epud_pkg_names="$(rtl_uniq ${_epud_pkg_names})"; + fi; + + rtl_llift_set \$_epud_pkg_names \$_epud_pkg_names_set; + for _epud_pkg_name in ${_epud_pkg_names}; do + if rtl_get_var_unsafe \$_epud_depends -u "PKG_"${_epud_pkg_name}"_DEPENDS"\ + && [ "${_epud_depends:+1}" = 1 ]; then + _epud_pkg_unknown=""; + if ! ex_pkg_check_depends_unknown "${_epud_pkg_name}" \$_epud_pkg_names_set \$_epud_pkg_unknown; then + for _epud_pkg_name_depend in ${_epud_pkg_unknown}; do + rtl_log_msgV "warning" "${MSG_build_unknown_dep}" "${_epud_pkg_name_depend}" "${_epud_pkg_name}"; + done; + _epud_unknown_depends=1; + fi; + fi; + + if [ "${_epud_restart}" = "ALL" ]\ + || rtl_lmatch \$_epud_restart "${_epud_pkg_name}"; then + _epud_restartfl=1; + else + _epud_restartfl=0; + fi; + + if rtl_get_var_unsafe \$_epud_pkg_disabled -u "PKG_${_epud_pkg_name}_DISABLED"\ + && [ "${_epud_pkg_disabled}" = 1 ]; + then + rtl_lconcat "${_epud_rdisabled}" "${_epud_pkg_name}"; + + elif [ "${_epud_test_finished:-1}" -eq 1 ]\ + && ex_pkg_state_test2 "${_epud_workdir}" "${_epud_pkg_name}" finish\ + && [ "${_epud_restartfl:-0}" -eq 0 ]\ + && [ "${_epud_forcefl:-0}" -ne 1 ]\ + && rtl_get_var_unsafe \$_epud_pkg_force -u "${_epud_group_name}_FORCE"\ + && [ "${_epud_pkg_force}" != 1 ]; + then + rtl_lconcat "${_epud_rfinished}" "${_epud_pkg_name}"; + + else + rtl_lconcat \$_epud_pkg_names_new "${_epud_pkg_name}"; + fi; + done; + rtl_llift_unset \$_epud_pkg_names_set; + + if [ "${_epud_unknown_depends}" -eq 1 ]; then + rtl_log_msgV "warning" "${MSG_build_unknown_deps}"; + fi; + + eval ${_epud_rdisabled}='$(rtl_uniq2 "${_epud_rdisabled}")'; + eval ${_epud_rfinished}='$(rtl_uniq2 "${_epud_rfinished}")'; + eval ${_epud_rnames}='$(rtl_uniq "${_epud_pkg_names_new}")'; + + return 0; +}; + +# +# ex_pkg_unfold_rdepends() - unfold list of package names into reverse dependency-expanded set of complete, disabled, finished, and outstanding package names +# @_rdisabled: in reference to out variable of disabled packages +# @_rfinished: in reference to out variable of finished packages +# @_rnames: out reference to variable of package names +# @_group_name: build group name +# @_pkg_names: list of package names +# @_restart: optional whitespace-separated list of package names to rebuild +# @_test_finished: only exclude disabled packages (0,) split finished packages +# @_workdir: pathname to build-specific temporary directory +# @_recursefl: resolve recursively ("recurse") or non-recursively ("norecurse") +# +# Returns: zero (0) on success, non-zero (>0) on failure. +# +ex_pkg_unfold_rdepends() { + local _epur_rdisabled="${1#\$}" _epur_rfinished="${2#\$}" _epur_rnames="${3#\$}" \ + _epur_group_name="${4}" _epur_pkg_names="${5}" _epur_restart="${6}" \ + _epur_test_finished="${7}" _epur_workdir="${8}" _epur_recursefl="${9}" \ + _epur_depends="" _epur_disabled=0 _epur_force=0 _epur_pkg_depends="" \ + _epur_pkg_name="" _epur_pkg_names_new="" _epur_pkg_name_depend="" \ + _epur_pkg_name_rdepend="" _epur_pkg_rdepends=""; + + for _epur_pkg_name_depend in ${_epur_restart}; do + for _epur_pkg_name in ${_epur_pkg_names}; do + if [ "${_epur_pkg_name}" = "${_epur_pkg_name_depend}" ]; then + continue; + + elif rtl_get_var_unsafe \$_epur_depends -u "PKG_"${_epur_pkg_name}"_DEPENDS"\ + && rtl_lunfold_dependsV 'PKG_${_rld_name}_DEPENDS' \$_epur_pkg_depends ${_epur_depends}\ + && [ "${_epur_pkg_depends:+1}" = 1 ]\ + && rtl_lmatch \$_epur_pkg_depends "${_epur_pkg_name_depend}"; + then + case "${_epur_recursefl}" in + recurse) _epur_pkg_rdepends="${_epur_pkg_name} ${_epur_pkg_depends}"; ;; + norecurse) _epur_pkg_rdepends="${_epur_pkg_name}"; ;; + esac; + + for _epur_pkg_name_rdepend in ${_epur_pkg_rdepends}; do + if rtl_get_var_unsafe \$_epur_disabled -u "PKG_${_epur_pkg_name_rdepend}_DISABLED"\ + && [ "${_epur_disabled}" = 1 ]; + then + rtl_lconcat "${_epur_rdisabled}" "${_epur_pkg_name_rdepend}"; + + elif [ "${_epur_test_finished}" -eq 1 ]\ + && ex_pkg_state_test2 "${_epur_workdir}" "${_epur_pkg_name_rdepend}" finish\ + && rtl_get_var_unsafe \$_epur_force -u "${_epur_group_name}_FORCE"\ + && [ "${_epur_force}" != 1 ]; + then + rtl_lconcat "${_epur_rfinished}" "${_epur_pkg_name_rdepend}"; + + elif [ "${_epur_test_finished:-1}" -eq 0 ]\ + || ! ex_pkg_state_test2 "${_epur_workdir}" "${_epur_pkg_name_rdepend}" finish\ + || ( rtl_get_var_unsafe \$_epur_force -u "${_epur_group_name}_FORCE"\ + && [ "${_epur_force}" = 1 ] ); + then + rtl_lconcat \$_epur_pkg_names_new "${_epur_pkg_name_rdepend}"; + fi; + done; + fi; + done; + done; + + eval ${_epur_rdisabled}='$(rtl_uniq2 "${_epur_rdisabled}")'; + eval ${_epur_rfinished}='$(rtl_uniq2 "${_epur_rfinished}")'; + eval ${_epur_rnames}='$(rtl_uniq "${_epur_pkg_names_new}")'; + + return 0; +}; + +# vim:filetype=sh textwidth=0 diff --git a/subr.ex/ex_pkg_dispatch.subr b/subr.ex/ex_pkg_dispatch.subr new file mode 100644 index 00000000..19818e97 --- /dev/null +++ b/subr.ex/ex_pkg_dispatch.subr @@ -0,0 +1,407 @@ +# +# Copyright (c) 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Lucía Andrea Illanes Albornoz <lucia@luciaillanes.de> +# set +o errexit -o noglob -o nounset is assumed. +# + +# +# exp_pkg_dispatch_complete() - completes all disabled and finished packages +# @_dispatch_fn: top-level dispatch function name +# @_group_names: build group name(s) +# @_pkg_disabled: list of disabled packages +# @_pkg_finished: list of finished packages +# +# Returns: zero (0) on success, non-zero (>0) on failure. +# +exp_pkg_dispatch_complete() { + local _epdc_dispatch_fn="${1}" _epdc_group_name="${2}" _epdc_pkg_disabled="${3}" \ + _epdc_pkg_finished="${4}" \ + _epdc_pkg_name=""; + + for _epdc_pkg_name in ${_epdc_pkg_disabled}; do + "${_epdc_dispatch_fn}" disabled_pkg "${_epdc_group_name}" "${_epdc_pkg_name}"; + done; + for _epdc_pkg_name in ${_epdc_pkg_finished}; do + "${_epdc_dispatch_fn}" skipped_pkg "${_epdc_group_name}" "${_epdc_pkg_name}"; + done; + + return 0; +}; + +# +# exp_pkg_dispatch_expand_packages() - expand build group name to list of packages ordered and filtered according to dependency and restart constraints +# @_rdisabled: out reference to variable of disabled packages +# @_rfinished: out reference to variable of finished packages +# @_rnames: out reference to variable of package names +# @_checkfl: enable (1) or inhibit (0) dependency expansion +# @_forcefl: enable (1) or inhibit (0) forcibly rebuilding finished packages +# @_group_name: build group name +# @_restart: optional whitespace-separated list of package names to rebuild +# @_reversefl: unfold reverse dependencies (1) or dependencies (0) +# @_workdir: pathname to build-specific temporary directory +# +# Returns: zero (0) on success, non-zero (>0) on failure. +# +exp_pkg_dispatch_expand_packages() { + local _epdep_rdisabled="${1#\$}" _epdep_rfinished="${2#\$}" _epdep_rnames="${3#\$}" \ + _epdep_checkfl="${4}" _epdep_forcefl="${5}" _epdep_group_name="${6}" \ + _epdep_restart="${7}" _epdep_reversefl="${8}" _epdep_workdir="${9}" \ + _epdep_pkg_names=""; + + eval ${_epdep_rdisabled}=; + eval ${_epdep_rfinished}=; + eval ${_epdep_rnames}=; + + if rtl_get_var_unsafe \$_epdep_pkg_names -u "${_epdep_group_name}_PACKAGES"\ + && [ "${_epdep_pkg_names:+1}" = 1 ]; then + if [ "${_epdep_reversefl:-0}" -eq 0 ]; then + ex_pkg_unfold_depends \ + "${_epdep_rdisabled}" "${_epdep_rfinished}" \ + "${_epdep_rnames}" "${_epdep_checkfl}" "${_epdep_forcefl}" \ + "${_epdep_group_name}" "${_epdep_pkg_names}" \ + "${_epdep_restart}" 1 "${_epdep_workdir}"; + else + ex_pkg_unfold_rdepends \ + "${_epdep_rdisabled}" "${_epdep_rfinished}" \ + "${_epdep_rnames}" "${_epdep_group_name}" \ + "${_epdep_pkg_names}" "${_epdep_restart}" 1 \ + "${_epdep_workdir}" "recurse"; + fi; + fi; + + eval ${_epdep_rdisabled}='$(rtl_uniq2 "${_epdep_rdisabled}")'; + eval ${_epdep_rfinished}='$(rtl_uniq2 "${_epdep_rfinished}")'; + eval ${_epdep_rnames}='$(rtl_uniq2 "${_epdep_rnames}")'; + + return 0; +}; + +# +# exp_pkg_dispatch_group() - dispatch a single build group +# @_rdispatch_count: in reference to out variable of dispatcher count +# @_rdispatch_count_cur: in reference to out variable of current dispatcher count +# @_dispatch_count_max: maximum dispatcher count +# @_dispatch_group_cur: current group +# @_dispatch_group_max: maximum group +# @_rdispatch_njobs: in reference to out variable of dispatcher count +# @_rdispatch_wait: in reference to out variable of package names in a wait state +# @_rpkg_disabled: in reference to variable of list of disabled packages +# @_rpkg_finished: in reference to out variable of list of finished packages +# @_rpkg_names: in reference to out variable of list of package names +# @_build_steps_default: list of default build steps +# @_build_vars_default: list of default build variables +# @_checkfl: enable (1) or inhibit (0) dependency expansion +# @_continue_on_failfl: continue on failed package build (1) or break (0) +# @_dispatch_fn: top-level dispatch function name +# @_group_name: build group name +# @_njobs_max: maximum count of simultaneous jobs +# @_pipe_path: pathname to build FIFO +# @_restart_at: optional comma-separated list of build steps at which to rebuild or ALL or LAST +# @_workdir: pathname to build-specific temporary directory +# +# Returns: zero (0) on success, non-zero (>0) on failure. +# +exp_pkg_dispatch_group() { + local _epdg_rdispatch_count="${1#\$}" _epdg_rdispatch_count_cur="${2#\$}" _epdg_dispatch_count_max="${3#\$}" \ + _epdg_dispatch_group_cur="${4#\$}" _epdg_dispatch_group_max="${5#\$}" _epdg_rdispatch_njobs="${6#\$}" \ + _epdg_rdispatch_wait="${7#\$}" _epdg_rpkg_disabled="${8#\$}" _epdg_rpkg_finished="${9#\$}" \ + _epdg_rpkg_names="${10#\$}" _epdg_build_steps_default="${11}" _epdg_build_vars_default="${12}" \ + _epdg_checkfl="${13}" _epdg_continue_on_failfl="${14}" _epdg_dispatch_fn="${15}" \ + _epdg_group_name="${16}" _epdg_njobs_max="${17}" _epdg_pipe_path="${18}" _epdg_restart_at="${19}" \ + _epdg_workdir="${20}" \ + _epdg_perc_group=0 _epdg_perc_pkg=0 _epdg_pipe_msg="" _epdg_pkg_name="" _epdg_rc=0; + + rtl_fileop mkfifo "${_epdg_pipe_path}"; + while true; do + while eval [ \"\${${_epdg_rdispatch_njobs}:-0}\" -gt 0 ]\ + && read _epdg_pipe_msg; + do + + case "${_epdg_pipe_msg%% *}" in + + done) _epdg_pkg_name="${_epdg_pipe_msg#done * }"; + eval : '$(('${_epdg_rdispatch_count_cur}'+=1))'; + eval : '$(('${_epdg_rdispatch_njobs}'-=1))'; + + rtl_lconcat "${_epdg_rpkg_finished}" "${_epdg_pkg_name}"; + rtl_percentage2 \$_epdg_dispatch_group_cur \$_epdg_dispatch_group_max \$_epdg_perc_group; + rtl_percentage2 "${_epdg_rdispatch_count_cur}" \$_epdg_dispatch_count_max \$_epdg_perc_pkg; + + "${_epdg_dispatch_fn}" \ + finish_pkg ${_epdg_pipe_msg#done } \ + "${_epdg_dispatch_count_max}" \ + "${_epdg_perc_group}" "${_epdg_perc_pkg}"; + + rtl_lfilter "${_epdg_rpkg_names}" "${_epdg_pkg_name}"; + rtl_lfilter "${_epdg_rdispatch_wait}" "${_epdg_pkg_name}"; + + if eval [ \"\${${_epdg_rpkg_names}:+1}\" = 1 ]; then + if eval [ \"\${${_epdg_rdispatch_njobs}:-0}\" -ne \"\${_epdg_njobs_max}\" ]; then + exp_pkg_dispatch_packages \ + "${_epdg_rdispatch_count}" \ + "${_epdg_rdispatch_count_cur}" \ + "${_epdg_dispatch_count_max}" \ + "${_epdg_dispatch_group_cur}" \ + "${_epdg_dispatch_group_max}" \ + "${_epdg_rdispatch_njobs}" \ + "${_epdg_rdispatch_wait}" \ + "${_epdg_rpkg_disabled}" \ + "${_epdg_rpkg_finished}" "${_epdg_rpkg_names}" \ + "${_epdg_build_steps_default}" \ + "${_epdg_build_vars_default}" "${_epdg_checkfl}" \ + "${_epdg_dispatch_fn}" "${_epdg_group_name}" \ + "${_epdg_njobs_max}" "${_epdg_pipe_path}" \ + "${_epdg_restart_at}" "${_epdg_workdir}"; + fi; + elif eval [ \"\${${_epdg_rdispatch_njobs}:-0}\" -eq 0 ]; then + break; + fi; + ;; + + fail) _epdg_pkg_name="${_epdg_pipe_msg#fail * }"; + eval : '$(('${_epdg_rdispatch_njobs}'-=1))'; + _epdg_rc=1; + rtl_lfilter "${_epdg_rpkg_names}" "${_epdg_pkg_name}"; + "${_epdg_dispatch_fn}" \ + fail_pkg ${_epdg_pipe_msg#fail } \ + "${_epdg_dispatch_count_max}"; + + if [ "${_epdg_rc}" -ne 0 ]\ + && [ "${_epdg_continue_on_failfl}" -ne 1 ]; then + break; + fi; + ;; + + msg_pkg) + "${_epdg_dispatch_fn}" msg_pkg ${_epdg_pipe_msg#msg_pkg }; + ;; + + step) "${_epdg_dispatch_fn}" step_pkg ${_epdg_pipe_msg#step }; + ;; + + esac; done <>"${_epdg_pipe_path}"; + + if [ "${_epdg_rc}" -ne 0 ]\ + && [ "${_epdg_continue_on_failfl}" -ne 1 ]; then + break; + elif eval [ \"\${${_epdg_rpkg_names}:+1}\" = 1 ]; then + if eval [ \"\${${_epdg_rdispatch_njobs}:-0}\" -ne \"\${_epdg_njobs_max}\" ]; then + exp_pkg_dispatch_packages \ + "${_epdg_rdispatch_count}" \ + "${_epdg_rdispatch_count_cur}" \ + "${_epdg_dispatch_count_max}" \ + "${_epdg_dispatch_group_cur}" \ + "${_epdg_dispatch_group_max}" \ + "${_epdg_rdispatch_njobs}" \ + "${_epdg_rdispatch_wait}" \ + "${_epdg_rpkg_disabled}" \ + "${_epdg_rpkg_finished}" "${_epdg_rpkg_names}" \ + "${_epdg_build_steps_default}" \ + "${_epdg_build_vars_default}" "${_epdg_checkfl}" \ + "${_epdg_dispatch_fn}" "${_epdg_group_name}" \ + "${_epdg_njobs_max}" "${_epdg_pipe_path}" \ + "${_epdg_restart_at}" "${_epdg_workdir}"; + fi; + elif eval [ \"\${${_epdg_rdispatch_njobs}:-0}\" -eq 0 ]; then + break; + fi; + done; + + rtl_fileop rm "${_epdg_pipe_path}"; + + return "${_epdg_rc}"; +}; + +# +# exp_pkg_dispatch_packages() - dispatch set of packages +# @_rdispatch_count: in reference to out variable of dispatcher count +# @_dispatch_count_cur: current dispatcher count +# @_dispatch_count_max: maximum dispatcher count +# @_dispatch_group_cur: current group +# @_dispatch_group_max: maximum group +# @_rdispatch_njobs: in reference to out variable of dispatcher count +# @_rdispatch_wait: in reference to out variable of package names in a wait state +# @_rpkg_disabled: in reference to variable of list of disabled packages +# @_rpkg_finished: in reference to out variable of list of finished packages +# @_rpkg_names: in reference to out variable of list of package names +# @_build_steps_default: list of default build steps +# @_build_vars_default: list of default build variables +# @_checkfl: enable (1) or inhibit (0) dependency expansion +# @_dispatch_fn: top-level dispatch function name +# @_group_name: build group name +# @_njobs_max: maximum count of simultaneous jobs +# @_pipe_path: pathname to parent-child process FIFO +# @_restart_at: optional comma-separated list of build steps at which to rebuild or ALL or LAST +# @_workdir: pathname to build-specific temporary directory +# +# Returns: zero (0) on success, non-zero (>0) on failure. +# +exp_pkg_dispatch_packages() { + local _epdp2_rdispatch_count="${1#\$}" _epdp2_dispatch_count_cur="${2}" _epdp2_dispatch_count_max="${3}" \ + _epdp2_dispatch_group_cur="${4}" _epdp2_dispatch_group_max="${5}" _epdp2_rdispatch_njobs="${6#\$}" \ + _epdp2_rdispatch_wait="${7#\$}" _epdp2_rpkg_disabled="${8#\$}" _epdp2_rpkg_finished="${9#\$}" \ + _epdp2_rpkg_names="${10#\$}" _epdp2_build_steps_default="${11}" _epdp2_build_vars_default="${12}" \ + _epdp2_checkfl="${13}" _epdp2_dispatch_fn="${14}" _epdp2_group_name="${15}" _epdp2_njobs_max="${16}" \ + _epdp2_pipe_path="${17}" _epdp2_restart_at="${18}" _epdp2_workdir="${19}" \ + _epdp2_foundfl=0 _epdp2_njob=0 _epdp2_pkg_depends="" _epdp2_pkg_name=""; + + while eval [ \"\${${_epdp2_rdispatch_njobs}}\" -lt \"\${_epdp2_njobs_max}\" ]; do + _epdp2_foundfl=0; + eval _epdp2_pkg_names="\${${_epdp2_rpkg_names}}"; + for _epdp2_pkg_name in ${_epdp2_pkg_names}; do + if ! rtl_lmatch "${_epdp2_rdispatch_wait}" "${_epdp2_pkg_name}"\ + && ex_pkg_check_depends \ + "${_epdp2_checkfl}" "${_epdp2_rpkg_disabled}" \ + "${_epdp2_rpkg_finished}" "${_epdp2_pkg_name}" \ + "${_epdp2_rpkg_names}" "${_epdp2_workdir}"; + then + ex_pkg_exec \ + "${_epdp2_rdispatch_count}" \ + "${_epdp2_dispatch_count_cur}" "${_epdp2_dispatch_count_max}" \ + "${_epdp2_dispatch_group_cur}" "${_epdp2_dispatch_group_max}" \ + "${_epdp2_rdispatch_njobs}" "${_epdp2_rdispatch_wait}" \ + "${_epdp2_build_steps_default}" \ + "${_epdp2_build_vars_default}" "${_epdp2_dispatch_fn}" \ + "${_epdp2_group_name}" "${_epdp2_pipe_path}" \ + "${_epdp2_pkg_name}" "${_epdp2_restart_at}" \ + "${_epdp2_workdir}"; + _epdp2_foundfl=1; break; + fi; + done; + + if [ "${_epdp2_foundfl:-0}" -eq 0 ]; then + break; + fi; + done; + + return "${_epdp2_foundfl}"; +}; + +# +# ex_pkg_dispatch() - dispatch a set of build group +# @_rdispatch_wait: out reference to variable of package names in a wait state +# @_build_steps_default: list of default build steps +# @_build_vars_default: list of default build variables +# @_continue_on_failfl: continue on failed package build (1) or break (0) +# @_dispatch_fn: top-level dispatch function name +# @_group_names: build group name(s) +# @_groups_inhibit_deps: inhibit group-group dependency expansion +# @_njobs_max: maximum count of simultaneous jobs +# @_pipe_path: pathname to build FIFO +# @_restart: optional whitespace-separated list of package names to rebuild +# @_restart_at: optional comma-separated list of build steps at which to rebuild or ALL or LAST +# @_restart_recursive: optional flag specifiying either no dependency expansion (0,) dependency expansion (1,) dependency expansion and forcibly rebuild (2,) forcibly rebuild reverse dependencies (3.) +# @_workdir: pathname to build-specific temporary directory +# +# Returns: zero (0) on success, non-zero (>0) on failure. +# +ex_pkg_dispatch() { + local _epd_rdispatch_wait="${1#\$}" _epd_build_steps_default="${2}" _epd_build_vars_default="${3}" \ + _epd_continue_on_failfl="${4}" _epd_dispatch_fn="${5}" _epd_group_names="${6}" \ + _epd_groups_inhibit_deps="${7}" _epd_njobs_max="${8}" _epd_pipe_path="${9}" _epd_restart="${10}" \ + _epd_restart_at="${11}" _epd_restart_recursive="${12}" _epd_workdir="${13}" \ + _epd_checkfl=1 _epd_forcefl=0 _epd_perc_group=0 \ + _epd_pkg_disabled="" _epd_pkg_finished="" _epd_pkg_names="" _epd_pkg_name="" \ + _epd_pkg_dispatch_count=0 _epd_pkg_dispatch_count_cur=0 _epd_pkg_dispatch_count_max=0 \ + _epd_pkg_dispatch_group_cur=1 _epd_pkg_dispatch_group_max=0 \ + _epd_pkg_dispatch_njobs=0 \ + _epd_rc=0 _epd_reversefl=0; + + case "${_epd_groups_inhibit_deps:-0}" in + 0) rtl_lunfold_dependsV '${_rld_name}_GROUP_DEPENDS' \$_epd_group_names ${_epd_group_names}; + _epd_group_names="$(rtl_uniq2 \$_epd_group_names)"; + esac; + + if [ "${_epd_restart:+1}" = 1 ]; then + case "${_epd_restart_recursive:-0}" in + 0) _epd_checkfl=0; _epd_forcefl=0; _epd_reversefl=0; ;; + 1) _epd_checkfl=1; _epd_forcefl=0; _epd_reversefl=0; ;; + 2) _epd_checkfl=1; _epd_forcefl=1; _epd_reversefl=0; ;; + 3) _epd_checkfl=1; _epd_forcefl=1; _epd_reversefl=1; ;; + esac; + fi; + + rtl_llength \$_epd_pkg_dispatch_group_max \$_epd_group_names; + + for _epd_group_name in ${_epd_group_names}; do + _epd_pkg_disabled=""; + _epd_pkg_finished=""; + _epd_pkg_names=""; + eval ${_epd_rdispatch_wait}=; + _epd_pkg_dispatch_count=0; + _epd_pkg_dispatch_count_cur=0; + _epd_pkg_dispatch_count_max=0; + _epd_pkg_dispatch_njobs=0; + + rtl_percentage "${_epd_pkg_dispatch_group_cur}" "${_epd_pkg_dispatch_group_max}" \$_epd_perc_group; + + if "${_epd_dispatch_fn}" \ + start_group "${_epd_group_name}" \ + "" "${_epd_pkg_dispatch_group_cur}" \ + "${_epd_pkg_dispatch_group_max}" \ + "${_epd_perc_group}"; + then + if rtl_fileop mkdir "${_epd_workdir}"\ + && rtl_log_msgV "verbose" "${MSG_build_resolving_deps}" "${_epd_group_name}"\ + && exp_pkg_dispatch_expand_packages \ + \$_epd_pkg_disabled \$_epd_pkg_finished \ + \$_epd_pkg_names "${_epd_checkfl}" \ + "${_epd_forcefl}" "${_epd_group_name}" \ + "${_epd_restart}" "${_epd_reversefl}" \ + "${_epd_workdir}" \ + && exp_pkg_dispatch_complete \ + "${_epd_dispatch_fn}" "${_epd_group_name}" \ + "${_epd_pkg_disabled}" "${_epd_pkg_finished}" \ + && rtl_log_msgV "verbose" "${MSG_build_resolved_deps}" "${_epd_group_name}"\ + && rtl_llength \$_epd_pkg_dispatch_count_max \$_epd_pkg_names\ + && [ "${_epd_pkg_dispatch_count_max}" -gt 0 ]; + then + exp_pkg_dispatch_group \ + \$_epd_pkg_dispatch_count \$_epd_pkg_dispatch_count_cur \ + "${_epd_pkg_dispatch_count_max}" \ + "${_epd_pkg_dispatch_group_cur}" "${_epd_pkg_dispatch_group_max}" \ + \$_epd_pkg_dispatch_njobs "${_epd_rdispatch_wait}" \ + \$_epd_pkg_disabled \$_epd_pkg_finished \$_epd_pkg_names \ + "${_epd_build_steps_default}" "${_epd_build_vars_default}" \ + "${_epd_checkfl}" "${_epd_continue_on_failfl}" "${_epd_dispatch_fn}" \ + "${_epd_group_name}" "${_epd_njobs_max}" "${_epd_pipe_path}" \ + "${_epd_restart_at}" "${_epd_workdir}"; + _epd_rc="${?}"; + fi; + + : $((_epd_pkg_dispatch_group_cur+=1)); + rtl_percentage "${_epd_pkg_dispatch_group_cur}" "${_epd_pkg_dispatch_group_max}" \$_epd_perc_group; + + "${_epd_dispatch_fn}" \ + finish_group "${_epd_group_name}" \ + "" "${_epd_pkg_dispatch_group_cur}" \ + "${_epd_pkg_dispatch_group_max}" \ + "${_epd_perc_group}"; + if [ "${_epd_rc}" -ne 0 ]; then + break; + fi; + fi; + done; + + return "${_epd_rc}"; +}; + +# +# ex_pkg_dipatch_send() - send message from dispatcher child process to dispatcher parent process across FIFO +# @_op: message operation string +# +# Returns: zero (0) invariably. +# +ex_pkg_dispatch_send() { + local _epds_op="${1}"; + shift 1; + + trap '' PIPE; + while ! printf "%s%s\n" "${_epds_op}" "${*:+ "${*}"}" 1>&3 2>/dev/null; do + :; + done; + trap - PIPE; + + return 0; +}; + +# vim:filetype=sh textwidth=0 diff --git a/subr.ex/ex_pkg_env.subr b/subr.ex/ex_pkg_env.subr new file mode 100644 index 00000000..7c4d7daf --- /dev/null +++ b/subr.ex/ex_pkg_env.subr @@ -0,0 +1,195 @@ +# +# Copyright (c) 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Lucía Andrea Illanes Albornoz <lucia@luciaillanes.de> +# set +o errexit -o noglob -o nounset is assumed. +# +# Package variable and environment variable preparation +# Package build (step) state setting and testing +# + +# +# exp_pkg_env_defaults() - set package variable defaults for single named package +# @_build_steps_default: list of default build steps +# @_pkg_name: single package name +# @_workdir: pathname to build-specific temporary directory +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +exp_pkg_env_defaults() { + local _epped_build_steps_default="${1}" _epped_pkg_name="${2}" _epped_workdir="${3}"; + + : ${PKG_NAME:="${_epped_pkg_name}"}; + : ${MIDIPIX_BUILD_PWD:="$(pwd)"}; + : ${PKG_BASE_DIR:="${_epped_workdir}/${_epped_pkg_name}-${PKG_BUILD_TYPE}-${PKG_TARGET}"}; + + if [ "${PKG_BUILD_STEPS_DISABLE:+1}" = 1 ]; then + rtl_lfilter2 \$_epped_build_steps_default \$PKG_BUILD_STEPS "${PKG_BUILD_STEPS_DISABLE:-}"; + else + : ${PKG_BUILD_STEPS:="${_epped_build_steps_default}"}; + fi; + + if [ "${PKG_URL:+1}" = 1 ]; then + : ${PKG_FNAME:="${PKG_URL##*/}"}; + fi; + + if [ "${PKG_SUBDIR:+1}" != 1 ]; then + if [ "${PKG_URLS_GIT:+1}" = 1 ]\ + && [ "${PKG_FNAME:+1}" = 1 ]; then + rtl_log_msgV "fatalexit" "${MSG_pkg_fail_missing_vars}"; + elif [ "${PKG_URLS_GIT:+1}" = 1 ]; then + PKG_SUBDIR="${PKG_URLS_GIT%%=*}"; + else case "${PKG_FNAME:-}" in + *.t*) PKG_SUBDIR="${PKG_FNAME%%.t*}"; ;; + *) PKG_SUBDIR="${_epped_pkg_name}"; ;; + esac; fi; + fi; + + if [ "${PKG_BUILD_DIR:+1}" != 1 ]; then + case "${PKG_IN_TREE:-0}" in + 0) PKG_BUILD_DIR="obj"; ;; + 1) PKG_BUILD_DIR="${PKG_SUBDIR}"; ;; + esac; + fi; + + PKG_BUILD_DIR="${PKG_BASE_DIR}/${PKG_BUILD_DIR}"; + PKG_CONFIGURE="${PKG_BASE_DIR}/${PKG_CONFIGURE:-${PKG_SUBDIR}/configure}"; + PKG_DESTDIR="${PKG_BASE_DIR}/${PKG_DESTDIR:-destdir}"; + PKG_DESTDIR_HOST="${PKG_BASE_DIR}/${PKG_DESTDIR_HOST:-destdir_host}"; + + return 0; +}; + +# +# exp_pkg_env_set() - set package variables for single named package +# @_build_vars_default: list of default build variables +# @_group_name: build group name +# @_pkg_name: single package name +# +# Sets package variables from either defaults, defaults specific to build type, +# build group, package to inherit from if any, or package for a single named +# package, and exports variables optionally named in ${PKG_ENV_VARS_EXTRA}. +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +exp_pkg_env_set() { + local _eppes_build_vars_default="${1}" _eppes_group_name="${2}" _eppes_pkg_name="${3}" \ + _eppes_lvars="" _eppes_var_prefixes="" _eppes_vars_set="" \ + _eppes_vars_unset="" _eppes_vname="" _eppes_vnames="" IFS IFS0; + + rtl_set_var _eppes_vars_set BUILD_TYPE "DEFAULT ${_eppes_group_name} PKG_${_eppes_pkg_name}"; + rtl_set_var _eppes_vars_set INHERIT_FROM "PKG_${_eppes_pkg_name}"; + _eppes_var_prefixes="DEFAULT DEFAULT_${PKG_BUILD_TYPE} ${_eppes_group_name}"; + rtl_toupper \$_eppes_var_prefixes; + rtl_lfilter2 \$_eppes_build_vars_default \$_eppes_vnames BUILD_TYPE; + + for _eppes_vname in ${_eppes_vnames}; do + if [ "${PKG_INHERIT_FROM:+1}" = 1 ]; then + _eppes_lvars="PKG_${PKG_INHERIT_FROM} PKG_${PKG_INHERIT_FROM}_${BUILD_KIND} PKG_${_eppes_pkg_name} PKG_${_eppes_pkg_name}_${BUILD_KIND}"; + rtl_toupper \$_eppes_lvars; + rtl_lconcat2 \$_eppes_lvars \$_eppes_var_prefixes "${_eppes_lvars}"; + rtl_set_var _eppes_vars_set "${_eppes_vname}" "${_eppes_lvars}"; + else + _eppes_lvars="PKG_${_eppes_pkg_name} PKG_${_eppes_pkg_name}_${BUILD_KIND}"; + rtl_toupper \$_eppes_lvars; + rtl_lconcat2 \$_eppes_lvars \$_eppes_var_prefixes "${_eppes_lvars}"; + rtl_set_var _eppes_vars_set "${_eppes_vname}" "${_eppes_lvars}"; + fi; + done; + + IFS0="${IFS:- }"; IFS=":"; for _eppes_vname in ${PKG_ENV_VARS_EXTRA:-}; do + export "${_eppes_vname}"; + done; IFS="${IFS0}"; + + return 0; +}; + +# +# ex_pkg_env() - set package variables for single named package +# @_build_steps_default: list of default build steps +# @_build_vars_default: list of default build variables +# @_group_name: build group name +# @_pkg_name: single package name +# @_restart_at: optional comma-separated list of build steps at which to rebuild or ALL or LAST +# @_workdir: pathname to build-specific temporary directory +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +ex_pkg_env() { + local _epe_build_steps_default="${1}" _epe_build_vars_default="${2}" \ + _epe_group_name="${3}" _epe_pkg_name="${4}" _epe_restart_at="${5}" \ + _epe_workdir="${6}" \ + _epe_file_idx=0 _epe_inherit_from="" _epe_pkg_version="" \ + _epe_vars_file="" _epe_vars_file_parent="" _epe_vname=""; + + if rtl_get_var_unsafe \$_epe_inherit_from -u "PKG_${_epe_pkg_name}_INHERIT_FROM"\ + && [ "${_epe_inherit_from:+1}" = 1 ]; then + rtl_get_var_unsafe \$_epe_vars_file_parent -u "PKG_${_epe_inherit_from}_VARS_FILE"; + rtl_get_var_unsafe \$_epe_vars_file -u "PKG_${_epe_pkg_name}_VARS_FILE"; + if [ "${_epe_vars_file:+1}" != 1 ]; then + _epe_vars_file="${_epe_vars_file_parent}"; + fi; + else + rtl_get_var_unsafe \$_epe_vars_file -u "PKG_${_epe_pkg_name}_VARS_FILE"; + fi; + + if [ "${_epe_vars_file:+1}" != 1 ]; then + rtl_get_var_unsafe \$_epe_pkg_version -u "PKG_${_epe_pkg_name}_VERSION"; + _epe_file_idx=1; + while ex_pkg_get_default \ + \$_epe_vars_file "${_epe_file_idx}" \ + "${_epe_pkg_name}" \ + "${_epe_pkg_version}" \ + "vars_files" \ + && [ "${_epe_vars_file:+1}" = 1 ]; + do + : $((_epe_file_idx += 1)); + rtl_fileop source_opt "${_epe_vars_file}"; + done; + else + rtl_fileop source_opt \ + "${_epe_vars_file}"; + fi; + + if ! exp_pkg_env_set "${_epe_build_vars_default}" "${_epe_group_name}" "${_epe_pkg_name}"\ + || ! exp_pkg_env_defaults "${_epe_build_steps_default}" "${_epe_pkg_name}" "${_epe_workdir}"; then + return 1; + fi; + + return 0; +}; + +# +# ex_pkg_state_set() - update build step status for single named package +# @_pkg_name: single package name +# @_build_step: build step set status of +# @...: optional list of build steps to invalidate status of +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +ex_pkg_state_set() { + rtl_state_set "${BUILD_WORKDIR}" "${@}"; +}; + + +ex_pkg_state_set2() { + local _epss2_workdir="${1}"; shift; + rtl_state_set "${_epss2_workdir}" "${@}"; +}; + +# +# ex_pkg_state_test() - test build step status of single named package +# @_pkg_name: single package name +# @_build_step: build step to test status of +# @_restart_at: optional comma-separated list of build steps at which to rebuild or ALL or LAST +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +ex_pkg_state_test() { + rtl_state_test "${BUILD_WORKDIR}" "${@}"; +}; + +ex_pkg_state_test2() { + local _epst2_workdir="${1}"; shift; + rtl_state_test "${_epst2_workdir}" "${@}"; +}; + +# vim:filetype=sh textwidth=0 diff --git a/subr.ex/ex_pkg_exec.subr b/subr.ex/ex_pkg_exec.subr new file mode 100644 index 00000000..e2b3ba0d --- /dev/null +++ b/subr.ex/ex_pkg_exec.subr @@ -0,0 +1,223 @@ +# +# Copyright (c) 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Lucía Andrea Illanes Albornoz <lucia@luciaillanes.de> +# set +o errexit -o noglob -o nounset is assumed. +# + +# +# exp_pkg_exec_pre() - prepare environment for single named package w/ dispatcher +# @_dispatch_fn: top-level dispatch function name +# @_group_name: build group name +# @_pkg_name: single package name +# @_restart_at: optional comma-separated list of build steps at which to rebuild or ALL or LAST +# @_workdir: pathname to build-specific temporary directory +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +exp_pkg_exec_pre() { + local _eppep_dispatch_fn="${1}" _eppep_group_name="${2}" _eppep_pkg_name="${3}" \ + _eppep_restart_at="${4}" _eppep_workdir="${5}"; + + if [ "${PKG_URL:+1}" != 1 ]\ + && [ "${PKG_URLS_GIT:+1}" != 1 ]\ + && [ "${PKG_VERSION:+1}" != 1 ]\ + && [ "${PKG_INSTALL_FILES:+1}" != 1 ]\ + && [ "${PKG_INSTALL_FILES_V2:+1}" != 1 ]\ + && ! rtl_test_cmd "pkg_${_eppep_pkg_name}_all"; + then + "${_eppep_dispatch_fn}" missing_pkg "${_eppep_group_name}" "${_eppep_pkg_name}"; + return 1; + elif ! ex_pkg_state_test2 \ + "${_eppep_workdir}" \ + "${_eppep_pkg_name}" "start" \ + "${_eppep_restart_at}"; + then + if [ "${PKG_NO_CLEAN_BASE_DIR:-0}" -eq 0 ]\ + && ! rtl_fileop rm "${PKG_BASE_DIR}" "${PKG_BUILD_DIR}" "${PKG_DESTDIR}" "${PKG_DESTDIR_HOST}"\ + || ! rtl_fileop mkdir "${PKG_BASE_DIR}"; + then + return 1; + fi; + + if ! rtl_fileop mkdir "${PKG_BUILD_DIR}" "${PKG_DESTDIR}"\ + || ! ex_pkg_state_set2 "${_eppep_workdir}" "${_eppep_pkg_name}" "start"; + then + return 1; + fi; + elif ! rtl_exists_any "${PKG_BASE_DIR}" "${PKG_BUILD_DIR}" "${PKG_DESTDIR}" "${PKG_DESTDIR_HOST}"\ + && ! rtl_fileop mkdir "${PKG_BASE_DIR}" "${PKG_BUILD_DIR}" "${PKG_DESTDIR}" "${PKG_DESTDIR_HOST}"; + then + return 1 + fi; + + rtl_fileop cd "${PKG_BUILD_DIR}"; + return "${?}"; +}; + +# +# exp_pkg_exec_step() - execute single build steps & update state for single named package w/ dispatcher +# @_group_name: build group name +# @_pkg_name: single package name +# @_restart_at: optional comma-separated list of build steps at which to rebuild or ALL or LAST +# @_step: build step to execute +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +exp_pkg_exec_step() { + local _eppes_group_name="${1}" _eppes_pkg_name="${2}" _eppes_restart_at="${3}" \ + _eppes_step="${4}" \ + _eppes_fn_name="" _eppes_pkg_step_fn="" _eppes_rc=0; + + if rtl_test_cmd "pkg_${_eppes_pkg_name}_${_eppes_step}"; then + _eppes_pkg_step_fn="pkg_${_eppes_pkg_name}_${_eppes_step}"; + else + _eppes_pkg_step_fn="pkg_${_eppes_step}"; + fi; + + for _eppes_fn_name in \ + "pkg_${_eppes_pkg_name}_${_eppes_step}_pre" \ + "${_eppes_pkg_step_fn}" \ + "pkg_${_eppes_pkg_name}_${_eppes_step}_post"; + do + if rtl_test_cmd "${_eppes_fn_name}"\ + && ! "${_eppes_fn_name}" \ + "${_eppes_group_name}" "${_eppes_pkg_name}" \ + "${_eppes_restart_at}"; + then + _eppes_rc=1; break; + fi; + done; + + return "${_eppes_rc}"; +}; + +# +# exp_pkg_exec() - execute all pertaining build steps & update state for single named package w/ dispatcher +# @_dispatch_fn: top-level dispatch function name +# @_group_name: build group name +# @_pkg_name: single package name +# @_restart_at: optional comma-separated list of build steps at which to rebuild or ALL or LAST +# @_workdir: pathname to build-specific temporary directory +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +exp_pkg_exec() { + local _eppe_dispatch_fn="${1}" _eppe_group_name="${2}" _eppe_pkg_name="${3}" \ + _eppe_restart_at="${4}" _eppe_workdir="${5}" \ + _eppe_build_step_last="" _eppe_rc=0 _eppe_step=""; + + if ! exp_pkg_exec_pre \ + "${_eppe_dispatch_fn}" \ + "${_eppe_group_name}" "${_eppe_pkg_name}" \ + "${_eppe_restart_at}" "${_eppe_workdir}" \ + || ! "${_eppe_dispatch_fn}" \ + start_pkg_child "${_eppe_group_name}" \ + "${_eppe_pkg_name}"; + then + _eppe_rc=1; + elif rtl_test_cmd "pkg_${_eppe_pkg_name}_all"; then + "pkg_${_eppe_pkg_name}_all" \ + "${_eppe_group_name}" "${_eppe_pkg_name}" \ + "${_eppe_restart_at}"; + _eppe_rc="${?}"; + else + set -- ${PKG_BUILD_STEPS}; + while [ ${#} -gt 0 ]; do + _eppe_step="${1}"; shift; + + if [ "${#_eppe_restart_at}" -gt 0 ]\ + && [ "${_eppe_restart_at}" != "ALL" ]\ + && [ "${_eppe_restart_at}" != "LAST" ]\ + && ! rtl_lmatch \$_eppe_restart_at "${_eppe_step}" ","; then + continue; + fi; + + if [ "${_eppe_step}" = "finish" ]; then + ex_pkg_state_set2 "${_eppe_workdir}" "${_eppe_pkg_name}" finish; break; + elif [ "${PKG_FORCE:-0}" -eq 0 ]\ + && ex_pkg_state_test2 "${_eppe_workdir}" "${_eppe_pkg_name}" "${_eppe_step}" "${_eppe_restart_at}"; + then + continue; + elif ! exp_pkg_exec_step \ + "${_eppe_group_name}" "${_eppe_pkg_name}" \ + "${_eppe_restart_at}" "${_eppe_step}"; + then + _eppe_rc=1; break; + else ex_pkg_dispatch_send "step" "${_eppe_group_name}" "${_eppe_pkg_name}" "${_eppe_step}"; + ex_pkg_state_set2 "${_eppe_workdir}" "${_eppe_pkg_name}" "${_eppe_step}" "${@}"; + fi; + done; + fi; + + return "${_eppe_rc}"; +}; + +# +# ex_pkg_exec() - prepare environment for, execute all pertaining build steps & update state for single named package w/ dispatcher +# @_rdispatch_count: reference to inout variable of dispatcher count +# @_dispatch_count_cur: current dispatcher count +# @_dispatch_count_max: maximum dispatcher count +# @_dispatch_group_cur: current group +# @_dispatch_group_max: maximum group +# @_rdispatch_njobs: reference to inout variable of dispatcher count +# @_rdispatch_wait: reference to inout variable of package names in a wait state +# @_build_steps_default: list of default build steps +# @_build_vars_default: list of default build variables +# @_dispatch_fn: top-level dispatch function name +# @_group_name: build group name +# @_pipe_path: pathname to parent-child process FIFO +# @_pkg_name: single package name +# @_restart_at: optional comma-separated list of build steps at which to rebuild or ALL or LAST +# @_workdir: pathname to build-specific temporary directory +# +# Returns: zero (0) on success, non-zero (>0) on failure. +# +ex_pkg_exec() { + local _epdp_rdispatch_count="${1#\$}" _epdp_dispatch_count_cur="${2}" _epdp_dispatch_count_max="${3}" \ + _epdp_dispatch_group_cur="${4}" _epdp_dispatch_group_max="${5}" _epdp_rdispatch_njobs="${6#\$}" \ + _epdp_rdispatch_wait="${7#\$}" _epdp_build_steps_default="${8}" _epdp_build_vars_default="${9}" \ + _epdp_dispatch_fn="${10}" _epdp_group_name="${11}" _epdp_pipe_path="${12}" _epdp_pkg_name="${13}" \ + _epdp_restart_at="${14}" _epdp_workdir="${15}" \ + _epdp_dispatch_count_new=0 _epdp_perc_group=0 _epdp_perc_pkg=0; + + rtl_percentage2 \$_epdp_dispatch_group_cur \$_epdp_dispatch_group_max \$_epdp_perc_group; + rtl_percentage2 \$_epdp_dispatch_count_cur \$_epdp_dispatch_count_max \$_epdp_perc_pkg; + + eval _epdp_dispatch_count_new='$((${'"${_epdp_rdispatch_count}"'}+1))'; + if "${_epdp_dispatch_fn}" \ + start_pkg "${_epdp_group_name}" \ + "${_epdp_pkg_name}" \ + "${_epdp_dispatch_count_new}" \ + "${_epdp_dispatch_count_max}" \ + "${_epdp_perc_group}" "${_epdp_perc_pkg}"; + then + eval : '$(('${_epdp_rdispatch_njobs}'+=1))'; + eval ${_epdp_rdispatch_count}=\"\${_epdp_dispatch_count_new}\"; + rtl_lconcat "${_epdp_rdispatch_wait}" "${_epdp_pkg_name}"; + + (trap "if [ \${?} -eq 0 ]; then \ + ex_pkg_dispatch_send \"done\" \"${_epdp_group_name}\" \"${_epdp_pkg_name}\" \"${_epdp_dispatch_count_new}\"; \ + else \ + ex_pkg_dispatch_send \"fail\" \"${_epdp_group_name}\" \"${_epdp_pkg_name}\" \"${_epdp_dispatch_count_new}\"; \ + pkill -U "${$}"; \ + fi;" EXIT HUP INT TERM USR1 USR2; + set +o errexit -o noglob -o nounset; BUILD_IS_PARENT=0; rtl_log_set_fname ""; rtl_log_set_no_attr 1; + + if ex_pkg_env \ + "${_epdp_build_steps_default}" "${_epdp_build_vars_default}" \ + "${_epdp_group_name}" "${_epdp_pkg_name}" \ + "${_epdp_restart_at}" "${_epdp_workdir}"; + then + exp_pkg_exec \ + "${_epdp_dispatch_fn}" "${_epdp_group_name}" \ + "${_epdp_pkg_name}" "${_epdp_restart_at}" \ + "${_epdp_workdir}"; + else + return 1; + fi;) 1>"${_epdp_workdir}/${_epdp_pkg_name}_stderrout.log" 2>&1 3>"${_epdp_pipe_path}" & + return "${?}"; + else + return 1; + fi; +}; + +# vim:filetype=sh textwidth=0 diff --git a/subr.ex/ex_pkg_restart.subr b/subr.ex/ex_pkg_restart.subr new file mode 100644 index 00000000..a0cf220e --- /dev/null +++ b/subr.ex/ex_pkg_restart.subr @@ -0,0 +1,324 @@ +# +# Copyright (c) 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Lucía Andrea Illanes Albornoz <lucia@luciaillanes.de> +# set +o errexit -o noglob -o nounset is assumed. +# + +# +# exp_pkg_check_restart_at() - check restart (-r) specification for unknown build steps +# @_rstatus: out reference to status string +# @_rspec_at: in reference to restart build step list +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +exp_pkg_check_restart_at() { + local _epcra_rstatus="${1#\$}" _epcra_rspec_at="${2#\$}" \ + _epcra_len=0 _epcra_rc=0 _epcra_spec_at=""; + + if ! rtl_llift2 "${_epcra_rspec_at}" \$_epcra_spec_at "," " "\ + || ! rtl_lfilter \$_epcra_spec_at "${DEFAULT_BUILD_STEPS} ALL LAST"\ + || ! rtl_llength \$_epcra_spec_at \$_epcra_len; then + _epcra_rc=1; + elif [ "${_epcra_len}" -gt 0 ]; then + _epcra_rc=1; + rtl_setrstatus "${_epcra_rstatus}" 'unknown build step(s) \`'"${_epcra_spec_at}"''\'''; + fi; + + return "${_epcra_rc}"; +}; + +# +# exp_pkg_expand_restart_at_spec() - expand list of virtual build steps and list of build steps into list of build steps w/ operator subspecifications and virtual build steps expanded +# @_rstatus: out reference to status string +# @_rset: in reference to restart virtual build step set +# @_rspec_at: inout reference to restart build step list +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +exp_pkg_expand_restart_at_spec() { + local _eperas_rstatus="${1#\$}" _eperas_rset="${2#\$}" _eperas_rspec_at="${3#\$}" \ + _eperas_at="" _eperas_rc=0 _eperas_spec_at="" _eperas_spec_at_=""; + eval _eperas_spec_at='${'"${_eperas_rspec_at}"'}'; + + case "${_eperas_spec_at}" in + ALL|LAST|"") + ;; + + ^*) + _eperas_spec_at="${_eperas_spec_at#^}"; + if exp_pkg_expand_restart_at_virtual \ + "${_eperas_rstatus}" \ + "${_eperas_spec_at}" \$_eperas_spec_at \ + "${_eperas_rset}" \ + && exp_pkg_check_restart_at "${_eperas_rstatus}" \$_eperas_spec_at; + then + rtl_llift2 \$DEFAULT_BUILD_STEPS "${_eperas_rspec_at}" " " ","; + rtl_llift2 \$_eperas_spec_at \$_eperas_spec_at_ "," " "; + for _eperas_at in ${_eperas_spec_at_}; do + rtl_lfilter "${_eperas_rspec_at}" "${_eperas_at}" ","; + done; rtl_lfilter "${_eperas_rspec_at}" "finish" ","; + else + _eperas_rc=1; + fi; ;; + + \<=*|\<*|\>=*|\>*) + exp_pkg_expand_restart_at_spec_cmp \ + "${_eperas_rstatus}" \ + "${_eperas_rset}" "${_eperas_rspec_at}"; + _eperas_rc="${?}"; ;; + + *) + if ! exp_pkg_expand_restart_at_virtual \ + "${_eperas_rstatus}" \ + "${_eperas_spec_at}" "${_eperas_rspec_at}" \ + "${_eperas_rset}"; then + _eperas_rc=1; + fi; ;; + esac; + + if [ "${_eperas_rc}" -eq 0 ]; then + if ! exp_pkg_check_restart_at "${_eperas_rstatus}" "${_eperas_rspec_at}"; then + _epprs_rc=1; + elif eval [ '"${'"${_eperas_rspec_at}"':+1}"' != 1 ]; then + _epprs_rc=1; + rtl_setrstatus "${_eperas_rstatus}" 'zero-length build step list'; + fi; + fi; + + return "${_eperas_rc}"; +}; + +# +# exp_pkg_expand_restart_at_spec_cmp() - expand list of virtual build steps and list of build steps into list of build steps w/ operator subspecifications expanded +# @_rstatus: out reference to status string +# @_rset: in reference to restart virtual build step set +# @_rspec_at: inout reference to restart build step list +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +exp_pkg_expand_restart_at_spec_cmp() { + local _eperasc_rstatus="${1#\$}" _eperasc_rset="${2#\$}" _eperasc_rspec_at="${3#\$}" \ + _eperasc_at="" _eperasc_eqfl="" _eperasc_foundfl="" _eperasc_ltfl="" _eperasc_rc=0 \ + _eperasc_spec_at="" _eperasc_spec_at0=""; + eval _eperasc_spec_at0='${'"${_eperasc_rspec_at}"'}'; + + [ "${_eperasc_spec_at0#<}" = "${_eperasc_spec_at0}" ]; _eperasc_ltfl="${?}"; + if [ "${_eperasc_spec_at0#[<>]=}" != "${_eperasc_spec_at0}" ]; then + _eperasc_spec_at0="${_eperasc_spec_at0#[<>]=}"; _eperasc_eqfl=1; + else + _eperasc_spec_at0="${_eperasc_spec_at0#[<>]}"; _eperasc_eqfl=0; + fi; _eperasc_spec_at=""; + + if exp_pkg_expand_restart_at_virtual \ + "${_eperasc_rstatus}" \ + "${_eperasc_spec_at0%%,*}" \$_eperasc_spec_at0 \ + "${_eperasc_rset}" \ + && exp_pkg_check_restart_at "${_eperasc_rstatus}" \$_eperasc_spec_at0; then + if [ "${_eperasc_eqfl}" -eq 1 -a "${_eperasc_ltfl}" -eq 1 ]\ + || [ "${_eperasc_eqfl}" -eq 0 -a "${_eperasc_ltfl}" -eq 0 ]; then + _eperasc_spec_at0="${_eperasc_spec_at0##*,}"; + elif [ "${_eperasc_eqfl}" -eq 1 -a "${_eperasc_ltfl}" -eq 0 ]\ + || [ "${_eperasc_eqfl}" -eq 0 -a "${_eperasc_ltfl}" -eq 1 ]; then + _eperasc_spec_at0="${_eperasc_spec_at0%%,*}"; + fi; + + _eperasc_foundfl=0; for _eperasc_at in ${DEFAULT_BUILD_STEPS}; do + if [ "${_eperasc_ltfl}" -eq 1 ]; then + if [ "${_eperasc_at}" = "${_eperasc_spec_at0%%,*}" ]; then + if [ "${_eperasc_eqfl}" -eq 1 ]; then + _eperasc_spec_at="${_eperasc_spec_at:+${_eperasc_spec_at},}${_eperasc_at}"; + fi; break; + fi; + else + if [ "${_eperasc_at}" = "${_eperasc_spec_at0%%,*}" ]; then + _eperasc_foundfl=1; [ "${_eperasc_eqfl}" -eq 0 ] && continue; + fi; [ "${_eperasc_foundfl}" -eq 0 ] && continue; + fi; + _eperasc_spec_at="${_eperasc_spec_at:+${_eperasc_spec_at},}${_eperasc_at}"; + done; + else + _eperasc_rc=1; + fi; + + eval ${_eperasc_rspec_at}='${_eperasc_spec_at}'; + return "${_eperasc_rc}"; +}; + +# +# exp_pkg_expand_restart_at_virtual() - expand list of build steps into list of build steps w/ expansion of virtual build steps +# @_rstatus: out reference to status string +# @_spec_at: restart build step list +# @_rspec_at_new: out reference to new restart build step list +# @_rset: in reference to restart virtual build step set +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +exp_pkg_expand_restart_at_virtual() { + local _epera_rstatus="${1#\$}" _epera_spec_at="${2}" _epera_rspec_at_new="${3#\$}" \ + _epera_rset="${4#\$}" \ + _epera_at="" _epera_IFS0="${IFS:- }" _epera_rc=0 _epera_spec_at_new="" \ + IFS; + + eval ${_epera_rspec_at_new}=; + IFS=","; set -- ${_epera_spec_at}; IFS="${_epera_IFS0}"; + while [ "${#}" -gt 0 ]; do + _epera_at="${1}"; shift; + if [ "${_epera_at#@}" != "${_epera_at}" ]; then + _epera_at="${_epera_at#@}"; + if [ "${_epera_at%[!0-9a-zA-Z_]*}" != "${_epera_at}" ]; then + _epera_rc=1; + rtl_setrstatus "${_epera_rstatus}" 'invalid virtual build step \`'"${_epera_at}"''\'''; + elif eval [ '"${'"${_epera_rset}${_epera_at}"':+1}"' = 1 ]; then + eval _epera_at='${'"${_epera_rset}${_epera_at}"'}'; + else + _epera_rc=1; + rtl_setrstatus "${_epera_rstatus}" 'unknown virtual build step \`'"${_epera_at}"''\'''; + fi; + fi; + eval ${_epera_rspec_at_new}='${'"${_epera_rspec_at_new}"':+${'"${_epera_rspec_at_new}"'},}${_epera_at}'; + done; + + return "${_epera_rc}"; +}; + +# +# exp_pkg_expand_restart_recursive() - expand restart (-r) specification into recursion flag +# @_rspec: inout reference to restart {specification,package name list} +# @_rrecursive: out reference to recursion flag +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +exp_pkg_expand_restart_recursive() { + local _eperr_rspec="${1#\$}" _eperr_rrecursive="${2#\$}" _eperr_spec=""; + eval _eperr_spec='${'"${_eperr_rspec}"'}'; + + case "${_eperr_spec}" in + + \*\*\*[a-zA-Z]*) + eval ${_eperr_rspec}='${_eperr_spec#\*\*\*}' ${_eperr_rrecursive}=3; ;; + \*\*[a-zA-Z]*) eval ${_eperr_rspec}='${_eperr_spec#\*\*}' ${_eperr_rrecursive}=2; ;; + \*[a-zA-Z]*) eval ${_eperr_rspec}='${_eperr_spec#\*}' ${_eperr_rrecursive}=1; ;; + ALL) eval ${_eperr_rrecursive}=2; ;; + LAST) eval ${_eperr_rrecursive}=0; ;; + + esac; + + return 0; +}; + +# +# exp_pkg_expand_restart_spec() - expand restart (-r) specification into list of build steps +# @_rstatus: out reference to status string +# @_rspec: inout reference to restart {specification,package name list} +# @_rspec_at: out reference to restart build step list +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +exp_pkg_expand_restart_spec() { + local _epers_rstatus="${1#\$}" _epers_rspec="${2#\$}" _epers_rspec_at="${3#\$}" \ + _epers_last_pkg="" _epers_rc=0 _epers_spec="" _epers_spec_at="" _epers_spec_at0=""; + eval _epers_spec='${'"${_epers_rspec}"'}'; + + case "${_epers_spec}" in + "") eval ${_epers_rspec_at}=; ;; + ALL) eval ${_epers_rspec_at}=ALL; ;; + LAST|LAST:*) + case "${_epers_spec}" in + LAST) eval ${_epers_rspec_at}=LAST; ;; + LAST:*) eval ${_epers_rspec_at}='${_epers_spec#LAST:}'; ;; + esac; + if [ "${DEFAULT_BUILD_LAST_FAILED_PKG_FNAME:+1}" = 1 ]\ + && [ -e "${DEFAULT_BUILD_LAST_FAILED_PKG_FNAME}" ]; then + if read -r _epers_last_pkg <"${DEFAULT_BUILD_LAST_FAILED_PKG_FNAME}"\ + && rtl_fileop rm "${DEFAULT_BUILD_LAST_FAILED_PKG_FNAME}"; then + eval ${_epers_rspec}='${_epers_last_pkg}'; + else + _epers_rc=1; + rtl_setrstatus "${_epers_rstatus}" 'failed to read or clear status of last failed package \`'"${_epers_last_pkg}"''\'''; + fi; + else + _epers_rc=1; + rtl_setrstatus "${_epers_rstatus}" 'cannot rebuild last failed package'; + fi; ;; + + *:*) eval ${_epers_rspec}='${_epers_spec%:*}' ${_epers_rspec_at}='${_epers_spec#*:}'; ;; + *) eval ${_epers_rspec_at}= ${_epers_rspec_at}=ALL; ;; + esac; + + return "${_epers_rc}"; +}; + +# +# exp_pkg_init_restart_at_virtual() - produce list of virtual build step set in default build steps +# @_rset: out reference to restart virtual build step set +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +exp_pkg_init_restart_at_virtual() { + local _eperav_rset="${1#\$}" _eperav_step="" _eperav_step_virtual="" _epera_steps=""; + + rtl_lfilter2 \$DEFAULT_BUILD_STEPS \$_epera_steps "finish"; + for _eperav_step in ${_epera_steps}; do + _eperav_step_virtual="${_eperav_step%%_*}"; + if eval [ '"${'"${_eperav_rset}${_eperav_step_virtual}"':+1}"' != 1 ]; then + eval ${_eperav_rset}='"${'"${_eperav_rset}"':+${'"${_eperav_rset}"'},}${_eperav_step_virtual}"'; + fi; + eval ${_eperav_rset}${_eperav_step_virtual}='"${'"${_eperav_rset}${_eperav_step_virtual}"':+${'"${_eperav_rset}${_eperav_step_virtual}"'},}${_eperav_step}"'; + done; + + return 0; +}; + +# +# ex_pkg_process_restart_spec() - process restart (-r) specification into list of build steps and recursion flag +# @_rstatus: out reference to status string +# @_rspec: inout reference to restart {specification,package name list} +# @_rspec_at: out reference to restart build step list +# @_rrecursive: out reference to restart recursion flag +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +ex_pkg_process_restart_spec() { + local _epprs_rstatus="${1#\$}" _epprs_rspec="${2#\$}" _epprs_rspec_at="${3#\$}" \ + _epprs_rrecursive="${4#\$}" \ + _epprs_at="" _epprs_rc=0 _epprs_spec_at_new="" _epprs_step="" _epprs_step1="" \ + _epprs_virtual_set=""; + + if eval [ '"${'"${_epprs_rspec}"':+1}"' = 1 ]; then + if exp_pkg_init_restart_at_virtual \$_epprs_virtual_set \ + && exp_pkg_expand_restart_spec "${_epprs_rstatus}" "${_epprs_rspec}" \$_epprs_spec_at_new \ + && exp_pkg_expand_restart_recursive "${_epprs_rspec}" "${_epprs_rrecursive}" \ + && exp_pkg_expand_restart_at_spec "${_epprs_rstatus}" \$_epprs_virtual_set \$_epprs_spec_at_new; + then + + eval ${_epprs_rspec_at}=; + case "${_epprs_spec_at_new}" in + + ALL|LAST) + eval ${_epprs_rspec_at}='${_epprs_spec_at_new}'; ;; + + *) + for _epprs_at in ${DEFAULT_BUILD_STEPS}; do + if rtl_lmatch \$_epprs_at "${_epprs_spec_at_new}" ","; then + eval ${_epprs_rspec_at}='${'"${_epprs_rspec_at}"':+${'"${_epprs_rspec_at}"'},}${_epprs_at}'; + fi; + done; + if eval [ '"${'"${_epprs_rspec_at}"'##*,}"' != "finish" ]; then + rtl_lfilter2 "${_epprs_rspec_at}" \$_epprs_step "clean,finish" ","; _epprs_step="${_epprs_step##*,}"; + rtl_lfilter2 \$DEFAULT_BUILD_STEPS \$_epprs_step1 "clean finish"; _epprs_step1="${_epprs_step1##* }"; + if [ "${_epprs_step}" = "${_epprs_step1}" ]; then + eval ${_epprs_rspec_at}='${'"${_epprs_rspec_at}"':+${'"${_epprs_rspec_at}"'},}finish'; + fi; + fi; ;; + + esac; + rtl_llift "${_epprs_rspec}" "," " " || _epprs_rc=1; + else + _epprs_rc=1; + fi; + rtl_sunset \$_epprs_virtual_set; + fi; + + return "${_epprs_rc}"; +}; + +# vim:filetype=sh textwidth=0 diff --git a/subr.ex/ex_rtl.subr b/subr.ex/ex_rtl.subr new file mode 100644 index 00000000..a6177fa7 --- /dev/null +++ b/subr.ex/ex_rtl.subr @@ -0,0 +1,99 @@ +# +# Copyright (c) 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Lucía Andrea Illanes Albornoz <lucia@luciaillanes.de> +# set +o errexit -o noglob -o nounset is assumed. +# +# + +# +# ex_rtl_fixup_pkgconfig_paths() - fixup pathname prefixes in pkg-config(1) files +# @_dname_base: base directory pathname +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +ex_rtl_fixup_pkgconfig_paths() { + local _erfpp_dname_base="${1}" \ + _erfpp_pc_path=""; + + for _erfpp_pc_path in $(find "${_erfpp_dname_base=}" -name \*.pc); do + if [ -n "$(sed -ne '/^libdir=[^$]*$/p' "${_erfpp_pc_path}")" ] \ + && ! sed -i"" -e '/^libdir=[^$]*$/s/^libdir=\(.*\)$/libdir=${exec_prefix}\1/' \ + -e '/^exec_prefix=$/s/^.*$/exec_prefix=${prefix}/' \ + "${_erfpp_pc_path}"; + then + return 1; + fi; + + if [ -n "$(sed -ne '/^includedir=[^$]*$/p' "${_erfpp_pc_path}")" ] \ + && ! sed -i"" -e '/^includedir=[^$]*$/s/^includedir=\(.*\)$/includedir=${prefix}\1/' \ + "${_erfpp_pc_path}"; + then + return 1; + fi; + done; + + return 0; +}; + +# +# ex_rtl_purge_la_files() - purge .la files in tree +# @_dname_base: base directory pathname +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +ex_rtl_purge_la_files() { + local _erplf_dname_base="${1}" \ + _erplf_la_path=""; + + for _erplf_la_path in $(find \ + "${_erplf_dname_base}" \ + -type f \ + -name \*.la); + do + if ! rtl_fileop rm "${_erplf_la_path}"; then + return 1; + fi; + done; + return 0; +}; + +# +# ex_rtl_strip_files() - strip files of debugging information +# @_strip_cmd: strip(1) command name +# @_tree_root: pathname to tree root +# @--: (ignored) +# @_log_fn: logging function name; called with @... and pathname of each file stripped +# @...: @_fn initial arguments list as positional parameters +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +ex_rtl_strip_files() { + local _ersf_strip_cmd="${1}" _ersf_tree_root="${2}" \ + _ersf_ignored="${3}" _ersf_log_fn="${4}" \ + _ersf_bin_path=""; + shift 4; + + if [ -e "${_ersf_tree_root}" ]; then + for _ersf_bin_path in $(find \ + "${_ersf_tree_root}" \ + -perm /a=x \ + -type f); + do + if objdump \ + -sj .debug_frame \ + -j .debug_info \ + "${_ersf_bin_path}" \ + >/dev/null 2>&1; + then + if ! "${_ersf_strip_cmd}" "${_ersf_bin_path}"; then + return 1; + else + "${_ersf_log_fn}" "${@}" "${_ersf_bin_path}"; + fi; + fi; + done; + fi; + + return 0; +}; + +# vim:filetype=sh textwidth=0 diff --git a/subr.ex/ex_rtl_configure.subr b/subr.ex/ex_rtl_configure.subr new file mode 100644 index 00000000..bd448213 --- /dev/null +++ b/subr.ex/ex_rtl_configure.subr @@ -0,0 +1,437 @@ +# +# Copyright (c) 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Lucía Andrea Illanes Albornoz <lucia@luciaillanes.de> +# set +o errexit -o noglob -o nounset is assumed. +# +# Package {configure,make} command execution +# + +# +# ex_rtl_configure() - run configure script +# @_ar: ar(1) command name or pathname +# @_cc: C compiler command name or pathname +# @_configure: configure script command name or pathname +# @_cxx: C++ compiler command name or pathname +# @_ld: ld(1) command name or pathname +# @_libtool: libtool(1) command name or pathname or "none" +# @_pkg_config: pkg-config(1) command name or pathname +# @_python: python command name or pathname +# @_ranlib: ranlib(1) command name or pathname +# @--: (ignored) +# @_flags: configure script flags as a whitespace-separated list +# @_flags_extra: extra configure script flags as a whitespace-separated likst +# @_flags_list: configure script flags as a :-separated list +# @_flags_extra_list: extra configure script flags as a :-separated list +# @--: (ignored) +# @_cflags: $CFLAGS +# @_cflags_extra: extra $CFLAGS +# @_cppflags: $CPPFLAGS +# @_cppflags_extra: extra $CPPFLAGS +# @_cxxflags: $CXXFLAGS +# @_cxxflags_extra: extra $CXXFLAGS +# @_ldflags: $LDFLAGS +# @_ldflags_extra: extra $LDFLAGS +# @_pkg_config_libdir: pkg-config(1) search directory +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +ex_rtl_configure() { + local _erc_ar="${1}" _erc_cc="${2}" _erc_configure="${3}" _erc_cxx="${4}" _erc_ld="${5}" \ + _erc_libtool="${6}" _erc_pkg_config="${7}" _erc_python="${8}" _erc_ranlib="${9}" \ + _erc_ignored="${10}" \ + _erc_flags="${11}" _erc_flags_extra="${12}" \ + _erc_flags_list="${13}" _erc_flags_extra_list="${14}" \ + _erc_ignored="${15}" \ + _erc_cflags="${16}" _erc_cflags_extra="${17}" _erc_cppflags="${18}" \ + _erc_cppflags_extra="${19}" _erc_cxxflags="${20}" _erc_cxxflags_extra="${21}" \ + _erc_ldflags="${22}" _erc_ldflags_extra="${23}" _erc_pkg_config_libdir="${24}" \ + _erc_rc=0; + + case "${_erc_libtool:-}" in + none) _erc_libtool=""; ;; + esac; + + [ "${_erc_cflags_extra:+1}" = 1 ] && _erc_cflags="${_erc_cflags:+${_erc_cflags} }${_erc_cflags_extra}"; + [ "${_erc_cppflags_extra:+1}" = 1 ] && _erc_cppflags="${_erc_cppflags:+${_erc_cppflags} }${_erc_cppflags_extra}"; + [ "${_erc_cxxflags_extra:+1}" = 1 ] && _erc_cxxflags="${_erc_cxxflags:+${_erc_cxxflags} }${_erc_cxxflags_extra}"; + [ "${_erc_ldflags_extra:+1}" = 1 ] && _erc_ldflags="${_erc_ldflags:+${_erc_ldflags} }${_erc_ldflags_extra}"; + +( + if [ "${_erc_libtool:+1}" = 1 ]; then + export MAKE="make LIBTOOL=${_erc_libtool}"; + fi; + + [ "${_erc_ar:+1}" = 1 ] && export AR="${_erc_ar}"; + [ "${_erc_cc:+1}" = 1 ] && export CC="${_erc_cc}"; + [ "${_erc_cxx:+1}" = 1 ] && export CXX="${_erc_cxx}"; + [ "${_erc_ld:+1}" = 1 ] && export LD="${_erc_ld}"; + [ "${_erc_libtool:+1}" = 1 ] && export LIBTOOL="${_erc_libtool}"; + [ "${_erc_pkg_config:+1}" = 1 ] && export PKG_CONFIG="${_erc_pkg_config}"; + [ "${_erc_python:+1}" = 1 ] && export PYTHON="${_erc_python}"; + [ "${_erc_ranlib:+1}" = 1 ] && export RANLIB="${_erc_ranlib}"; + + [ "${_erc_cflags:+1}" = 1 ] && export CFLAGS="${_erc_cflags}"; + [ "${_erc_cppflags:+1}" = 1 ] && export CPPFLAGS="${_erc_cppflags}"; + [ "${_erc_cxxflags:+1}" = 1 ] && export CXXFLAGS="${_erc_cxxflags}"; + [ "${_erc_ldflags:+1}" = 1 ] && export LDFLAGS="${_erc_ldflags}"; + [ "${_erc_pkg_config_libdir:+1}" = 1 ] && export PKG_CONFIG_LIBDIR="${_erc_pkg_config_libdir}"; + + if [ "${_erc_flags_list:+1}" = 1 ]; then + rtl_run_cmdlineV ":" "${_erc_configure}" \ + "${_erc_flags_list}" \ + "${_erc_flags_extra_list:-}" \ + ; + exit "${?}"; + elif [ "${_erc_flags_extra_list:+1}" = 1 ]; then + rtl_run_cmdlineV ":" "${_erc_configure}" \ + ${_erc_flags:-} \ + "${_erc_flags_extra_list:-}" \ + ; + exit "${?}"; + else + rtl_run_cmdlineV ":" "${_erc_configure}" \ + ${_erc_flags:-} \ + ${_erc_flags_extra:-} \ + ; + exit "${?}"; + fi; +); + _erc_rc="${?}"; + + return "${_erc_rc}"; +}; + +# +# ex_rtl_configure_cmake() - configure CMake build +# @_ar: ar(1) command name or pathname +# @_cc: C compiler command name or pathname +# @_cmake: CMake command name or pathname +# @_cxx: C++ compiler command name or pathname +# @_ld: ld(1) command name or pathname +# @_pkg_config: pkg-config(1) command name or pathname +# @_python: python command name or pathname +# @_ranlib: ranlib(1) command name or pathname +# @--: (ignored) +# @_build_kind: build kind (Debug, Release) +# @_build_type: CMake build type (host, cross, native) +# @_cmake_args: additional CMake arguments as a whitespace-separated list +# @_cmake_args_extra: additional CMake extra arguments as a whitespace-separated likst +# @_prefix: build prefix pathname +# @_subdir: CMake build directory pathname +# @_system_name: CMake system name +# @_system_processor: CMake system processor +# @--: (ignored) +# @_cflags: $CFLAGS +# @_cflags_extra: extra $CFLAGS +# @_cppflags: $CPPFLAGS +# @_cppflags_extra: extra $CPPFLAGS +# @_cxxflags: $CXXFLAGS +# @_cxxflags_extra: extra $CXXFLAGS +# @_ldflags: $LDFLAGS +# @_ldflags_extra: extra $LDFLAGS +# @_pkg_config_libdir: pkg-config(1) search directory +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +ex_rtl_configure_cmake() { + local _ercc_ar="${1}" _ercc_cc="${2}" _ercc_cmake="${3}" \ + _ercc_cxx="${4}" _ercc_ld="${5}" _ercc_pkg_config="${6}" _ercc_python="${7}" \ + _ercc_ranlib="${8}" \ + _ercc_ignored="${9}" \ + _ercc_build_kind="${10}" _ercc_build_type="${11}" \ + _ercc_cmake_args="${12}" _ercc_cmake_args_extra="${13}" \ + _ercc_prefix="${14}" _ercc_subdir="${15}" \ + _ercc_system_name="${16}" _ercc_system_processor="${17}" \ + _ercc_ignored="${18}" \ + _ercc_cflags="${19}" _ercc_cflags_extra="${20}" _ercc_cppflags="${21}" \ + _ercc_cppflags_extra="${22}" _ercc_cxxflags="${23}" _ercc_cxxflags_extra="${24}" \ + _ercc_ldflags="${25}" _ercc_ldflags_extra="${26}" _ercc_pkg_config_libdir="${27}" \ + _ercc_cmd_name="" _ercc_cmake_args_auto="" _ercc_rc=0 _ercc_vname="" _ercc_vval="" + + [ "${_ercc_cflags_extra:+1}" = 1 ] && _ercc_cflags="${_ercc_cflags:+${_ercc_cflags} }${_ercc_cflags_extra}"; + [ "${_ercc_cppflags_extra:+1}" = 1 ] && _ercc_cppflags="${_ercc_cppflags:+${_ercc_cppflags} }${_ercc_cppflags_extra}"; + [ "${_ercc_cxxflags_extra:+1}" = 1 ] && _ercc_cxxflags="${_ercc_cxxflags:+${_ercc_cxxflags} }${_ercc_cxxflags_extra}"; + [ "${_ercc_ldflags_extra:+1}" = 1 ] && _ercc_ldflags="${_ercc_ldflags:+${_ercc_ldflags} }${_ercc_ldflags_extra}"; + +( + [ "${_ercc_pkg_config:+1}" = 1 ] && export PKG_CONFIG="${_ercc_pkg_config}"; + [ "${_ercc_pkg_config_libdir:+1}" = 1 ] && export PKG_CONFIG_LIBDIR="${_ercc_pkg_config_libdir}"; + [ "${_ercc_python:+1}" = 1 ] && export PYTHON="${_ercc_python}"; + + for _ercc_vname in ar cc cxx ld pkg_config ranlib; do + _ercc_vname="_ercc_${_ercc_vname}"; + + if eval [ '"${'"${_ercc_vname}"':+1}"' = 1 ]\ + && eval [ '"${'"${_ercc_vname}"'#/}"' = '"${'"${_ercc_vname}"'}"' ]; then + eval _ercc_cmd_name="\${${_ercc_vname}% *}"; + eval _ercc_vval="\${${_ercc_vname}#* }"; + eval ${_ercc_vname}='$(which "${_ercc_cmd_name}")' || return 1; + fi; + done; + + rtl_lconcat \$_ercc_cmake_args_auto "-DCMAKE_AR=${_ercc_ar}" "|"; + rtl_lconcat \$_ercc_cmake_args_auto "-DCMAKE_BUILD_TYPE=${_ercc_build_kind}" "|"; + rtl_lconcat \$_ercc_cmake_args_auto "-DCMAKE_C_COMPILER=${_ercc_cc}" "|"; + rtl_lconcat \$_ercc_cmake_args_auto "-DCMAKE_C_FLAGS=${_ercc_cflags}" "|"; + rtl_lconcat \$_ercc_cmake_args_auto "-DCMAKE_COMMAND=${_ercc_cmake}" "|"; + rtl_lconcat \$_ercc_cmake_args_auto "-DCMAKE_CPP_FLAGS=${_ercc_cppflags}" "|"; + rtl_lconcat \$_ercc_cmake_args_auto "-DCMAKE_CXX_COMPILER=${_ercc_cxx}" "|"; + rtl_lconcat \$_ercc_cmake_args_auto "-DCMAKE_CXX_FLAGS=${_ercc_cxxflags}" "|"; + rtl_lconcat \$_ercc_cmake_args_auto "-DCMAKE_EXE_LINKER_FLAGS=${_ercc_ldflags}" "|"; + rtl_lconcat \$_ercc_cmake_args_auto "-DCMAKE_FIND_ROOT_PATH=${_ercc_prefix}" "|"; + rtl_lconcat \$_ercc_cmake_args_auto "-DCMAKE_INSTALL_PREFIX=" "|"; + rtl_lconcat \$_ercc_cmake_args_auto "-DCMAKE_LINKER=${_ercc_ld}" "|"; + rtl_lconcat \$_ercc_cmake_args_auto "-DCMAKE_MODULE_LINKER_FLAGS=${_ercc_ldflags}" "|"; + rtl_lconcat \$_ercc_cmake_args_auto "-DCMAKE_RANLIB=${_ercc_ranlib}" "|"; + rtl_lconcat \$_ercc_cmake_args_auto "-DCMAKE_SHARED_LINKER_FLAGS=${_ercc_ldflags}" "|"; + rtl_lconcat \$_ercc_cmake_args_auto "-DCMAKE_SYSTEM_PROCESSOR=${_ercc_system_processor}" "|"; + rtl_lconcat \$_ercc_cmake_args_auto "-DPKG_CONFIG_EXECUTABLE=${_ercc_pkg_config}" "|"; + + case "${_ercc_build_type}" in + native) + rtl_lconcat \$_ercc_cmake_args_auto "-DCMAKE_SYSROOT=${_ercc_prefix}" "|"; + rtl_lconcat \$_ercc_cmake_args_auto "-DCMAKE_SYSTEM_NAME=${_ercc_system_name}" "|"; + ;; + esac; + + rtl_llift \$_ercc_cmake_args " +" "|"; + rtl_llift \$_ercc_cmake_args_extra " +" "|"; + + rtl_run_cmdlineV "|" "${_ercc_cmake}" \ + "${_ercc_cmake_args_auto}" \ + ${_ercc_cmake_args:-} \ + ${_ercc_cmake_args_extra:-} \ + "${_ercc_subdir}"; + exit "${?}"; +); + _ercc_rc="${?}"; + + return "${_ercc_rc}"; +}; + +# +# ex_rtl_configure_prepare() - prepare configure script for running +# @_build_type: build type (host, native) +# @_builddir: build directory pathname +# @_config_cache: optional configuration cache directives +# @_config_cache_local: optional local configuration cache directives +# @_config_cache_extra: optional extra configuration cache directives +# @_config_guess_fname: config.guess file pathname +# @_config_sub_global_fname: global config.sub file pathname +# @_copy_config_guess: copy config.guess (copy) or keep local config.guess (keep) +# @_force_autoreconf: 1 to force reconfiguration if already configured, 0 otherwise +# @_subdir: subdirectory pathname +# @_pkg_config: pkg-config(1) command name or pathname +# @_pkg_config_libdir: pkg-config(1) search directory +# @_prefix: prefix pathname +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +ex_rtl_configure_prepare() { + local _ercp_build_type="${1}" _ercp_builddir="${2}" _ercp_config_cache="${3}" \ + _ercp_config_cache_local="${4}" _ercp_config_cache_extra="${5}" \ + _ercp_config_guess_fname="${6}" _ercp_config_sub_global_fname="${7}" \ + _ercp_copy_config_guess=="${8}" _ercp_force_autoreconf="${9}" \ + _ercp_subdir="${10}" _ercp_pkg_config="${11}" _ercp_pkg_config_libdir="${12}" \ + _ercp_prefix="${13}"; + + if rtl_exists_any "${_ercp_subdir}" \ + "configure.ac" \ + "configure.in" \ + "configure"; + then + rtl_export_vars \ + PKG_CONFIG "${_ercp_pkg_config}" \ + PKG_CONFIG_LIBDIR "${_ercp_pkg_config_libdir}"; + + if [ "${_ercp_force_autoreconf:-0}" -eq 1 ]\ + && ! (cd "${_ercp_subdir}" && autoreconf -fiv); then + return 1; + fi; + + if [ -e "${_ercp_subdir}/configure.ac" ]\ + && [ ! -e "${_ercp_subdir}/configure" ]; then + for _ercp_fname in bootstrap bootstrap.sh autogen.sh; do + if [ -e "${_ercp_subdir}/${_ercp_fname}" ]; then + for _ercp_subdir_tgt in \ + "${_ercp_subdir}/build-aux" \ + "${_ercp_subdir}"; + do if [ -e "${_ercp_subdir_tgt}" ]; then + if ! rtl_fileop install -m 0700 \ + "${_ercp_config_sub_global_fname}" \ + "${_ercp_subdir_tgt}/config.sub"; then + return 1; + fi; + + if [ "${_ercp_copy_config_guess}" = "copy" ]; then + if ! rtl_fileop install -m 0700 \ + "${_ercp_config_guess_fname}" \ + "${_ercp_subdir_tgt}/config.guess"; then + return 1; + else + break; + fi; + fi; + fi; + done; + + if ! (rtl_fileop cd "${_ercp_subdir}" && \ + /bin/sh "${_ercp_fname}"); then + return 1; + else + break; + fi; + fi; + done; + + if ! (rtl_fileop cd "${_ercp_subdir}" && autoconf); then + return 1; + fi; + fi; + + for _ercp_fname in $(find "${_ercp_subdir}" -name config.sub); do + if ! rtl_fileop mv "${_ercp_fname}" "${_ercp_fname}.orig"\ + || ! rtl_fileop install -m 0700 "${_ercp_config_sub_global_fname}" "${_ercp_fname}"; then + return 1; + fi; + done; + + if [ "${_ercp_copy_config_guess}" = "copy" ]; then + for _ercp_fname in $(find "${_ercp_subdir}" -name config.guess); do + if ! rtl_fileop mv "${_ercp_fname}" "${_ercp_fname}.orig"\ + || ! rtl_fileop install -m 0700 "${_ercp_config_guess_fname}" "${_ercp_fname}"; then + return 1; + fi; + done; + fi; + + if [ "${_ercp_build_type}" != host ]; then + if ! rtl_fileop touch "${_ercp_builddir}/config.cache"; then + return 1; + else + for _ercp_config_cache in \ + "${_ercp_config_cache:-}" \ + "${_ercp_config_cache_local:-}" \ + "${_ercp_config_cache_extra:-}"; + do + if [ "${_ercp_config_cache:+1}" = 1 ]\ + && ! printf "%s\n" "${_ercp_config_cache}" |\ + tr " " "\n" >> "${_ercp_builddir}/config.cache"; then + return 1; + fi; + done; + + if ! sed -i"" "s,%PREFIX%,${_ercp_prefix},g" "${_ercp_builddir}/config.cache"; then + return 1; + fi; + fi; + fi; + + rtl_export_vars -u \ + PKG_CONFIG "${_ercp_pkg_config}" \ + PKG_CONFIG_LIBDIR "${_ercp_pkg_config_libdir}"; + fi; + + return 0; +}; + +# +# ex_rtl_configure_sofort() - configure sofort build +# @_ar: ar(1) command name or pathname +# @_cc: C compiler command name or pathname +# @_configure: configure script command name or pathname +# @_cxx: C++ compiler command name or pathname +# @_ld: ld(1) command name or pathname +# @_ranlib: ranlib(1) command name or pathname +# @--: (ignored) +# @_native_ar: native ar(1) command name or pathname +# @_native_cc: native C compiler command name or pathname +# @_native_cxx: native C++ compiler command name or pathname +# @_native_ld: native ld(1) command name or pathname +# @_native_ranlib: native ranlib(1) command name or pathname +# @--: (ignored) +# @_flags: configure script flags as a whitespace-separated list +# @_flags_extra: extra configure script flags as a whitespace-separated likst +# @--: (ignored) +# @_cflags: $CFLAGS +# @_cflags_extra: extra $CFLAGS +# @_cppflags: $CPPFLAGS +# @_cppflags_extra: extra $CPPFLAGS +# @_cxxflags: $CXXFLAGS +# @_cxxflags_extra: extra $CXXFLAGS +# @_ldflags: $LDFLAGS +# @_ldflags_extra: extra $LDFLAGS +# @--: (ignored) +# @_native_cflags: native $CFLAGS +# @_native_cflags_extra: native extra $CFLAGS +# @_native_cppflags: native $CPPFLAGS +# @_native_cppflags_extra: native extra $CPPFLAGS +# @_native_cxxflags: native $CXXFLAGS +# @_native_cxxflags_extra: native extra $CXXFLAGS +# @_native_ldflags: native $LDFLAGS +# @_native_ldflags_extra: native extra $LDFLAGS +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +ex_rtl_configure_sofort() { + local _ercs_ar="${1}" _ercs_cc="${2}" _ercs_configure="${3}" _ercs_cxx="${4}" _ercs_ld="${5}" _ercs_ranlib="${6}" \ + _ercs_ignored="${7}" \ + _ercs_native_ar="${8}" _ercs_native_cc="${9}" _ercs_native_cxx="${10}" _ercs_native_ld="${11}" \ + _ercs_native_ranlib="${12}" \ + _ercs_ignored="${13}" \ + _ercs_flags="${14}" _ercs_flags_extra="${15}" \ + _ercs_ignored="${16}" \ + _ercs_cflags="${17}" _ercs_cflags_extra="${18}" _ercs_cppflags="${19}" \ + _ercs_cppflags_extra="${20}" _ercs_cxxflags="${21}" _ercs_cxxflags_extra="${22}" \ + _ercs_ldflags="${23}" _ercs_ldflags_extra="${24}" \ + _ercs_ignored="${25}" \ + _ercs_native_cflags="${26}" _ercs_native_cflags_extra="${27}" _ercs_native_cppflags="${28}" \ + _ercs_native_cppflags_extra="${29}" _ercs_native_cxxflags="${30}" _ercs_native_cxxflags_extra="${31}" \ + _ercs_native_ldflags="${32}" _ercs_native_ldflags_extra="${33}" \ + _ercs_vname="" _ercs_rc=0; + + [ "${_ercs_cflags_extra:+1}" = 1 ] && _ercs_cflags="${_ercs_cflags:+${_ercs_cflags} }${_ercs_cflags_extra}"; + [ "${_ercs_cppflags_extra:+1}" = 1 ] && _ercs_cppflags="${_ercs_cppflags:+${_ercs_cppflags} }${_ercs_cppflags_extra}"; + [ "${_ercs_cxxflags_extra:+1}" = 1 ] && _ercs_cxxflags="${_ercs_cxxflags:+${_ercs_cxxflags} }${_ercs_cxxflags_extra}"; + [ "${_ercs_ldflags_extra:+1}" = 1 ] && _ercs_ldflags="${_ercs_ldflags:+${_ercs_ldflags} }${_ercs_ldflags_extra}"; + + [ "${_ercs_native_cflags_extra:+1}" = 1 ] && _ercs_native_cflags="${_ercs_native_cflags:+${_ercs_native_cflags} }${_ercs_native_cflags_extra}"; + [ "${_ercs_native_cppflags_extra:+1}" = 1 ] && _ercs_native_cppflags="${_ercs_native_cppflags:+${_ercs_native_cppflags} }${_ercs_native_cppflags_extra}"; + [ "${_ercs_native_cxxflags_extra:+1}" = 1 ] && _ercs_native_cxxflags="${_ercs_native_cxxflags:+${_ercs_native_cxxflags} }${_ercs_native_cxxflags_extra}"; + [ "${_ercs_native_ldflags_extra:+1}" = 1 ] && _ercs_native_ldflags="${_ercs_native_ldflags:+${_ercs_native_ldflags} }${_ercs_native_ldflags_extra}"; + +( + [ "${_ercs_ar:+1}" = 1 ] && export AR="${_ercs_ar}"; + [ "${_ercs_cc:+1}" = 1 ] && export CC="${_ercs_cc}"; + [ "${_ercs_cxx:+1}" = 1 ] && export CXX="${_ercs_cxx}"; + [ "${_ercs_ld:+1}" = 1 ] && export LD="${_ercs_ld}"; + [ "${_ercs_ranlib:+1}" = 1 ] && export RANLIB="${_ercs_ranlib}"; + + [ "${_ercs_native_ar:+1}" = 1 ] && export NATIVE_AR="${_ercs_native_ar}"; + [ "${_ercs_native_cc:+1}" = 1 ] && export NATIVE_CC="${_ercs_native_cc}"; + [ "${_ercs_native_cxx:+1}" = 1 ] && export NATIVE_CXX="${_ercs_native_cxx}"; + [ "${_ercs_native_ld:+1}" = 1 ] && export NATIVE_LD="${_ercs_native_ld}"; + [ "${_ercs_native_ranlib:+1}" = 1 ] && export NATIVE_RANLIB="${_ercs_native_ranlib}"; + + [ "${_ercs_cflags:+1}" = 1 ] && export CFLAGS="${_ercs_cflags}" CFLAGS_SHARED="${_ercs_cflags}" CFLAGS_STATIC="${_ercs_cflags}"; + [ "${_ercs_cppflags:+1}" = 1 ] && export CPPFLAGS="${_ercs_cppflags}" CPPFLAGS_SHARED="${_ercs_cppflags}" CPPFLAGS_STATIC="${_ercs_cppflags}"; + [ "${_ercs_cxxflags:+1}" = 1 ] && export CXXFLAGS="${_ercs_cxxflags}" CXXFLAGS_SHARED="${_ercs_cxxflags}" CXXFLAGS_STATIC="${_ercs_cxxflags}"; + [ "${_ercs_ldflags:+1}" = 1 ] && export LDFLAGS="${_ercs_ldflags}" LDFLAGS_SHARED="${_ercs_ldflags}" LDFLAGS_STATIC="${_ercs_ldflags}"; + + [ "${_ercs_native_cflags:+1}" = 1 ] && export NATIVE_CFLAGS="${_ercs_native_cflags}"; + [ "${_ercs_native_cppflags:+1}" = 1 ] && export NATIVE_CPPFLAGS="${_ercs_native_cppflags}"; + [ "${_ercs_native_cxxflags:+1}" = 1 ] && export NATIVE_CXXFLAGS="${_ercs_native_cxxflags}"; + [ "${_ercs_native_ldflags:+1}" = 1 ] && export NATIVE_LDFLAGS="${_ercs_native_ldflags}"; + + "${_ercs_configure}" \ + ${_ercs_flags:-} \ + ${_ercs_flags_extra:-}; + exit $((${?} ? 1 : ${_ercs_rc})); +); + _ercs_rc="${?}"; + + return "${_ercs_rc}"; +}; + +# vim:filetype=sh textwidth=0 diff --git a/subr.ex/ex_rtl_make.subr b/subr.ex/ex_rtl_make.subr new file mode 100644 index 00000000..6867dfad --- /dev/null +++ b/subr.ex/ex_rtl_make.subr @@ -0,0 +1,184 @@ +# +# Copyright (c) 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Lucía Andrea Illanes Albornoz <lucia@luciaillanes.de> +# set +o errexit -o noglob -o nounset is assumed. +# +# Package make command execution +# + +# +# ex_rtl_make() - run make(1) +# @_ar: ar(1) command name or pathname +# @_cc: C compiler command name or pathname +# @_cxx: C++ compiler command name or pathname +# @_ld: ld(1) command name or pathname +# @_libtool: libtool(1) command name or pathname or "none" +# @_make: make(1) command name or pathname +# @_pkg_config: pkg-config(1) command name or pathname +# @_ranlib: ranlib(1) command name or pathname +# @--: (ignored) +# @_set_ccfl: 1 if CC=... is to be passed to make(1), 0 if CC=... is not to be passed to make(1) +# @_subdir: make(1) -C argument +# @--: (ignored) +# @_makeflags: make(1) flags as a whitespace-separated list +# @_makeflags_extra: extra make(1) flags as a whitespace-separated likst +# @_makeflags_list: make(1) flags as a :-separated list +# @_makeflags_extra_list: extra make(1) flags as a :-separated list +# @_makeflags_loadavg: make(1) -l load argument +# @_makeflags_parallelise: make(1) -j jobs argument +# @_makeflags_verbosity: make(1) Makefile verbosity arguments or "none" +# @--: (ignored) +# @_cflags: $CFLAGS +# @_cflags_extra: extra $CFLAGS +# @_cppflags: $CPPFLAGS +# @_cppflags_extra: extra $CPPFLAGS +# @_cxxflags: $CXXFLAGS +# @_cxxflags_extra: extra $CXXFLAGS +# @_ldflags: $LDFLAGS +# @_ldflags_extra: extra $LDFLAGS +# @_pkg_config_libdir: pkg-config(1) search directory +# @--: (ignored) +# @_destdir_spec: DESTDIR=... specification +# @_target: make(1) target +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +ex_rtl_make() { + local _erm_ar="${1}" _erm_cc="${2}" _erm_cxx="${3}" _erm_ld="${4}" \ + _erm_libtool="${5}" _erm_make="${6}" _erm_pkg_config="${7}" _erm_ranlib="${8}" \ + _erm_ignored="${9}" \ + _erm_set_ccfl="${10}" _erm_subdir="${11}" \ + _erm_ignored="${12}" \ + _erm_makeflags="${13}" _erm_makeflags_extra="${14}" _erm_makeflags_list="${15}" \ + _erm_makeflags_extra_list="${16}" _erm_makeflags_loadavg="${17}" \ + _erm_makeflags_parallelise="${18}" _erm_makeflags_verbosity="${19}" \ + _erm_ignored="${20}" \ + _erm_cflags="${21}" _erm_cflags_extra="${22}" _erm_cppflags="${23}" \ + _erm_cppflags_extra="${24}" _erm_cxxflags="${25}" _erm_cxxflags_extra="${26}" \ + _erm_ldflags="${27}" _erm_ldflags_extra="${28}" _erm_pkg_config_libdir="${29}" \ + _erm_ignored="${30}" \ + _erm_destdir_spec="${31}" _erm_target="${32}" \ + _erm_rc=0; + + case "${_erm_makeflags_loadavg:-}" in + none) _erm_makeflags_loadavg=""; ;; + esac; + + case "${_erm_libtool:-}" in + none) _erm_libtool=""; ;; + esac; + + case "${_erm_makeflags_verbosity}" in + none) _erm_makeflags_verbosity=""; ;; + esac; + + case "${_erm_set_ccfl}" in + 1) _erm_set_ccfl="1"; ;; + *) _erm_set_ccfl=""; ;; + esac; + +( + if [ "${_erm_libtool:+1}" = 1 ]; then + export MAKE="make LIBTOOL=${_erm_libtool}"; + fi; + + if [ "${_erm_makeflags_list:+1}" = 1 ]; then + rtl_run_cmdlineV ":" "${_erm_make}" \ + AR="${_erm_ar}" \ + ${_erm_set_ccfl:+CC="${_erm_cc}"} \ + ${_erm_set_ccfl:+CXX="${_erm_cxx}"} \ + LD="${_erm_ld}" \ + ${_erm_libtool:+LIBTOOL="${_erm_libtool}"} \ + ${_erm_pkg_config:+PKG_CONFIG="${_erm_pkg_config}"} \ + RANLIB="${_erm_ranlib}" \ + \ + "${_erm_makeflags_list}" \ + "${_erm_makeflags_extra_list:-}" \ + ${_erm_makeflags_loadavg:-} \ + ${_erm_makeflags_parallelise:-} \ + ${_erm_makeflags_verbosity} \ + \ + ${_erm_cflags:+CFLAGS="${_erm_cflags}"} \ + ${_erm_cflags_extra:+CFLAGS+="${_erm_cflags_extra}"} \ + ${_erm_cppflags:+CPPFLAGS="${_erm_cppflags}"} \ + ${_erm_cppflags_extra:+CPPFLAGS+="${_erm_cppflags_extra}"} \ + ${_erm_cxxflags:+CXXFLAGS="${_erm_cxxflags}"} \ + ${_erm_cxxflags_extra:+CXXFLAGS+="${_erm_cxxflags_extra}"} \ + ${_erm_ldflags:+LDFLAGS="${_erm_ldflags}"} \ + ${_erm_ldflags_extra:+LDFLAGS+="${_erm_ldflags_extra}"} \ + ${_erm_pkg_config_libdir:+PKG_CONFIG_LIBDIR="${_erm_pkg_config_libdir}"} \ + \ + ${_erm_subdir:+-C "${_erm_subdir}"} \ + ${_erm_destdir_spec:+"${_erm_destdir_spec}"} \ + ${_erm_target:+"${_erm_target}"} \ + ; + exit "${?}"; + elif [ "${_erm_makeflags_extra_list:+1}" = 1 ]; then + rtl_run_cmdlineV ":" "${_erm_make}" \ + AR="${_erm_ar}" \ + ${_erm_set_ccfl:+CC="${_erm_cc}"} \ + ${_erm_set_ccfl:+CXX="${_erm_cxx}"} \ + LD="${_erm_ld}" \ + ${_erm_libtool:+LIBTOOL="${_erm_libtool}"} \ + ${_erm_pkg_config:+PKG_CONFIG="${_erm_pkg_config}"} \ + RANLIB="${_erm_ranlib}" \ + \ + ${_erm_makeflags:-} \ + "${_erm_makeflags_extra_list}" \ + ${_erm_makeflags_loadavg:-} \ + ${_erm_makeflags_parallelise:-} \ + ${_erm_makeflags_verbosity} \ + \ + ${_erm_cflags:+CFLAGS="${_erm_cflags}"} \ + ${_erm_cflags_extra:+CFLAGS+="${_erm_cflags_extra}"} \ + ${_erm_cppflags:+CPPFLAGS="${_erm_cppflags}"} \ + ${_erm_cppflags_extra:+CPPFLAGS+="${_erm_cppflags_extra}"} \ + ${_erm_cxxflags:+CXXFLAGS="${_erm_cxxflags}"} \ + ${_erm_cxxflags_extra:+CXXFLAGS+="${_erm_cxxflags_extra}"} \ + ${_erm_ldflags:+LDFLAGS="${_erm_ldflags}"} \ + ${_erm_ldflags_extra:+LDFLAGS+="${_erm_ldflags_extra}"} \ + ${_erm_pkg_config_libdir:+PKG_CONFIG_LIBDIR="${_erm_pkg_config_libdir}"} \ + \ + ${_erm_subdir:+-C "${_erm_subdir}"} \ + ${_erm_destdir_spec:+"${_erm_destdir_spec}"} \ + ${_erm_target:+"${_erm_target}"} \ + ; + exit "${?}"; + else + rtl_run_cmdlineV ":" "${_erm_make}" \ + AR="${_erm_ar}" \ + ${_erm_set_ccfl:+CC="${_erm_cc}"} \ + ${_erm_set_ccfl:+CXX="${_erm_cxx}"} \ + LD="${_erm_ld}" \ + ${_erm_libtool:+LIBTOOL="${_erm_libtool}"} \ + ${_erm_pkg_config:+PKG_CONFIG="${_erm_pkg_config}"} \ + RANLIB="${_erm_ranlib}" \ + \ + ${_erm_makeflags:-} \ + ${_erm_makeflags_extra:-} \ + ${_erm_makeflags_loadavg:-} \ + ${_erm_makeflags_parallelise:-} \ + ${_erm_makeflags_verbosity} \ + \ + ${_erm_cflags:+CFLAGS="${_erm_cflags}"} \ + ${_erm_cflags_extra:+CFLAGS+="${_erm_cflags_extra}"} \ + ${_erm_cppflags:+CPPFLAGS="${_erm_cppflags}"} \ + ${_erm_cppflags_extra:+CPPFLAGS+="${_erm_cppflags_extra}"} \ + ${_erm_cxxflags:+CXXFLAGS="${_erm_cxxflags}"} \ + ${_erm_cxxflags_extra:+CXXFLAGS+="${_erm_cxxflags_extra}"} \ + ${_erm_ldflags:+LDFLAGS="${_erm_ldflags}"} \ + ${_erm_ldflags_extra:+LDFLAGS+="${_erm_ldflags_extra}"} \ + ${_erm_pkg_config_libdir:+PKG_CONFIG_LIBDIR="${_erm_pkg_config_libdir}"} \ + \ + ${_erm_subdir:+-C "${_erm_subdir}"} \ + ${_erm_destdir_spec:+"${_erm_destdir_spec}"} \ + ${_erm_target:+"${_erm_target}"} \ + ; + exit "${?}"; + fi; +); + _erm_rc="${?}"; + + return "${_erm_rc}"; +}; + +# vim:filetype=sh textwidth=0 diff --git a/subr.ex/ex_rtl_midipix.subr b/subr.ex/ex_rtl_midipix.subr new file mode 100644 index 00000000..1fb594a8 --- /dev/null +++ b/subr.ex/ex_rtl_midipix.subr @@ -0,0 +1,93 @@ +# +# Copyright (c) 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Lucía Andrea Illanes Albornoz <lucia@luciaillanes.de> +# set +o errexit -o noglob -o nounset is assumed. +# +# + +# +# ex_rtl_install_library_archives() - install library archives and library links (.lib.a) for all libraries (.so) in tree matching lib* +# @_dname_base: base directory pathname +# @_mdso_cmd: mdso command name +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +ex_rtl_install_library_archives() { + local _erila_dname_base="${1}" _erila_mdso_cmd="${2}" \ + _erila_postfix="" _erila_lib_dst_path="" _erila_lib_name="" \ + _erila_lib_src_path="" _erila_so_dst_dir="" _erila_so_src_path=""; + + for _erila_so_src_path in \ + $(find "${_erila_dname_base}" \ + \( -name "*.so" -or -name "*.so.*" \) \ + \( -name "lib*" \) \ + -print); + do + if [ "$(readlink -f "${_erila_so_src_path}")" != "/dev/null" ]\ + && rtl_remove_postfix "[0-9.]" "${_erila_so_src_path##*.so}" \$_erila_postfix\ + && [ "${_erila_postfix:+1}" != 1 ]; then + + case "${_erila_so_src_path}" in + *.so) _erila_lib_src_path="${_erila_so_src_path%%.so}.lib.a"; ;; + *.so.*) _erila_lib_src_path="${_erila_so_src_path%%.so.*}.${_erila_so_src_path##*.so.}.lib.a"; ;; + esac; + + _erila_so_dst_dir="${_erila_so_src_path%/*}"; + rtl_basename2 \$_erila_lib_src_path \$_erila_lib_name; + _erila_lib_dst_path="${_erila_so_dst_dir}/${_erila_lib_name}"; + + if [ ! -L "${_erila_lib_src_path}" ]\ + && [ ! -e "${_erila_lib_dst_path}" ]; then + if ! (rtl_basename2 \$_erila_so_src_path \$_erila_fname; \ + rtl_basename2 \$_erila_lib_dst_path \$_erila_fname_dst; \ + rtl_dirname2 \$_erila_so_src_path \$_erila_dname; \ + rtl_fileop cd "${_erila_dname}" && \ + perk -e "${_erila_fname}" |\ + "${_erila_mdso_cmd}" \ + -i "${_erila_fname_dst}" \ + -n "${_erila_fname}" -); + then + return 1; + fi; + fi; + + if ! ex_rtl_install_library_link \ + "${_erila_lib_name}" "${_erila_so_dst_dir}" \ + "${_erila_so_src_path}"; + then + return 1; + fi; + fi; + done; + + return 0; +}; + +# +# ex_rtl_install_library_link() - install library archive (.lib.a) link for library (.so) +# @_lib_name: library name +# @_so_dir: library directory pathname +# @_so_path: library file pathname +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +ex_rtl_install_library_link() { + local _erill_lib_name="${1}" _erill_so_dir="${2}" _erill_so_path="${3}" \ + _erill_lib_link_path="${3%.so*}.lib.a" _erill_fname="" _erill_lib_link_tgt=""; + + if _erill_lib_link_tgt="$(find "${_erill_so_dir}" \ + -name "${_erill_lib_name%%.*}.*.lib.a" |\ + sort | tail -1)"\ + && [ "${_erill_lib_link_tgt:+1}" = 1 ]\ + && [ "${_erill_lib_link_tgt}" != "${_erill_lib_link_path}" ]; + then + rtl_basename2 \$_erill_lib_link_tgt \$_erill_fname; + + if ! rtl_fileop rm "${_erill_lib_link_path}"\ + || ! rtl_fileop ln_symbolic "${_erill_fname}" "${_erill_lib_link_path}"; then + return 1; + fi; + fi; + return 0; +}; + +# vim:filetype=sh textwidth=0 diff --git a/subr.ex/ex_rtl_rpm.subr b/subr.ex/ex_rtl_rpm.subr new file mode 100644 index 00000000..2f1589d6 --- /dev/null +++ b/subr.ex/ex_rtl_rpm.subr @@ -0,0 +1,270 @@ +# +# Copyright (c) 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Lucía Andrea Illanes Albornoz <lucia@luciaillanes.de> +# set +o errexit -o noglob -o nounset is assumed. +# +# + +# +# ex_rtl_build_rpm() - build RPM package +# @_destdir: package destination directory +# @_jobs_max: maximum count of simultaneously executing rpmbuild(1) processes +# @_jobs_semaphore: pathname to current count of simultaneously executing rpmbuild(1) processes semaphore file +# @_jobs_wait: wait period in seconds when @_jobs_semaphore is locked +# @_name: package name +# @_rpms_dname: RPMs directory pathname +# @_spec_fname: RPM .spec file pathname +# @_spec_fname_tgt: target package RPM .spec file pathname +# @_tmp_dname: temporary files directory pathname +# @_topdir: package top directory +# @_url: package URL +# @_version: package version +# @_version_rpm: package RPM version +# +# Returns: zero (0) on success, non-zero (>0) on failure +# N.B.: The following variables are substituted prior to running rpmbuild(1): +# %{pkg_destdir} +# %{pkg_name} +# %{pkg_url} +# %{pkg_version_full} +# %{pkg_version_rpm} +# +# The \n-separated list of package files is inserted after the `%files' line. +# +ex_rtl_build_rpm() { + local _erbr_destdir="${1}" _erbr_jobs_max="${2}" _erbr_jobs_semaphore="${3}" _erbr_jobs_wait="${4}" \ + _erbr_name="${5}" _erbr_rpms_dname="${6}" _erbr_spec_fname="${7}" _erbr_spec_fname_tgt="${8}" \ + _erbr_tmp_dname="${9}" _erbr_topdir="${10}" _erbr_url="${11}" _erbr_version="${12}" \ + _erbr_version_rpm="${13}" \ + _erbr_spec_fname_tgt_tmp="" _erbr_job_count=0 _erbr_rc=0 _erbr_rc_jobs=0; + +( + while true; do + (set +o errexit -o noglob -o nounset; + rtl_flock_acquire 4 || exit $((${?} + 1)); + + read _erbr_job_count <&4; + if [ "${_erbr_job_count:+1}" != 1 ]; then + _erbr_job_count=0; + fi; + + if [ "${_erbr_job_count}" -ge "${_erbr_jobs_max}" ]; then + exit 1; + else + : $((_erbr_job_count += 1)); + printf "%s" "${_erbr_job_count}" >"${_erbr_jobs_semaphore}" || exit $((${?} + 1)); + exit 0; + fi) 4<>"${_erbr_jobs_semaphore}"; + _erbr_rc_jobs="${?}"; + + case "${_erbr_rc_jobs}" in + 0) break; ;; + 1) sleep "${_erbr_jobs_wait}" || return "${?}"; ;; + *) return $((${_erbr_rc_jobs} - 1)); + esac; + done; + + trap ' + (set +o errexit -o noglob -o nounset; + rtl_flock_acquire 4 || exit 1; + + read _erbr_job_count <&4; + if [ "${_erbr_job_count:+1}" != 1 ]\ + || [ "${_erbr_job_count}" -lt 1 ]; then + _erbr_job_count=1; + fi; + + : $((_erbr_job_count -= 1)); + printf "%s" "${_erbr_job_count}" >"${_erbr_jobs_semaphore}" || exit 1; + exit 0) 4<>"${_erbr_jobs_semaphore}"' \ + EXIT HUP INT TERM USR1 USR2; + + ( + _erbr_spec_fname_tgt_tmp="${_erbr_spec_fname_tgt}.tmp"; + trap "rm -f \"${_erbr_spec_fname_tgt_tmp}\"" EXIT HUP INT TERM USR1 USR2; + + # + # N.B. Keep list in sync w/ list in function documentation comment block at top. + # + if rtl_fileop cp "${_erbr_spec_fname}" "${_erbr_spec_fname_tgt_tmp}" \ + && sed -i"" \ + -ne '/^#REMOVEDBYSED#/!p' \ + "${_erbr_spec_fname_tgt_tmp}" \ + && sed -i"" \ + -e 's#%{pkg_destdir}#'"${_erbr_destdir}"'#g' \ + -e 's#%{pkg_name}#'"${_erbr_name}"'#g' \ + -e 's#%{pkg_url}#'"${_erbr_url}"'#g' \ + -e 's#%{pkg_version_full}#'"${_erbr_version}"'#g' \ + -e 's#%{pkg_version_rpm}#'"${_erbr_version_rpm}"'#g' \ + "${_erbr_spec_fname_tgt_tmp}" \ + && sed -n -e '1,/^%files$/p' \ + "${_erbr_spec_fname_tgt_tmp}" \ + > "${_erbr_spec_fname_tgt}" \ + && (cd "${_erbr_destdir}"; \ + find -mindepth 1 \( -type f -or -type l \) | \ + sed -e 's,^./,'"/"',' \ + -e 's/^/"/' \ + -e 's/$/"/') \ + >> "${_erbr_spec_fname_tgt}" \ + && sed -n -e '/^%files$/,${/^%files$/d;p}' \ + "${_erbr_spec_fname_tgt_tmp}" \ + >> "${_erbr_spec_fname_tgt}" \ + ; \ + then + _erbr_rc=0; + else + _erbr_rc=1; + fi; + exit "${_erbr_rc}"; + ); _erbr_rc="${?}"; + + if [ "${_erbr_rc}" -eq 0 ]; then + while true; do + rpmbuild \ + -bb \ + --define "_binary_payload w2T16.xzdio" \ + --define="_tmppath ${_erbr_tmp_dname=}" \ + --define="_topdir ${_erbr_topdir}" \ + --nodeps \ + "${_erbr_spec_fname_tgt}"; + _erbr_rc="${?}"; + + if [ "${_erbr_rc}" -eq 141 ]; then + _erbr_rc=0; continue; + else + break; + fi; + done; + + if [ "${_erbr_rc}" -eq 0 ]; then + if ! find "${_erbr_rpms_dname}/${_erbr_name}-${_erbr_version_rpm}/RPMS" \ + -iname \*.rpm -exec cp -pP {} "${_erbr_rpms_dname}/" \; \ + || ! rtl_fileop rm "${_erbr_rpms_dname}/${_erbr_name}-${_erbr_version_rpm}" \ + || ! rtl_fileop cp "${_erbr_spec_fname_tgt}" "${_erbr_rpms_dname}/"; + then + _erbr_rc=1; + fi; + fi; + fi; + + exit "${_erbr_rc}"; +); + _erbr_rc="${?}"; + + return "${_erbr_rc}"; +}; + +# +# ex_rtl_expand_rpm_version() - expand RPM version strings +# @_rurl: out reference to package URL +# @_rversion: out reference to package version +# @_rversion_rpm: out reference to RPM version string +# @_subdir: package subdirectory +# @_url: package URL +# @_url_censor: package URL filter +# @_urls_git: package Git URL(s) +# @_version: package version +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +ex_rtl_expand_rpm_version() { + local _ererv_rurl="${1#\$}" _ererv_rversion="${2#\$}" _ererv_rversion_rpm="${3#\$}" \ + _ererv_subdir="${4}" _ererv_url="${5}" _ererv_url_censor="${6}" \ + _ererv_urls_git="${7}" _ererv_version="${8}" \ + _ererv_version_full="" _ererv_version_rpm="" + + if [ "${_ererv_url:+1}" = 1 ]; then + _ererv_url="${_ererv_url%% *}"; + _ererv_version_full="${_ererv_version}"; + _ererv_version_rpm="${_ererv_version%%-*}"; + + elif [ "${_ererv_urls_git:+1}" = 1 ]; then + _ererv_url="${_ererv_urls_git%% *}"; + _ererv_url="${_ererv_url##*=}"; + _ererv_url="${_ererv_url%%@*}"; + + _ererv_version_rpm="$(cd "${_ererv_subdir}" && git rev-parse HEAD)" || return 1; + _ererv_version_full="${_ererv_version_rpm} ($(cd "${_ererv_subdir}" && git rev-parse --abbrev-ref HEAD))" || return 1; + fi; + + if [ "${_ererv_url#${_ererv_url_censor}}" != "${_ererv_url}" ]; then + _ererv_url="Unknown"; + fi; + + eval ${_ererv_rurl}='${_ererv_url}'; + eval ${_ererv_rversion}='${_ererv_version_full}'; + eval ${_ererv_rversion_rpm}='${_ererv_version_rpm}'; + + return 0; +}; + +# +# ex_rtl_fixup_pkgconfig_paths() - fixup pathname prefixes in pkg-config(1) files +# @_dname_base: base directory pathname +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +ex_rtl_fixup_pkgconfig_paths() { + local _erfpp_dname_base="${1}" \ + _erfpp_pc_path=""; + + for _erfpp_pc_path in $(find "${_erfpp_dname_base=}" -name \*.pc); do + if [ -n "$(sed -ne '/^libdir=[^$]*$/p' "${_erfpp_pc_path}")" ] \ + && ! sed -i"" -e '/^libdir=[^$]*$/s/^libdir=\(.*\)$/libdir=${exec_prefix}\1/' \ + -e '/^exec_prefix=$/s/^.*$/exec_prefix=${prefix}/' \ + "${_erfpp_pc_path}"; + then + return 1; + fi; + + if [ -n "$(sed -ne '/^includedir=[^$]*$/p' "${_erfpp_pc_path}")" ] \ + && ! sed -i"" -e '/^includedir=[^$]*$/s/^includedir=\(.*\)$/includedir=${prefix}\1/' \ + "${_erfpp_pc_path}"; + then + return 1; + fi; + done; + + return 0; +}; + +# +# ex_rtl_strip_files() - strip files of debugging information +# @_strip_cmd: strip(1) command name +# @_tree_root: pathname to tree root +# @--: (ignored) +# @_log_fn: logging function name; called with @... and pathname of each file stripped +# @...: @_fn initial arguments list as positional parameters +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +ex_rtl_strip_files() { + local _ersf_strip_cmd="${1}" _ersf_tree_root="${2}" \ + _ersf_ignored="${3}" _ersf_log_fn="${4}" \ + _ersf_bin_path=""; + shift 4; + + if [ -e "${_ersf_tree_root}" ]; then + for _ersf_bin_path in $(find \ + "${_ersf_tree_root}" \ + -perm /a=x \ + -type f); + do + if objdump \ + -sj .debug_frame \ + -j .debug_info \ + "${_ersf_bin_path}" \ + >/dev/null 2>&1; + then + if ! "${_ersf_strip_cmd}" "${_ersf_bin_path}"; then + return 1; + else + "${_ersf_log_fn}" "${@}" "${_ersf_bin_path}"; + fi; + fi; + done; + fi; + + return 0; +}; + +# vim:filetype=sh textwidth=0 |