# Copyright 1999-2014 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # $Header: $ # @ECLASS: multilib-build.eclass # @MAINTAINER: # gx86-multilib team # @AUTHOR: # Author: Michał Górny # @BLURB: flags and utility functions for building multilib packages # @DESCRIPTION: # The multilib-build.eclass exports USE flags and utility functions # necessary to build packages for multilib in a clean and uniform # manner. # # Please note that dependency specifications for multilib-capable # dependencies shall use the USE dependency string in ${MULTILIB_USEDEP} # to properly request multilib enabled. if [[ ! ${_MULTILIB_BUILD} ]]; then # EAPI=4 is required for meaningful MULTILIB_USEDEP. case ${EAPI:-0} in 4|5) ;; *) die "EAPI=${EAPI} is not supported" ;; esac inherit multibuild multilib # @ECLASS-VARIABLE: _MULTILIB_FLAGS # @INTERNAL # @DESCRIPTION: # The list of multilib flags and corresponding ABI values. If the same # flag is reused for multiple ABIs (e.g. x86 on Linux&FreeBSD), multiple # ABIs may be separated by commas. # # Please contact multilib before modifying this list. This way we can # ensure that every *preliminary* work is done and the multilib can be # extended safely. _MULTILIB_FLAGS=( abi_x86_32:x86,x86_fbsd abi_x86_64:amd64,amd64_fbsd abi_x86_x32:x32 abi_mips_n32:n32 abi_mips_n64:n64 abi_mips_o32:o32 ) # @ECLASS-VARIABLE: MULTILIB_COMPAT # @DEFAULT_UNSET # @DESCRIPTION: # List of multilib ABIs supported by the ebuild. If unset, defaults to # all ABIs supported by the eclass. # # This variable is intended for use in prebuilt multilib packages that # can provide binaries only for a limited set of ABIs. If ABIs need to # be limited due to a bug in source code, package.use.mask is # recommended instead. # # Example use: # @CODE # # Upstream provides binaries for x86 & amd64 only # MULTILIB_COMPAT=( abi_x86_{32,64} ) # @CODE # @ECLASS-VARIABLE: MULTILIB_USEDEP # @DESCRIPTION: # The USE-dependency to be used on dependencies (libraries) needing # to support multilib as well. # # Example use: # @CODE # RDEPEND="dev-libs/libfoo[${MULTILIB_USEDEP}] # net-libs/libbar[ssl,${MULTILIB_USEDEP}]" # @CODE # @ECLASS-VARIABLE: MULTILIB_ABI_FLAG # @DEFAULT_UNSET # @DESCRIPTION: # The complete ABI name. Resembles the USE flag name. # # This is set within multilib_foreach_abi(), # multilib_parallel_foreach_abi() and multilib-minimal sub-phase # functions. # # It may be null (empty) when the build is done on ABI not controlled # by a USE flag (e.g. on non-multilib arch or when using multilib # portage). The build will always be done for a single ABI then. # # Example value: # @CODE # abi_x86_64 # @CODE _multilib_build_set_globals() { local flags=( "${_MULTILIB_FLAGS[@]%:*}" ) if [[ ${MULTILIB_COMPAT[@]} ]]; then # Validate MULTILIB_COMPAT and filter out the flags. local f for f in "${MULTILIB_COMPAT[@]}"; do if ! has "${f}" "${flags[@]}"; then die "Invalid value in MULTILIB_COMPAT: ${f}" fi done flags=( "${MULTILIB_COMPAT[@]}" ) fi local usedeps=${flags[@]/%/(-)?} IUSE=${flags[*]} MULTILIB_USEDEP=${usedeps// /,} } _multilib_build_set_globals # @ECLASS-VARIABLE: _MULTILIB_ABI_WHITELIST # @INTERNAL # @DESCRIPTION: # Sanity checking variable enumerating known ABI values. A way to discover # situations where this eclass and PORTDIR have fallen out-of-sync. To update/check, use: # find /usr/portage/profiles -type f | xargs grep '^\(DEFAULT_\)ABI\{0,1\}=' # # Note that despite the name, these are not required to be multilib ABI's -- the complete list of ABI's # supported by the gentoo repository is supposed to go here. # # TODO: add prefix ABI's here! _MULTILIB_ABI_WHITELIST=( x86 amd64 x32 n32 n64 o32 s390 s390x sparc32 sparc64 ppc ppc64 amd64_fbsd x86_fbsd ) # @FUNCTION: get_multilib_build_abis # @USAGE: [--dependmode] # @DESCRIPTION: # Returns a list of abis with multiple-abi multilib-build support # This is a global list of all ABI values which have corresponding # flags in the global hard-coded database of multibuild-compatible ABI's # (_MULTILIB_FLAGS). As of this writing, it returns at least these: # # "x86 x86_fbsd amd64 amd64_fbsd x32 n32 n64 o32" # # Results go to standard output. If the current DEFAULT_ABI is # not present in the list, it will be appended; otherwise, # it will be placed at the end of the list -- therefore, # the standard result is not a suitable basis for the generation of # package-manager-cached metadata. # # However, if the --dependmode argument is supplied, then this # API will act as though the default ABI was "default" and therefore # act in a completely deterministic manner suitable for this purpose. get_multilib_build_abis() { [[ $# -gt 1 ]] && die "${FUNCNAME} takes at most one argument" local rslt=${_MULTILIB_FLAGS[*]##*:} rslt=" ${rslt//,/ } " if [[ ${1} == --dependmode ]] ; then rslt=$(echo ${rslt} default) else rslt=$(echo ${rslt/ ${DEFAULT_ABI:-default} / } ${DEFAULT_ABI:-default}) fi echo ${rslt} } # @FUNCTION: multilib_abi_flag # @USAGE: # @DESCRIPTION: # Return the use-flag corresponding to the specified multilib # ABI on stdout. If no corresponding flag is found, returns # nothing. multilib_abi_flag() { debug-print-function ${FUNCNAME} "${@}" local abi="$1" i found m_abis m_abi m_flag for i in "${_MULTILIB_FLAGS[@]}"; do m_abis=${i#*:} m_flag=${i%:*} # split on ,; we can't switch IFS for function scope because # paludis is broken (bug #486592), and switching it locally # for the split is more complex than cheating like this for m_abi in ${m_abis//,/ }; do if [[ ${m_abi} == ${abi} ]] ; then echo "${m_flag}" return 0 fi done done debug-print "${FUNCNAME}: No multilib abi \"${abi}\" found, returning nothing" return 1 } # @FUNCTION: multilib_flag_abi # @USAGE: # @DESCRIPTION: # Returns, when applicable, any active multilib ABI corresponding # to the provided abi_ USE_EXPAND USE-flag, by way of # output to standard output. # # Due to the recycling of use-flags in the multilib-build # framework between ABIs, this API cannot return purely # functional package-manager-independant information # suitable for cacheable ebuild settings, such as those # in generated USE dependencies. # # However, for many other purposes it is quite practical to # want to map back freely from flag to ABI values. This tries. # # If no such mapping is to be found, this does not fall back to # the default ABI. It instead will silently return a nonzero # failure code. multilib_flag_abi() { debug-print-function ${FUNCNAME} "${@}" local i req_flag=${1} test_flag test_abis test_abi enabled_abi for i in "${_MULTILIB_FLAGS[@]}"; do test_flag=${i%:*} [[ ${test_flag} == ${req_flag} ]] || continue test_abis=${i#*:} for test_abi in ${test_abis//,/ }; do for enabled_abi in $(get_all_abis); do if [[ ${enabled_abi} == ${test_abi} ]] ; then # a match! return it. echo "${test_abi}" return 0 fi done done done return 1 } # @FUNCTION: multilib_get_enabled_abis # @DESCRIPTION: # Return the ordered list of enabled ABIs if multilib builds # are enabled. The best (most preferred) ABI will come last. # # If multilib is disabled, the default ABI will be returned # in order to enforce consistent testing with multilib code. multilib_get_enabled_abis() { debug-print-function ${FUNCNAME} "${@}" local pairs=( $(multilib_get_enabled_abi_pairs) ) echo "${pairs[@]#*.}" } # @FUNCTION: multilib_get_enabled_abi_pairs # @DESCRIPTION: # Return the ordered list of enabled . pairs # if multilib builds are enabled. The best (most preferred) # ABI will come last. # # If multilib is disabled, the default ABI will be returned # along with empty . multilib_get_enabled_abi_pairs() { debug-print-function ${FUNCNAME} "${@}" local abis=( $(get_all_abis) ) local abi i found for abi in "${abis[@]}"; do for i in "${_MULTILIB_FLAGS[@]}"; do local m_abis=${i#*:} m_abi local m_flag=${i%:*} # split on ,; we can't switch IFS for function scope because # paludis is broken (bug #486592), and switching it locally # for the split is more complex than cheating like this for m_abi in ${m_abis//,/ }; do if [[ ${m_abi} == ${abi} ]] && use_if_iuse "${m_flag}"; then echo "${m_flag}.${abi}" found=1 break 2 fi done done done if [[ ! ${found} ]]; then # ${ABI} can be used to override the fallback (multilib-portage), # ${DEFAULT_ABI} is the safe fallback. local abi=${ABI:-${DEFAULT_ABI:-default}} debug-print "${FUNCNAME}: no ABIs enabled, fallback to ${abi}" debug-print "${FUNCNAME}: ABI=${ABI}, DEFAULT_ABI=${DEFAULT_ABI}" echo ".${abi}" fi } # @FUNCTION: _multilib_multibuild_wrapper # @USAGE: ... # @INTERNAL # @DESCRIPTION: # Initialize the environment for ABI selected for multibuild. _multilib_multibuild_wrapper() { debug-print-function ${FUNCNAME} "${@}" local ABI=${MULTIBUILD_VARIANT#*.} # fixme: deprecated -- try to use MULTIIB_ABI_FLAG (but not exported, so...?) local MULTILIB_BUILD_ABI="${ABI}" local MULTILIB_ABI_FLAG=${MULTIBUILD_VARIANT%.*} export MULTILIB_BUILD_ABI multilib_toolchain_setup "${ABI}" "${@}" } # @FUNCTION: multilib-build_run_in_build_dir # @DESCRIPTION: # Run a command in the build dir using _multilib_multibuild_wrapper multilib-build_run_in_build_dir() { debug-print-function "${FUNCNAME}" "$@" run_in_build_dir _multilib_multibuild_wrapper "$@" } # @FUNCTION: multilib_tc_export # @DESCRIPTION: # Code running in the context of _multilib_multibuild_wrapper cannot use tc_export # from toolchain-funcs.eclass (at least, not without some care), as this will # munge the settings from multilib_toolchain_setup. This might be fixable; however, # until some solution is arrived at to automagically do the right thing there, # routing that code through this wrapper function should provide a reliable-ish # solution to the problem. The basic recipe is to replace: # @CODE # some_function() { # tc_export X Y Z # foo # bar # } # @CODE # with # @CODE # some_function() { # MULTILIB_TC_EXPORT_VARS="X Y Z" multilib_tc_export _stuff_to_do # } # # _stuff_to_do() { # foo # bar # } # # By design, the exported variables will NOT persist in any way, so if you are # adapting code that expects those exports to persist across phase function # boundaries, you will have to re-wrap the exports. This sucks but the only # alternative is a lot of confusion. Note that this code will also not work # properly unless you are executing in a context where multilib_toolchain_setup # has already run. The principal advantage of this is that cleanup will happen # automatically once your wrapped function completes. multilib_tc_export() { for var in ${MULTILIB_TC_EXPORT_VARS} ; do case ${var} in CHOST|CBUILD|AS|CC|CXX|LD|PKG_CONFIG_LIBDIR|PKG_CONFIG_PATH) # if already managed by multilib_toolchain_setup, keep it. However, to # ensure that callers can uniformly expect the variable to be scope-localized, # localize it. if multilib_is_native_abi ; then eval "local ${var}=\"$(tc-get${var})\"" else eval "local ${var}=\"${!var}\"" fi eval "export ${var}" ;; *) # non multilib_toolchain_setup variables are just localized eval "local ${var}" tc-export $var ;; esac done "$@" } # @FUNCTION: multilib_foreach_abi # @USAGE: ... # @DESCRIPTION: # If multilib support is enabled, sets the toolchain up for each # supported ABI along with the ABI variable and correct BUILD_DIR, # and runs the given commands with them. # # If multilib support is disabled, it just runs the commands. No setup # is done. multilib_foreach_abi() { debug-print-function ${FUNCNAME} "${@}" local MULTIBUILD_VARIANTS=( $(multilib_get_enabled_abi_pairs) ) multibuild_foreach_variant _multilib_multibuild_wrapper "${@}" } # @FUNCTION: multilib_parallel_foreach_abi # @USAGE: ... # @DESCRIPTION: # If multilib support is enabled, sets the toolchain up for each # supported ABI along with the ABI variable and correct BUILD_DIR, # and runs the given commands with them. The commands are run # in parallel with number of jobs being determined from MAKEOPTS. # # If multilib support is disabled, it just runs the commands. No setup # is done. # # Useful for running configure scripts. multilib_parallel_foreach_abi() { debug-print-function ${FUNCNAME} "${@}" local MULTIBUILD_VARIANTS=( $(multilib_get_enabled_abi_pairs) ) multibuild_parallel_foreach_variant _multilib_multibuild_wrapper "${@}" } # @ECLASS-VARIABLE: MULTILIB_UNCHECKED_HEADERS # @DESCRIPTION: # A list of header files to ignore when checking for header conflicts. # If an ebuild or eclass author has implemented their own solution # to a possible header conflict, (if appropriate, that solution may # simply be to ignore it, which would typically result in the # native ABI's header being installed. # # This variable has to be a bash array. Paths shall be relative to # installation root (${ED}), and name regular files. # # Note that if a header appears in MULTILIB_WRAPPED_HEADERS, adding # it to this array, as well, will not prevent the header from being # wrapped. # # Example: # @CODE # MULTILIB_UNCHECKED_HEADERS=( # /usr/include/foobar/config.h # ) # @CODE # @FUNCTION: multilib_check_headers # @DESCRIPTION: # Check whether the header files are consistent between ABIs. # # This function needs to be called after each ABI's installation phase. # It obtains the header file checksums and compares them with previous # runs (if any). Dies if header files differ. multilib_check_headers() { _multilib_check_header_filter() { local exgrep="" hdr for hdr in "${MULTILIB_UNCHECKED_HEADERS[@]}" ; do exgrep="${exgrep}${exgrep:+|}\s${ED}${hdr#/}\$" done if [[ ${exgrep} ]]; then egrep -v "${exgrep}" else tee /dev/null fi return 0 } _multilib_header_cksum() { [[ -d ${ED}usr/include ]] && \ find "${ED}"usr/include -type f -exec cksum {} + | \ _multilib_check_header_filter | sort -k2 } local cksum=$(_multilib_header_cksum) local cksum_file=${T}/.multilib_header_cksum if [[ -f ${cksum_file} ]]; then local cksum_prev=$(< "${cksum_file}") if [[ ${cksum} != ${cksum_prev} ]]; then echo "${cksum}" > "${cksum_file}.new" eerror "Header files have changed between ABIs." if type -p diff &>/dev/null; then eerror "$(diff -du "${cksum_file}" "${cksum_file}.new")" else eerror "Old checksums in: ${cksum_file}" eerror "New checksums in: ${cksum_file}.new" fi die "Header checksum mismatch, aborting." fi else echo "${cksum}" > "${cksum_file}" fi } # @FUNCTION: multilib_copy_sources # @DESCRIPTION: # Create a single copy of the package sources for each enabled ABI. # # The sources are always copied from initial BUILD_DIR (or S if unset) # to ABI-specific build directory matching BUILD_DIR used by # multilib_foreach_abi(). multilib_copy_sources() { debug-print-function ${FUNCNAME} "${@}" local MULTIBUILD_VARIANTS=( $(multilib_get_enabled_abi_pairs) ) multibuild_copy_sources } # @ECLASS-VARIABLE: MULTILIB_WRAPPED_HEADERS # @DESCRIPTION: # A list of headers to wrap for multilib support. The listed headers # will be moved to a non-standard location and replaced with a file # including them conditionally to current ABI. # # This variable has to be a bash array. Paths shall be relative to # installation root (${ED}), and name regular files. Recursive wrapping # is not supported. # # Please note that header wrapping is *discouraged*. It is preferred to # install all headers in a subdirectory of libdir and use pkg-config to # locate the headers. Some C preprocessors will not work with wrapped # headers. # # If a header is preceeded by a carat-symbol ('^'), then the header- # wrapper will not be generated. Instead, the headers are moved # to their normal non-standard location -- specifically, # from /usr/include/${whatever}, a header # will be moved to /usr/include/${CHOST}/${whatever} -- and no # wrapper is generated. # # This may be preferable if the header in question is likely to # cause confusion in overzealous configure scripts and you prefer to # force explicit acquisition of the correct header file by # consumers. # # Example: # @CODE # MULTILIB_WRAPPED_HEADERS=( # /usr/include/foobar/config.h # ^/usr/include/poof-noconfig.h # ) # @CODE # @ECLASS-VARIABLE: MULTILIB_WRAPPED_EXECUTABLES # @DESCRIPTION: # 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. # # 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. The wrapper works by checking for a MULTILIB_BUILD_ABI # environment variable. # # 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, simply by omitting the executable from # MULTILIB_WRAPPED_EXECUTABLES). # # 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 '@'-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 # or override that process, for example, in order to facilitate # cross-compiles. # # Example: # @CODE # MULTILIB_WRAPPED_EXECUTABLES=( # /usr/bin/script-engine-config # @/usr/bin/script-engine # ) # @CODE # # FIXME: This feature should be merged into the MULTILIB_CHOST_TOOLS feature # @ECLASS-VARIABLE: MULTILIB_CHOST_TOOLS # @DESCRIPTION: # A list of tool executables to preserve for each multilib ABI. # The listed executables will be renamed to ${CHOST}-${basename}, # and the native variant will be symlinked to the generic name. # # This variable has to be a bash array. Paths shall be relative to # installation root (${ED}), and name regular files or symbolic # links to regular files. Recursive wrapping is not supported. # # If a symbolic link is passed, both the symlink path and target # will be changed. As a result, the symlink target is expected # to be wrapped as well (either by listing it in MULTILIB_CHOST_TOOLS # or externally). # # Please note that tool wrapping is *discouraged*. It is preferred to # install pkg-config files for each ABI, and require reverse # dependencies to use that. # # Packages that search for tools properly (e.g. using AC_PATH_TOOL # macro) will find the wrapper executables automatically. Other packages # will need explicit override of tool paths. # # Example: # @CODE # MULTILIB_CHOST_TOOLS=( # /usr/bin/foo-config # ) # @CODE # @FUNCTION: multilib_prepare_wrappers # @USAGE: [] # @DESCRIPTION: # Perform the preparation of all kinds of wrappers for the current ABI. # This function shall be called once per each ABI, after installing # the files to be wrapped. # # Takes an optional custom from which files will be # used. If no root is specified, uses ${ED}. # # The files to be wrapped are specified using separate variables, # e.g. MULTILIB_WRAPPED_HEADERS. Those variables shall not be changed # between the successive calls to multilib_prepare_wrappers # and multilib_install_wrappers. # # After all wrappers are prepared, multilib_install_wrappers shall # be called to commit them to the installation tree. multilib_prepare_wrappers() { debug-print-function ${FUNCNAME} "${@}" # ensure no lingering diropts from elsewhere won't ruin anybody's day # (fixes unfiled gmt-overlay bug: openssl headers permission denied) local DIROPTIONS diropts 0755 [[ ${#} -le 1 ]] || die "${FUNCNAME}: too many arguments" local root=${1:-${ED}} # ensure root has a single trailing slash [[ ${root} =~ /+$ ]] && root="${root%${BASH_REMATCH[0]}}" root="${root}/" local f local generate_wrapper if [[ ${MULTILIB_WRAPPED_HEADERS[@]} ]]; then # If abi_flag is unset, then header wrapping is unsupported on # this ABI. This means the arch doesn't support multilib at all # -- in this case, the headers are not wrapped and everything # works as expected. if [[ ${MULTILIB_ABI_FLAG} ]]; then for f in "${MULTILIB_WRAPPED_HEADERS[@]}"; do local generate_wrapper=yes [[ ${f:0:1} == ^ ]] && generate_wrapper=no f="${f#^}" # drop leading slash if it's there [[ ${f} =~ ^/+ ]] && f="${f#${BASH_REMATCH[0]}}" if [[ ${f} != usr/include/* ]]; then die "Wrapping headers outside of /usr/include is not supported at the moment." fi # and then usr/include f="${f#usr/include}" local dir="${f%/*}" # Some ABIs may have install less files than others. if [[ ${generate_wrapper} == yes && -f ${root}usr/include${f} ]]; then local wrapper=${ED}tmp/multilib-include${f} if [[ ! -f "${wrapper}" ]]; then einfo "generating multilib wrapper for header ${root}usr/include${f}" dodir "/tmp/multilib-include${dir}" # a generic template cat > "${wrapper}" <<_EOF_ /* This file is auto-generated by multilib-build.eclass * as a multilib-friendly wrapper. For the original content, * please see the files that are #included below. */ #if defined(__x86_64__) /* amd64 */ # if defined(__ILP32__) /* x32 ABI */ # error "abi_x86_x32 not supported by the package." # else /* 64-bit ABI */ # error "abi_x86_64 not supported by the package." # endif #elif defined(__i386__) /* plain x86 */ # error "abi_x86_32 not supported by the package." #elif defined(__mips__) # if(_MIPS_SIM == _ABIN32) /* n32 */ # error "abi_mips_n32 not supported by the package." # elif(_MIPS_SIM == _ABI64) /* n64 */ # error "abi_mips_n64 not supported by the package." # elif(_MIPS_SIM == _ABIO32) /* o32 */ # error "abi_mips_o32 not supported by the package." # endif #elif defined(__sparc__) # if defined(__arch64__) # error "abi_sparc_64 not supported by the package." # else # error "abi_sparc_32 not supported by the package." # endif #elif defined(__s390__) # if defined(__s390x__) # error "abi_s390_64 not supported by the package." # else # error "abi_s390_32 not supported by the package." # endif #elif defined(__powerpc__) # if defined(__powerpc64__) # error "abi_ppc_64 not supported by the package." # else # error "abi_ppc_32 not supported by the package." # endif #else # error "No ABI matched, please report a bug to bugs.gentoo.org" #endif _EOF_ fi # [[ ! -f "${wrapper}" ]] if ! grep -q "${MULTILIB_ABI_FLAG} " "${wrapper}" then die "Flag ${MULTILIB_ABI_FLAG} not listed in wrapper template. Please report a bug to https://bugs.gentoo.org." fi # ! grep -q "${MULTILIB_ABI_FLAG} " "${wrapper}" # Note: match a space afterwards to avoid collision potential. sed -e "/${MULTILIB_ABI_FLAG} /s&error.*&include <${CHOST}${f}>&" \ -i "${wrapper}" || die # Hack for emul-linux-x86 compatibility. # It assumes amd64 will come after x86, and will use amd64 # headers if no specific x86 headers were installed. if [[ ${ABI} == amd64 ]]; then sed -e "/abi_x86_32 /s&error.*&include <${CHOST}${f}>&" \ -i "${wrapper}" || die fi fi # [[ ${generate_wrapper} == yes && -f ${root}usr/include${f} ]] # move the header, if extant, whether ^wrapped or not # $CHOST will have been set by multilib_toolchain_setup if [[ -f ${root}usr/include${f} ]] ; then dodir "/tmp/multilib-include/${CHOST}${dir}" mv "${root}usr/include${f}" "${ED}tmp/multilib-include/${CHOST}${dir}/" || die else # it's very probably a bug or version-crufty thing... perhaps this would # be more elegant as an array of headers for which assymetry is allowed # without triggering a warning. [[ ${MULTILIB_DONT_WARN_ABOUT_MISSING_WRAPPED_HEADERS} ]] || \ ewarn "multilib wrapped header \"/usr/include${f}\" not generated for abi ${ABI}" fi done # for f in "${MULTILIB_WRAPPED_HEADERS[@]}" fi # [[ ${MULTILIB_ABI_FLAG} ]] fi # [[ ${MULTILIB_WRAPPED_HEADERS[@]} ]] for f in "${MULTILIB_WRAPPED_EXECUTABLES[@]}" ; do 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}" [[ -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]}}" [[ ${generate_wrapper} == yes && ! -d "${ED}tmp/multilib-bin-wrappers/${dir}" ]] && \ dodir "/tmp/multilib-bin-wrappers/${dir}" if [[ -f "${root}${f}-${ABI}" ]] ; then # In order to support quick-and-dirty re-installation using ebuild install, # we need to either (a) permit these files to be overwritten or # (b) not wrap them. Here I've chosen (a), but we dump this warning # in case this represents a real name collision. ewarn ewarn "Name collision wrapping multilib executable \"${f}\"." ewarn "Destination \"${root}${f}-${ABI}\" will be over-written." ewarn rm -f "${root}${f}-${ABI}" || die fi # [[ -f "${root}${f}-${ABI}" ]] if [[ ${generate_wrapper} == yes ]] ; then cp -T "${root}${f}" "${root}${f}-${ABI}" || die # make wrapper like original chown -c --reference="${root}${f}" "${root}${f}-${ABI}" || die "Cant chown \"${root}${f}-${ABI}\"" chmod -c --reference="${root}${f}" "${root}${f}-${ABI}" || die "Cant chmod \"${root}${f}-${ABI}\"" if has xattr ${FEATURES} ; then # TODO : fi touch --reference="${root}${f}" "${root}${f}-${ABI}" || die "Cant touch \"${root}${f}-${ABI}\"" # if the file is redundantly in MULTILIB_CHOST_TOOLS, we mustn't remove it. local remove_it=yes for f1 in "${MULTILIB_CHOST_TOOLS[@]}" ; do # strip leading slashes f1="${f1#/}" [[ ${f1} =~ ^/+ ]] && f1="${f1#${BASH_REMATCH[0]}}" # and then usr/include f1="${f1#usr/include}" if [[ ${f} == ${f1} ]] ; then remove_it=no break fi done # for f1 in "${MULTILIB_CHOST_TOOLS[@]} [[ ${remove_it} == yes ]] && { rm -f "${root}${f}" || die ; } else # [[ ${generate_wrapper} == yes ]] ln -T "${root}${f}" "${root}${f}-${ABI}" || die # make wrapper like original chown -c --reference="${root}${f}" "${root}${f}-${ABI}" || die "Cant chown \"${root}${f}-${ABI}\"" chmod -c --reference="${root}${f}" "${root}${f}-${ABI}" || die "Cant chmod \"${root}${f}-${ABI}\"" if has xattr ${FEATURES} ; then # TODO : fi touch --reference="${root}${f}" "${root}${f}-${ABI}" || die "Cant touch \"${root}${f}-${ABI}\"" fi # [[ ${generate_wrapper} != yes ]] if multilib_is_native_abi && \ [[ ${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 local pn_random_random="${PN}_${RANDOM}_${RANDOM}" local fwrap_dir="${WORKDIR}/multilib-bin-wrappers/${dir}" local f_c="${f##*/}.c" mkdir -p ${fwrap_dir} || die "Cannot create \"${fwrap_dir}\"." cat > "${fwrap_dir}/${f_c}" <<-_EOF_ #include #include #include #include #define DEBUG() ($( if has debug ${IUSE} && use debug; then echo 1; else echo 0; fi )) #define dprintf if (DEBUG()) fprintf static const char default_abi_prefix[] = "-$(x=$(multibuild_get_best_variant); echo ${x#*.})"; static const char f[] = "${EPREFIX}/${f}"; int main(int argc, char *argv[]) { 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); /* the '+1' here is for the hyphen -- room for the '\0' is provided by the constant */ target = (char *) malloc(strlen(target_base) + ${max_abi_len} + 1); if (!target) { fprintf(stderr, "${PF}-multilib-wrapper: memory allocation failure.\n"); exit(2); } strcpy(target, target_base); strncat(target, abi_prefix, ${max_abi_len}); dprintf(stderr, "${PF}-multilib-wrapper: Searching for possible target: \"%s\".\n", target); execvp(target, argv); dprintf(stderr, "${PF}-multilib-wrapper: Target binary matching \"%s\" not found.\n", target); } dprintf(stderr, "${PF}-multilib-wrapper called as: %s\n", argv[0]); /* circuit-breaker to prevent any possible self-exec() bomb */ if (scratch = getenv("${pn_random_random}")) { if ((int) getpid() == atoi(scratch)) { fprintf(stderr, "${PF}-multilib-wrapper: odd, apparent exec bomb: crashing.\n"); exit(2); } } snprintf(&pidstr[0], 20, "%d", (int) getpid()); setenv("${pn_random_random}", &pidstr[0], 1); /* 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]; scratch = getenv("MULTILIB_BUILD_ABI"); if (scratch) { if (strlen(scratch) >= ${max_abi_len}) { fprintf(stderr, "${PF}-multilib-wrapper: unexpectedly long ABI environment variable\n"); fprintf(stderr, "${PF}-multilib-wrapper: value detected: \"%s.$(( max_abi_len * 20 ))\".\n", scratch); exit(2); } /* 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}); 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]); attempt_exec(&f[0], &default_abi_prefix[0]); fprintf(stderr, "${PF}-multilib-wrapper: Invoked as \"%s\", unable to find suitable executable to invoke. Giving up.\n", argv[0]); exit(2); } _EOF_ einfo "Performing wrapper compilation in \"${fwrap_dir}\"." pushd "${fwrap_dir}" > /dev/null || die local cc=${CC:-$(tc-getCC)} ebegin "Compiling wrapper: ${cc} ${CFLAGS} ${f_c} -c -o ${f_c%.c}.o" ${cc} ${CFLAGS} "${f_c}" -c -o "${f_c%.c}.o" || \ { eend $? ; die "executable wrapper compilation failed for ${f_c} in \"${fwrap_dir}\"" ; } einfo "Linking wrapper: ${cc} ${LDFLAGS} ${f_c%.c}.o -o ${f_c%.c}" ${cc} ${LDFLAGS} "${f_c%.c}.o" -o "${f_c%.c}" || \ { eend $? ; die "executable wrapper linking failed for ${f_c%.c}.o in \"${fwrap_dir}\"" ; } einfo "Deploying compiled wrapper to staging area." mkdir -p "${ED}tmp/multilib-bin-wrappers/${dir}" || die cp "${f_c%.c}" "${ED}tmp/multilib-bin-wrappers/${f}" || die eend $? popd > /dev/null || die # make wrapper-executable like -ABI wrapped executable chown -c --reference="${root}${f}-${ABI}" "${ED}tmp/multilib-bin-wrappers/${f}" || \ die "Cant chown \"${ED}tmp/multilib-bin-wrappers/${f}\"" chmod -c --reference="${root}${f}-${ABI}" "${ED}tmp/multilib-bin-wrappers/${f}" || \ die "Cant chmod \"${ED}tmp/multilib-bin-wrappers/${f}\"" if has xattr ${FEATURES} ; then # TODO : fi touch --reference="${root}${f}-${ABI}" "${ED}tmp/multilib-bin-wrappers/${f}" || \ die "Cant touch \"${ED}tmp/multilib-bin-wrappers/${f}\"" fi # multilib_is_native_abi && [[ ${generate_wrapper} == yes && ! -f "${ED}tmp/multilib-bin-wrappers/${f}" ]] done # for f in "${MULTILIB_WRAPPED_EXECUTABLES[@]}" # we put these last to ensure they peaceful coexistence with MULTILIB_WRAPPED_EXECUTABLES # until MULTILIB_WRAPPED_EXECUTABLES can be merged into MULTILIB_CHOST_TOOLS. if [[ ${COMPLETE_MULTILIB} == yes ]]; then # symlink '${CHOST}-foo -> foo' to support abi-wrapper while # keeping ${CHOST}-foo calls correct. for f in "${MULTILIB_CHOST_TOOLS[@]}"; do # drop leading slash if it's there f=${f#/} local dir=${f%/*} local fn=${f##*/} ln -s "${fn}" "${root}/${dir}/${CHOST}-${fn}" || die done return fi # [[ ${COMPLETE_MULTILIB} == yes ]] for f in "${MULTILIB_CHOST_TOOLS[@]}"; do # drop leading slash if it's there f=${f#/} local dir=${f%/*} local fn=${f##*/} # decide if we behave like upstream, or if we are skipping the whole business about # linking the native program to the CHOST executable because that was handled by # a redundant @wrapped MULTILIB_WRAPPED_EXECUTABLE local dosymlink=yes for f1 in "${MULTILIB_WRAPPED_EXECUTABLES[@]}" ; do [[ ${f1:0:1} == @ ]] || continue f1=${f1:1} # strip leading slashes f1="${f1#/}" [[ ${f1} =~ ^/+ ]] && f1="${f1#${BASH_REMATCH[0]}}" # and then usr/include f1="${f1#usr/include}" if [[ ${f} == ${f1} ]] ; then dosymlink=no break fi done # for f1 in "${MULTILIB_WRAPPED_EXECUTABLES[@]}" # don't rewrite symlink targets if we are relying on redundant @wrapping! # that would be bad (even if it worked it'd be awfully confusing) if [[ ${dosymlink} == yes && -L "${root}${f}" ]]; then # rewrite the symlink target local target=$(readlink "${root}${f}") local target_dir local target_fn=${target##*/} [[ ${target} == */* ]] && target_dir=${target%/*} rm "${root}${f}" || die ln -f -s "${target_dir+${target_dir}/}${CHOST}-${target_fn}" \ "${root}${f}" || die elif [[ -L "${root}${f}" ]]; then # [[ ${dosymlink} == yes && -L "${root}${f}" ]] ewarn "============ hell no ===============" ewarn "\"${root}${f}\" is installed as a symlink by upstream or ebuild code; meanwhile," ewarn "it is both @wrapped in MULTILIB_WRAPPED_EXECUTABLES and present in MULTILIB_CHOST_TOOLS." ewarn "If that makes perfect sense to you, you're smarter than me." ewarn "====================================" die "\"${root}${f}\" seems 'semantically oversaturated'; giving up the ghost." fi # [[ ( ${dosymlink} != yes || -L "${root}${f}" ) && -L "${root}${f}" # move whatever it is to the ${CHOST}-prefixed name mv "${root}${f}" "${root}${dir}/${CHOST}-${fn}" || die # symlink the native one back (unless it's redundantly @wrapped) if multilib_is_native_abi && [[ ${dosymlink} == yes ]]; then ln -s "${CHOST}-${fn}" "${root}${f}" || die einfo "MULTILIB_CHOST_TOOLS: re-created \"${root}${f}\" as a symlink to \"${CHOST}-${fn}\"." fi done # for f in "${MULTILIB_CHOST_TOOLS[@]}" } # @FUNCTION: multilib_install_wrappers # @USAGE: [] # @DESCRIPTION: # Install the previously-prepared wrappers. This function shall # be called once, after all wrappers were prepared. # # Takes an optional custom to which the wrappers will be # installed. If no root is specified, uses ${ED}. There is no need to # use the same root as when preparing the wrappers. # # The files to be wrapped are specified using separate variables, # e.g. MULTILIB_WRAPPED_HEADERS. Those variables shall not be changed # between the calls to multilib_prepare_wrappers # and multilib_install_wrappers. multilib_install_wrappers() { debug-print-function ${FUNCNAME} "${@}" [[ ${#} -le 1 ]] || die "${FUNCNAME}: too many arguments" [[ ${COMPLETE_MULTILIB} == yes ]] && return local root=${1:-${ED}} # ensure root has a single trailing slash [[ ${root} =~ /+$ ]] && root="${root%${BASH_REMATCH[0]}}" root="${root}/" if [[ -d "${ED}"tmp/multilib-include ]]; then einfo "Merging multilib include wrappers" multibuild_merge_root \ "${ED}"tmp/multilib-include "${root}"usr/include rmdir "${ED}"tmp &>/dev/null # can fail if something else uses /tmp fi if [[ -d "${ED}"tmp/multilib-bin-wrappers ]] ; then einfo "Merging multilib executable wrappers" multibuild_merge_root \ "${ED}"tmp/multilib-bin-wrappers "${root%/}" rmdir "${ED}"tmp &>/dev/null # can fail if something else uses /tmp fi } # @FUNCTION: multilib_is_native_abi # @DESCRIPTION: # Determine whether the currently built ABI is the profile native. # Return true status (0) if that is true, otherwise false (1). multilib_is_native_abi() { debug-print-function ${FUNCNAME} "${@}" [[ ${#} -eq 0 ]] || die "${FUNCNAME}: too many arguments" [[ ${COMPLETE_MULTILIB} == yes || ${ABI} == ${DEFAULT_ABI} ]] } # @FUNCTION: multilib_build_binaries # @DESCRIPTION: # Deprecated alias for multilib_is_native_abi multilib_build_binaries() { debug-print-function ${FUNCNAME} "${@}" eqawarn "QA warning: multilib_build_binaries is deprecated. Please use the equivalent" eqawarn "multilib_is_native_abi function instead." multilib_is_native_abi "${@}" } # @FUNCTION: multilib_is_best_abi # @DESCRIPTION: # Deprecated alias for multilib_is_native_abi. multilib_is_best_abi() { debug-print-function ${FUNCNAME} "${@}" eqawarn "QA warning: multilib_is_best_abi is deprecated. Please use the equivalent" eqawarn "multilib_is_native_abi function instead." multilib_is_native_abi "${@}" } # @FUNCTION: multilib_get_best_abi # @DESCRIPTION: # Depreciated function to return the best ABI. Just returns the native ABI # instead. :( multilib_get_best_abi() { # yes, the >&2 may actually do something... see isolated-functions.sh eqawarn "QA warning: multilib_is_best_abi is deprecated. Please use the equivalent" >&2 eqawarn "multilib_is_native_abi function instead." >&2 multilib_get_native_abi "$@" } # @FUNCTION: multilib_get_native_abi # @DESCRIPTION: # Depreciated function to return the best ABI. Just returns the native ABI # instead. :( multilib_get_native_abi() { echo "${DEFAULT_ABI:-default}" } # @FUNCTION: multilib_native_use_with # @USAGE: [ []] # @DESCRIPTION: # Output --with configure option alike use_with if USE is enabled # and executables are being built (multilib_is_native_abi is true). # Otherwise, outputs --without configure option. Arguments are the same # as for use_with in the EAPI. multilib_native_use_with() { if multilib_is_native_abi; then use_with "${@}" else echo "--without-${2:-${1}}" fi } # @FUNCTION: multilib_non_native_use_with # @USAGE: [ []] # @DESCRIPTION: # Output --with configure option like use_with if USE is enabled # and multilib_is_native_abi is false. # Otherwise, outputs --without configure option. Arguments are the same # as for use_with in the EAPI. multilib_non_native_use_with() { if multilib_is_native_abi; then echo "--without-${2:-${1}}" else use_with "${@}" fi } # @FUNCTION: multilib_native_use_enable # @USAGE: [ []] # @DESCRIPTION: # Output --enable configure option like use_enable if USE # is enabled multilib_is_native_abi is true. Otherwise, outputs # --disable configure option. Arguments are the same as for # use_enable in the EAPI. multilib_native_use_enable() { if multilib_is_native_abi; then use_enable "${@}" else echo "--disable-${2:-${1}}" fi } # @FUNCTION: multilib_non_native_use_enable # @USAGE: [ []] # @DESCRIPTION: # Output --enable configure option like use_enable if USE # is enabled and multilib_is_native_abi is false. # Otherwise, outputs --disable configure option. Arguments are # the same as for use_enable in the EAPI. multilib_non_native_use_enable() { if multilib_is_native_abi; then echo "--disable-${2:-${1}}" else use_enable "${@}" fi } # @FUNCTION: multilib_native_usex # @USAGE: [ [ [ []]]] # @DESCRIPTION: # Output the concatenation of (or 'yes' if unspecified) # and if USE is enabled and executables are being built # (multilib_is_native_abi is true). Otherwise, output the concatenation # of (or 'no' if unspecified) and . Arguments # are the same as for usex in the EAPI. # # Note: in EAPI 4 you need to inherit eutils to use this function. multilib_native_usex() { if multilib_is_native_abi; then usex "${@}" else echo "${3-no}${5}" fi } # @FUNCTION: multilib_native_enable # @USAGE: [] # @DESCRIPTION: # When multilib_is_native_abi is true, returns (via standard output) "--enable-flagname" # (or "--enable-flagname=value", when the second argument is provided); when multilib_is_native_abi # is false, the second argument is ignored and the output is always "--disable-flagname". # An analogue of use_enable, but lacking use_with's first argument -- instead of testing a # provided use-flag, it instead tests multilib_is_native_abi. multilib_native_enable() { [[ -z "$1" ]] && die "multilib_native_enable called without a parameter." # ___eapi_use_enable_and_use_with_support_empty_third_argument if [[ ! ${EAPI:-0} =~ ^(0|1|2|3)$ ]] ; then local BW_SUFFIX=${2+=$2} else local BW_SUFFIX=${2:+=$2} fi if multilib_is_native_abi ; then echo "--enable-${1}${BW_SUFFIX}" else echo "--disable-${1}" fi return 0 } # @FUNCTION: multilib_native_with # @USAGE: [] # @DESCRIPTION: # When multilib_is_native_abi is true, returns (via standard output) "--with-flagname" # (or "--with-flagname=value", when the second argument is provided); when multilib_is_native_abi # is false, the second argument is ignored and the output is always "--without-flagname". # An analogue of use_with, but lacking use_with's first argument -- instead of testing a # provided use-flag, it instead tests multilib_is_native_abi. multilib_native_with() { [ -z "$1" ]] && die "best_abi_with called without a parameter." # ___eapi_use_enable_and_use_with_support_empty_third_argument if [[ ! ${EAPI:-0} =~ ^(0|1|2|3)$ ]] ; then local BW_SUFFIX=${2+=$2} else local BW_SUFFIX=${2:+=$2} fi if multilib_is_native_abi ; then echo "--with-${1}${BW_SUFFIX}" else echo "--without-${1}" fi return 0 } # @FUNCTION: multilib_non_native_enable # @USAGE: [] # @DESCRIPTION: # When multilib_is_native_abi is false, returns (via standard output) "--enable-flagname" # (or "--enable-flagname=value", when the second argument is provided); when multilib_is_native_abi # is true, the second argument is ignored and the output is always "--disable-flagname". # An analogue of use_enable, but lacking use_with's first argument -- instead of testing a # provided use-flag, it instead tests the logical negation of multilib_is_native_abi. multilib_non_native_enable() { [[ -z "$1" ]] && die "non_best_abi_enable called without a parameter." # ___eapi_use_enable_and_use_with_support_empty_third_argument if [[ ! ${EAPI:-0} =~ ^(0|1|2|3)$ ]] ; then local BW_SUFFIX=${2+=$2} else local BW_SUFFIX=${2:+=$2} fi if multilib_is_native_abi ; then echo "--disable-${1}" else echo "--enable-${1}${BW_SUFFIX}" fi return 0 } # @FUNCTION: multilib_non_native_with # @USAGE: [] # @DESCRIPTION: # When multilib_is_native_abi is false, returns (via standard output) "--with-flagname" # (or "--with-flagname=value", when the second argument is provided); when multilib_is_native_abi # is true, the second argument is ignored and the output is always "--without-flagname". # An analogue of use_with, but lacking use_with's first argument -- instead of testing a # provided use-flag, it instead tests the logical negation of multilib_is_native_abi. multilib_non_native_with() { [[ -z "$1" ]] && die "best_abi_with called without a parameter." # ___eapi_use_enable_and_use_with_support_empty_third_argument if [[ ! ${EAPI:-0} =~ ^(0|1|2|3)$ ]] ; then local BW_SUFFIX=${2+=$2} else local BW_SUFFIX=${2:+=$2} fi if multilib_is_native_abi ; then echo "--without-${1}" else echo "--with-${1}${BW_SUFFIX}" fi return 0 } # @FUNCTION: abi_arch_use # @USAGE: <[!]pseudo-flag> # @RETURN: True (zero) if the pseudo-use-flag test is positive, similar to use helper. # @DESCRIPTION: # Often pre-multilib-build ebuild and eclass code contain statements like: # @CODE # use foo && append-flags -funroll-loops # @CODE # where foo is an ARCH USE_EXPAND value such as "amd64". # When adapting such code to a multi-abi build environment based on # multilib-build.eclass, it is convenient to be able to quickly convert # such queries to instead check the currently activated ABI. However, # there is a non-trivial mapping between ARCHes and ABIs. This function acts # syntactically like the "use" phase-helper; however, it only works on # ARCH USE_EXPAND values (those in ${PORTDIR}/profiles/arch.list). # # It operates only on whitelisted values of ${ABI}, so, if ${ABI} is unknown, # or if ${ARCH} is known to have multilib support, but ${ABI} is not a # known abi for ${ARCH} (according to the hard-coded whitelist) then a # nonzero (false) value (or a zero (true) value, when # the pseudo-flag argument is preceeded by an exclamation point) would # be immediately returned, regardless of any underlying "truth" pertaining # to the multilib_build framework. # # TODO: handle prefix ABI's abi_arch_use() { debug-print-function ${FUNCNAME} "$@" local u=$1 local match=0 local notnot=1 local eff_abi=__WTF__ local eff_arch=__FTW__ # if we got something like '!flag', then invert the return value if [[ ${u:0:1} == "!" ]] ; then u=${u:1} notnot=0 fi # get eff_abi if [[ ${ABI:-default} == default ]] ; then has "${DEFAULT_ABI}" "${_MULTILIB_ABI_WHITELIST[@]}" && eff_abi="${DEFAULT_ABI}" else has ${ABI} "${_MULTILIB_ABI_WHITELIST[@]}" && eff_abi=${ABI} fi # get eff_arch case ${ARCH} in x86|amd64) case ${eff_abi} in x32|amd64) eff_arch=amd64 ;; x86) eff_arch=x86 ;; esac ;; x86-fbsd|amd64-fbsd) case ${eff_abi} in x86_fbsd) eff_arch=x86-fbsd ;; amd64_fbsd) eff_arch=amd64-fbsd ;; esac ;; mips) case ${eff_abi} in n32|n64|o32) eff_arch=mips ;; esac ;; sparc) case ${eff_abi} in sparc32|sparc64) eff_arch=sparc ;; esac ;; s390) case ${eff_abi} in s390|s390x) eff_arch=s390 ;; esac ;; ppc) case ${eff_abi} in ppc|ppc64) eff_arch=ppc ;; esac ;; *) case ${eff_abi} in __WTF__) : ;; *) eff_arch="${ARCH}" esac ;; esac [[ ${eff_abi} == __WTF__ ]] && \ ewarn "abi_arch_use could not calculate effective ABI" [[ ${eff_arch} == __FTW__ ]] && \ ewarn "abi_arch_use could not calculate effective ARCH" [[ ${eff_arch} == ${u} ]] && match=1 # debug-print "abi_arch_use: match=${match} notnot=${notnot} eff_abi=${eff_abi} eff_arch=${eff_arch} ABI=${ABI} ARCH=${ARCH}" return $(( match ^ notnot )) } _MULTILIB_BUILD=1 fi