summaryrefslogtreecommitdiffhomepage
path: root/subr.ex
diff options
context:
space:
mode:
Diffstat (limited to 'subr.ex')
-rw-r--r--subr.ex/ex_init.subr449
-rw-r--r--subr.ex/ex_pkg.subr320
-rw-r--r--subr.ex/ex_pkg_depends.subr225
-rw-r--r--subr.ex/ex_pkg_dispatch.subr407
-rw-r--r--subr.ex/ex_pkg_env.subr195
-rw-r--r--subr.ex/ex_pkg_exec.subr223
-rw-r--r--subr.ex/ex_pkg_restart.subr324
-rw-r--r--subr.ex/ex_rtl.subr99
-rw-r--r--subr.ex/ex_rtl_configure.subr437
-rw-r--r--subr.ex/ex_rtl_make.subr184
-rw-r--r--subr.ex/ex_rtl_midipix.subr93
-rw-r--r--subr.ex/ex_rtl_rpm.subr270
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