diff options
author | Gregory M. Tuner <gmt@be-evil.net> | 2013-12-30 14:21:00 -0800 |
---|---|---|
committer | Gregory M. Tuner <gmt@be-evil.net> | 2013-12-30 14:21:00 -0800 |
commit | 66aedd76059e5f4c518d5e83a0bc2451eebeaeac (patch) | |
tree | cffa467903ff7a42ae5b96d2682cbcdb640b1622 /eclass/multilib-build.eclass | |
parent | eclass/multilib-build: export MULTILIB_BUILD_ABI (diff) | |
download | gmt-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.eclass | 147 |
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 |