aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory M. Tuner <gmt@be-evil.net>2013-12-30 14:21:00 -0800
committerGregory M. Tuner <gmt@be-evil.net>2013-12-30 14:21:00 -0800
commit66aedd76059e5f4c518d5e83a0bc2451eebeaeac (patch)
treecffa467903ff7a42ae5b96d2682cbcdb640b1622 /eclass/multilib-build.eclass
parenteclass/multilib-build: export MULTILIB_BUILD_ABI (diff)
downloadgmt-66aedd76059e5f4c518d5e83a0bc2451eebeaeac.tar.gz
gmt-66aedd76059e5f4c518d5e83a0bc2451eebeaeac.tar.bz2
gmt-66aedd76059e5f4c518d5e83a0bc2451eebeaeac.zip
eclass/multilib-build: refine MULTILIB_WRAPPED_EXECUTABLES
Changes the regular mode of operation for MULTILIB_WRAPPED_EXECUTABLES to simply copy the executable with -${ABI} suffixes, and leave the best-abi version intact. Now, it only generates and compiles the wrapper if the executable is named in MULTILIB_WRAPPED_EXECUTABLES if the filename is prefixed with an '@'-symbol. Also refines the preservation of permissions and timestamps so that all the work occurs during multilib_prepare_wrappers. Adds enabled-ABI whitelisting in the wrapper and falls back to the best ABI if an unknown ABI is specified in MULTILIB_BUILD_ABI. Calculates, rather than pulls from MULTIBUILD_VARIANTS, the list of ABI's so that nothing breaks if an inner layer of multibuild iteration is interposed between multilib_foreach_abi and multilib_prepare_wrappers. fix missing eend Signed-off-by: Gregory M. Tuner <gmt@be-evil.net>
Diffstat (limited to 'eclass/multilib-build.eclass')
-rw-r--r--eclass/multilib-build.eclass147
1 files changed, 97 insertions, 50 deletions
diff --git a/eclass/multilib-build.eclass b/eclass/multilib-build.eclass
index b9ea4be..d887341 100644
--- a/eclass/multilib-build.eclass
+++ b/eclass/multilib-build.eclass
@@ -351,36 +351,51 @@ multilib_copy_sources() {
# @ECLASS-VARIABLE: MULTILIB_WRAPPED_EXECUTABLES
# @DESCRIPTION:
-# A list of executables to wrap for automatic multilib support. The listed
-# executables will be renamed with a "-${ABI}" suffix and replaced with a
-# generated binary wrapper executable compiled against the best ABI.
+# A list of executables to wrap for automatic multilib support. Any
+# executable in the list may be prefixed with an at-sign ('@'), which
+# will cause the executable itself to be replaced with a generated
+# wrapper executable; otherwise, the executable itself will not
+# be modified (only copied) by multilib-build, which, under most
+# circumstances, will result in the best ABI version being used.
#
-# The generated wrapper executable will perform a best-effort search for
-# the wrapped per-abi executable corresponding to the current multilib-build
-# ABI and invoke it, if it can be found.
+# So, if we were to add '/usr/bin/foo' to MULTILIB_WRAPPED_EXECUTABLES,
+# the expected result might be as follows:
+#
+# /usr/bin/foo : best ABI executable.
+# /usr/bin/foo-bar : executable for the 'bar' ABI
+# /usr/bin/foo-baz : executable for the 'baz' ABI
+#
+# If we were using the 'fake' multilib arch, with abi_fake_bar and abi_fake_baz
+# use flags activated. This means that if 'baz' was the best ABI, then
+# /usr/bin/foo and /usr/bin/baz would be identical (perhaps hard-linked) files.
+#
+# The generated wrapper executables, if requested, will perform a best-effort
+# search for the wrapped per-abi executable correspondinging to the current
+# multilib-build ABI (if any), and invoke it, if it can be found. Otherwise,
+# it will invoke the wrapped best-abi executable.
#
# In certain plausible cases, this may not be possible; it may therefore
-# be the case that wrapping a multilib executable creates more problems
-# than it solves.
+# be the case that '@'-wrapping a multilib executable creates more problems
+# than it solves. The wrapper works by checking for a MULTILIB_BUILD_ABI
+# environment variable.
#
-# This variable has to be a bash array. Paths shall be relative to
-# installation root (${ED}), and name regular executable files or
-# symbolic links to regular executable files. The latter is discouraged;
-# then again, so is the former!
+# The MULTILIB_WRAPPED_EXECUTABLES variable has to be a bash array. Paths
+# shall be relative to the installation root (${ED}), and name regular
+# executable files. It is an error to wrap an suid executable.
#
# If at all possible, it is preferred to simply drop non-best-ABI
# executables from your installation (this will happen automatically
-# in most cases).
+# in most cases, simply by omitting the executable from
+# MULTILIB_WRAPPED_EXECUTABLES).
#
-# If that won't do, then it is preferred to place your non-best-ABI
-# executables side-by-side with -${ABI}-suffixed names or to place them
-# in separate directories (a better solution if there are a lot of them).
+# If that won't do, then it is preferred to wrap without the '@' prefix
+# or to place them in separate directories (a better solution than
+# MULTILIB_WRAPPED_EXECUTABLES if there are a lot of them).
#
-# About the only good reason to rely on this feature is if other frameworks
-# tend to hard-code the path to the executable in question, and queries
-# it to perform build-time dependency analysis. configure scripts sometimes
-# do this, for example, for interpreter executables, resulting in attempts
-# to link against wrong-ABI libraries at compile time.
+# About the only good reason to rely on '@'-wrapping is if third-party
+# frameworks tend to hard-code the path to the executable in question into
+# configure scripts and then to rely on the executable itself to perform
+# configure-time dependency generation.
#
# Even in those rare cirucumstances, you might still investigate
# whether some prior art exists in Gentoo, or your framework, to skip
@@ -390,7 +405,8 @@ multilib_copy_sources() {
# Example:
# @CODE
# MULTILIB_WRAPPED_EXECUTABLES=(
-# /usr/bin/script-engine-executable
+# /usr/bin/script-engine-config
+# @/usr/bin/script-engine
# )
# @CODE
@@ -496,20 +512,32 @@ _EOF_
fi
done
+ local generate_wrapper
for f in "${MULTILIB_WRAPPED_EXECUTABLES[@]}" ; do
- # ensure leading slash is not present
+ generate_wrapper=no
+ [[ ${f:0:1} == @ ]] && generate_wrapper=yes
+ f="${f#@}"
+
+ # strip leading slashes
f="${f#/}"
[[ ${f} =~ ^/+ ]] && f="${f#${BASH_REMATCH[0]}}"
debug-print "${FUNCNAME}: wrapped executable check: ${root}${f}"
- [[ -f ${root}${f} ]] || continue
+ [[ -e ${root}${f} ]] || continue
+
+ # sanity checks
+ [[ -f ${root}${f} ]] || die "Only regular files may be wrapped: \"${root}${f}\" is something else"
+ [[ -x ${root}${f} ]] || die "Wrapped executables must be executable: \"${root}${f}\" isnt"
+ [[ -u ${root}${f} ]] && die "Suid executables may not be wrapped: \"${root}${f}\""
+ [[ -g ${root}${f} ]] && die "Sgid executables may not be wrapped: \"${root}${f}\""
debug-print "${FUNCNAME}: wrapped executable \"${root}${f}\" found, wrapping."
local dir="${f%/*}"
+ # strip trailing slashes
[[ ${dir} =~ /+$ ]] && dir="${dir%${BASH_REMATCH[0]}}"
- [[ -d "${ED}tmp/multilib-bin-wrappers/${dir}" ]] || \
+ [[ ${generate_wrapper} == yes && ! -d "${ED}tmp/multilib-bin-wrappers/${dir}" ]] && \
dodir "/tmp/multilib-bin-wrappers/${dir}"
if [[ -f "${root}${f}-${ABI}" ]] ; then
@@ -519,15 +547,30 @@ _EOF_
# in case this represents a real name collision.
ewarn
ewarn "Name collision wrapping multilib executable \"${f}\"."
- ewarn "Destination \"${root}${f}-${ABI}\" overwritten."
+ ewarn "Destination \"${root}${f}-${ABI}\" will be over-written."
ewarn
+ rm -fv "${root}${f}-${ABI}" || die
fi
- mv -fv "${root}${f}" "${root}${f}-${ABI}" || die
+ if [[ ${generate_wrapper} == yes ]] ; then
+ cp -vT "${root}${f}" "${root}${f}-${ABI}" || die
+ # make wrapper like original
+ chown -cv --reference="${root}${f}" "${root}${f}-${ABI}" || die "Cant chown \"${root}${f}-${ABI}\""
+ chmod -cv --reference="${root}${f}" "${root}${f}-${ABI}" || die "Cant chmod \"${root}${f}-${ABI}\""
+ touch --reference="${root}${f}" "${root}${f}-${ABI}" || die "Cant touch \"${root}${f}-${ABI}\""
+ rm -vf "${root}${f}"
+ else
+ ln -vT "${root}${f}" "${root}${f}-${ABI}" || die
+ # make wrapper like original
+ chown -cv --reference="${root}${f}" "${root}${f}-${ABI}" || die "Cant chown \"${root}${f}-${ABI}\""
+ chmod -cv --reference="${root}${f}" "${root}${f}-${ABI}" || die "Cant chmod \"${root}${f}-${ABI}\""
+ touch --reference="${root}${f}" "${root}${f}-${ABI}" || die "Cant touch \"${root}${f}-${ABI}\""
+ fi
- if [[ ! -f "${ED}tmp/multilib-bin-wrappers/${f}" ]]; then
- local max_abi_len=0 a
- for a in "${MULTIBUILD_VARIANTS[@]}" ; do
+ if [[ ${generate_wrapper} == yes && ! -f "${ED}tmp/multilib-bin-wrappers/${f}" ]]; then
+ # we need to get the enabled abis in case somehow we are invoked by an inner layer of multi-ness
+ local max_abi_len=0 a enabled_abis=( $(multilib_get_enabled_abis) )
+ for a in "${enabled_abis[@]}" ; do
(( max_abi_len < ${#a} )) && max_abi_len=${#a}
done
@@ -552,6 +595,12 @@ _EOF_
char pidstr[20], *target = NULL, env_abi_prefix[$(( ++max_abi_len + 1 ))], *env_abi;
const char *scratch;
+ int valid_abi(const char *abi) {
+ $( for abi in "${enabled_abis[@]}"; do
+ echo " if (strcmp(abi, \"${abi}\") == 0) return 1;"
+ done )
+ return 0;
+ }
int attempt_exec(const char *target_base, const char *abi_prefix) {
/* concatenate target_base and abi_prefix, and then attempt to execvp the result */
if (target) free(target);
@@ -580,7 +629,7 @@ _EOF_
snprintf(&pidstr[0], 20, "%d", (int) getpid());
setenv("${pn_random_random}", &pidstr[0], 1);
- /* Guess heuristically if we've been invoked during multilib-build ABI iteration. */
+ /* Determine if we've been invoked during multilib-build ABI iteration. */
env_abi_prefix[0] = '-';
env_abi_prefix[1] = '\0';
env_abi = &env_abi_prefix[1];
@@ -594,12 +643,15 @@ _EOF_
/* if env abi is the same as default, the fallback code does everything required, no need to continue. */
if (strcmp(scratch, &default_abi_prefix[1]) != 0) {
strncpy(env_abi, scratch, ${max_abi_len});
- dprintf(stderr, "${PF}-multilib-wrapper: Detected valid non-best-ABI multilib-build invocation under auspices of ABI \"%s\".\n", &env_abi[0]);
- attempt_exec(argv[0], &env_abi_prefix[0]);
- attempt_exec(&f[0], &env_abi_prefix[0]);
- fprintf(stderr, "${PF}-multilib-wrapper: During multilib-build invocation context with ABI \"%s\",\n", &env_abi[0]);
- fprintf(stderr, "${PF}-multilib-wrapper: unable to find appropriate ABI-specific target.\n");
- fprintf(stderr, "${PF}-multilib-wrapper: Falling-back to best-abi (\"%s\") invocation targets.\n", &default_abi_prefix[1]);
+ if (valid_abi(env_abi)) {
+ dprintf(stderr, "${PF}-multilib-wrapper: Detected valid non-best-ABI multilib-build invocation under auspices of ABI \"%s\".\n", &env_abi[0]);
+ attempt_exec(argv[0], &env_abi_prefix[0]);
+ attempt_exec(&f[0], &env_abi_prefix[0]);
+ fprintf(stderr, "${PF}-multilib-wrapper: During multilib-build invocation context with ABI \"%s\",\n", &env_abi[0]);
+ fprintf(stderr, "${PF}-multilib-wrapper: unable to find appropriate ABI-specific target.\n");
+ fprintf(stderr, "${PF}-multilib-wrapper: Falling-back to best-abi (\"%s\") invocation targets.\n", &default_abi_prefix[1]);
+ } else
+ fprintf(stderr, "${PF}-multilib-wrapper: unknown MULTILIB_BUILD_ABI value \"%s\" ignored.\n", &env_abi[0]);
}
}
attempt_exec(argv[0], &default_abi_prefix[0]);
@@ -625,9 +677,17 @@ _EOF_
einfo "Deploying compiled wrapper to staging area in \"/tmp/multilib-bin-wrappers/${dir}\"."
mkdir -p "${ED}tmp/multilib-bin-wrappers/${dir}" || die
cp -v "${f_c%.c}" "${ED}tmp/multilib-bin-wrappers/${f}" || die
+ eend $?
popd > /dev/null || die
}
multilib_for_best_abi do_executable_wrapper_compile
+ # make wrapper-executable like -ABI wrapped executable
+ chown -cv --reference="${root}${f}-${ABI}" "${ED}tmp/multilib-bin-wrappers/${f}" || \
+ die "Cant chown \"${ED}tmp/multilib-bin-wrappers/${f}\""
+ chmod -cv --reference="${root}${f}-${ABI}" "${ED}tmp/multilib-bin-wrappers/${f}" || \
+ die "Cant chmod \"${ED}tmp/multilib-bin-wrappers/${f}\""
+ touch --reference="${root}${f}-${ABI}" "${ED}tmp/multilib-bin-wrappers/${f}" || \
+ die "Cant touch \"${ED}tmp/multilib-bin-wrappers/${f}\""
fi
done
}
@@ -665,19 +725,6 @@ multilib_install_wrappers() {
if [[ -d "${ED}"tmp/multilib-bin-wrappers ]] ; then
einfo "Merging multilib executable wrappers"
- local f ref targ
- local MULTIBUILD_VARIANTS=( $(multilib_get_enabled_abis) )
- local b=$(multibuild_get_best_variant)
- while read -r f ; do
- f="${f#./}"
- ref="${ED}${f}-${b}"
- targ="${ED}tmp/multilib-bin-wrappers/${f}"
- [[ ( -d "${ref}" && -d "${targ}" ) || ( -f "${ref}" && -f "${targ}" ) ]] || continue
- # make $targ like $ref....
- chown -c --reference="${ref}" "${targ}" || die "Cant chown \"${targ}\""
- chmod -c --reference="${ref}" "${targ}" || die "Cant chmod \"${targ}\""
- touch -r --reference="${ref}" "${targ}" || die "Cant touch \"${targ}\""
- done < <( cd "${ED}"tmp/multilib-bin-wrappers || die ; find . -type f -o -type d -print )
multibuild_merge_root \
"${ED}"tmp/multilib-bin-wrappers "${root%/}"
rmdir "${ED}"tmp &>/dev/null # can fail if something else uses /tmp