# Copyright 1999-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # $Header: $ # @ECLASS: python-multilib-r1 # @MAINTAINER: # Nobody # @AUTHOR: # Greg Turner # Based on work of: Michał Górny # Based on work of: Krzysztof Pawlik # @BLURB: A common, simple eclass for making your head explode. # @DESCRIPTION: # A common eclass providing helper functions to build and install # packages supporting being installed for multiple Python # implementations. # # Please note that python-multilib-r1 will always inherit # python-multilib-utils-r1, as well. Thus, all the functions defined # there can be used in the packages using python-multilib-r1, and there # is no need ever to inherit both. However, doing so is harmless. # # For more information, please see the python-r1 Developer's Guide: # http://www.gentoo.org/proj/en/Python/python-r1/dev-guide.xml case "${EAPI:-0}" in 0|1|2|3) die "Unsupported EAPI=${EAPI:-0} (too old) for ${ECLASS}" ;; 4|5) # EAPI=4 is required for USE default deps on USE_EXPAND flags ;; *) die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}" ;; esac if [[ ! ${_PYTHON_MULTILIB_R1} ]]; then if [[ ${_PYTHON_ANY_R1} ]]; then die 'python-r1.eclass can not be used with python-any-r1.eclass.' fi [[ ${PYTHON_MULTILIB_UTILS_R1} ]] || \ inherit python-multilib-utils-r1 # @ECLASS-VARIABLE: DISTUTILS_JOBS # @DEFAULT_UNSET # @DESCRIPTION: # The number of parallel jobs to run for distutils-r1 parallel builds. # If unset, the job-count in ${MAKEOPTS} will be used. # # This variable is intended to be set in make.conf. # @ECLASS-VARIABLE: PYTHON_COMPAT # @DESCRIPTION: # This variable contains a list of Python implementations the package # supports. It must be set before the `inherit' call. It has to be # an array. # # Example: # @CODE # PYTHON_COMPAT=( python{2_5,2_6,2_7} ) # @CODE # @ECLASS-VARIABLE: PYTHON_COMPAT_MULTILIB # @DEFAULT-UNSET # @DESCRIPTION: # This variable is generated from PYTHON_COMPAT and multilib-build # metadata. It is simply the Cartesian product of ${PYTHON_COMPAT} and # _CACHED_MULTILIB_FLAGS from python-multilib-utils-r1.eclass, expressed # as an array of _ tuples. The tuples are # grouped by python-abi, with the best python-abi entries coming last, # and wihtin these groups, sorted such that the multilib flags corresponding # to the best multilib abi are last (except during the depend phase, # when no ordering guarantees are available). # # Aside from the ordering, (which is itself fully invariant during the # depend ebuild phase), this variable is invariant with respect # to profile settings and therefore should be suitable for generating # package-manager-cachable metadata. _autogen_python_compat_multilib_from_python_compat() { debug-print-function ${FUNCNAME} "$@" local impl flag # exploit PYTHON_NOMULTILIB_ALL_IMPLS best-last ordering & freedom from legacy impls for impl in "${_PYTHON_NOMULTILIB_ALL_IMPLS[@]}"; do # but skip any impls not in PYTHON_COMPAT [[ " ${PYTHON_COMPAT[*]} " == *" ${impl} "* ]] || continue # exploit (phase-predicated) CACHED_MULTILIB_FLAGS best-last ordering for flag in "${_CACHED_MULTILIB_FLAGS[@]}" ; do PYTHON_COMPAT_MULTILIB+=("${impl}_${flag}") done done debug-print "${FUNCNAME}: from PYTHON_COMPAT: ( $(mg-qm "${PYTHON_COMPAT[@]}") )" debug-print "${FUNCNAME}: computed PYTHON_COMPAT_MULTILIB: ( $(mg-qm "${PYTHON_COMPAT_MULTILIB[@]}") )" } _gen_python_multilib_deps() { local impls=() PYTHON_MULTILIB_DEPS= local i PYTHON_MULTILIB_PKG_DEP for i in "${PYTHON_COMPAT[@]}"; do _python_nomultilib_impl_supported "${i}" || continue python_export "${i}" PYTHON_MULTILIB_PKG_DEP PYTHON_MULTILIB_DEPS+="python_targets_${i}? ( ${PYTHON_MULTILIB_PKG_DEP} ) " impls+=( "${i}" ) done if [[ ${#impls[@]} -eq 0 ]]; then die "No supported implementation in PYTHON_COMPAT." fi local flags=( "${impls[@]/#/python_targets_}" ) debug-print "${FUNCNAME}: NML: flags=(${flags[*]})" local optflags=${flags[@]/%/(-)?} # A nice QA trick here. Since a python-single-r1 package has to have # at least one PYTHON_SINGLE_TARGET enabled (REQUIRED_USE), # the following check will always fail on those packages. Therefore, # it should prevent developers from mistakenly depending on packages # not supporting multiple Python implementations. local flags_st=( "${impls[@]/#/-python_single_target_}" ) debug-print "${FUNCNAME}: NML: flags_st=(${flags_st[*]})" optflags+=,${flags_st[@]/%/(-)} debug-print "${FUNCNAME}: NML: optflags=(${optflags[*]})" IUSE=${flags[*]} PYTHON_MULTILIB_REQUIRED_USE="|| ( ${flags[*]} )" PYTHON_MULTILIB_USEDEP=${optflags// /,} debug-print "${FUNCNAME}: IUSE (NML): \"${IUSE}\"" debug-print "${FUNCNAME}: PYTHON_MULTILIB_REQUIRED_USE (NML): \"${PYTHON_MULTILIB_REQUIRED_USE}\"" debug-print "${FUNCNAME}: PYTHON_MULTILIB_USEDEP (NML): \"${PYTHON_MULTILIB_USEDEP}\"" # 1) well, python-exec would suffice as an RDEP # but no point in making this overcomplex, BDEP doesn't hurt anyone # 2) python-exec should be built with all targets forced anyway # but if new targets were added, we may need to force a rebuild PYTHON_MULTILIB_DEPS+="dev-lang/python-exec:=[${PYTHON_MULTILIB_USEDEP}]" # multilib-specifc: impls=() for i in "${PYTHON_COMPAT_MULTILIB[@]}"; do _python_multilib_impl_supported "${i}" || continue si=$(_python_strip_multilib_impl_abi "${i}") uf="abi${i#${si}}" i2=$(epythonize "${i}") # this will always work during the depend phase but some irrelevant stuff will # go missing during the others, due to ABIs disabled in portage. # FIXME: probably a pms violation if [[ ${i2} ]] ; then # The chosen targets need to be in PYTHON_TARGETS and # PYTHON_MULTILIB_TARGETS. PYTHON_MULTILIB_REQUIRED_USE+=" python_multilib_targets_${i}? ( python_targets_${si} " # the multilib abi should match the python multilib abis PYTHON_MULTILIB_REQUIRED_USE+="${uf} )" python_export "${i2}" PYTHON_MULTILIB_PKG_DEP PYTHON_MULTILIB_DEPS+=" python_multilib_targets_${i}? ( ${PYTHON_MULTILIB_PKG_DEP} ) " impls+=( "${i}" ) fi done if [[ ${#impls[@]} -eq 0 ]]; then die "No supported implementation in PYTHON_COMPAT_MULTILIB." fi debug-print "${FUNCNAME}: impls=(${impls[*]})" flags=( "${impls[@]/#/python_multilib_targets_}" ) debug-print "${FUNCNAME}: ML: flags=(${flags[*]})" optflags=( "${impls[@]/#/python_multilib_mtargets_}" ) debug-print "${FUNCNAME}: ML: optflags=(${optflags[*]})" # QA "trick" multilib edition: flags_st=( "${impls[@]/#/-python_multilib_single_targets_}" ) optflags+=,${flags_st[@]/%/(-)} IUSE+=" ${flags[*]}" debug-print "${FUNCNAME}: final value: IUSE=\"${IUSE}\"" # nb: no required use augmentation required since # it is sufficient to have only nomultilib impls selected. PYTHON_MULTILIB_USEDEP+=",${optflags// /,}" } _python_multilib_set_globals() { debug-print-function ${FUNCNAME} "$@" PYTHON_COMPAT_MULTILIB=() _autogen_python_compat_multilib_from_python_compat _gen_python_multilib_deps } _python_multilib_set_globals # @ECLASS-VARIABLE:_PYTHON_ACTIVE_MULTILIB_IMPL_CACHE # @INTERNAL # @DEFAULT_UNSET # @DESCRIPTION: # Once generated, contains a list of all the currently active multilib # python impls as an array of PYTHON_COMPAT_MULTILIB impl specifiers. # This list may be empty, for example if there are no corresponding # multilib impls's for the active DEFAULT_ABI in portage. # # Except during the depend ebuild phase, this list will always be ordered # first by the python abi's and then by the multilib abi's, with the best # python abi's coming last and the best multilib abis (for a given python # abi) coming last, such that the very last item, if any, is the most # preferred multilib python impl available (however, it is possible that # a no-multilib python impl might be active which is preferred over all # of the multilib python impl's). # @FUNCTION: _python_multilib_impl_activate # @INTERNAL # @DESCRIPTION: # Appends a multilib impl to the _PYTHON_ACTIVE_MULTILIB_IMPL_CACHE, # creating the variable if it does not exist. _python_multilib_impl_activate() { debug-print-function ${FUNCNAME} "$@" if ! declare -p _PYTHON_ACTIVE_MULTILIB_IMPL_CACHE &> /dev/null ; then _PYHON_ACTIVE_MULTILIB_IMPL_CACHE=() fi _PYTHON_ACTIVE_MULTILIB_IMPL_CACHE+=("${1}") } # @FUNCTION: _python_multilib_cache_active_impls # @INTERNAL # @DESCRIPTION: # Enforce the proper setting of PYTHON_MULTILIB_TARGETS_*, and construct # the _PYTHON_ACTIVE_{NO,}MULTILIB_IMPL_CACHES if necesary. _python_multilib_cache_active_impls() { debug-print-function ${FUNCNAME} "${@}" local nomultilib_impl="${1}" i for i in "${PYTHON_COMPAT_MULTILIB[@]}"; do [[ $(_python_strip_multilib_impl_abi "${i}") == ${nomultilib_impl} ]] && use_if_iuse "python_multilib_targets_${i}" && \ _python_multilib_impl_activate "${i}" done debug-print "${FUNCNAME}: generated: _PYTHON_ACTIVE_MULTILIB_IMPL_CACHE=(${_PYTHON_ACTIVE_MULTILIB_IMPL_CACHE[*]})" } # @ECLASS-VARIABLE:_PYTHON_ACTIVE_NOMULTILIB_IMPL_CACHE # @INTERNAL # @DEFAULT_UNSET # @DESCRIPTION: # Once generated, contains a list of all the currently active nomultilib # python impls as an array of PYTHON_COMPAT impl specifiers. Some of these # may be redundant equivalents to the best-multilib-abi entries in the # _PYTHON_ACTIVE_MULTILIB_IMPL_CACHE. When multilib impl's exist for a # nomultilib impl, the nomultilib imple cache entry may be thought of as # a hint to use the multilib impl's instead. # # This list will always have the best enabled python ABI as the last item. # @FUNCTION: _python_nomultilib_impl_activate # @INTERNAL # @DESCRIPTION: # Appends a nomultilib impl to the _PYTHON_ACTIVE_NOMULTILIB_IMPL_CACHE, # creating the variable if it does not exist. Then calls # _python_multilib_cache_active_impls in order to cache any corresponding # multilib impls. _python_nomultilib_impl_activate() { debug-print-function ${fUNCNAME} "$@" declare -p _PYTHON_ACTIVE_NOMULTILIB_IMPL_CACHE &> /dev/null || \ _PYHON_ACTIVE_NOMULTILIB_IMPL_CACHE=() _PYTHON_ACTIVE_NOMULTILIB_IMPL_CACHE+=("${1}") _python_multilib_cache_active_impls "${1}" } # @FUNCTION: _python_cache_active_impls # @INTERNAL # @DESCRIPTION: # Enforce and remember the proper setting of PYTHON_TARGETS. _python_cache_active_impls() { debug-print-function ${FUNCNAME} "${@}" if declare -p _PYTHON_ACTIVE_NOMULTILIB_IMPL_CACHE &> /dev/null ; then debug-print "${FUNCNAME}: already generated" return 0 fi declare -p PYTHON_COMPAT &> /dev/null || \ die "Somebody forgot to define PYTHON_COMPAT before inheriting a python-multilib-r1 framework eclass." local i found= # exploit PYTHON_NOMULTILIB_ALL_IMPLS's best-last ordering & guaranteed content validity for i in "${_PYTHON_NOMULTILIB_ALL_IMPLS[@]}"; do # ... but skip any impls not in PYTHON_COMPAT [[ " ${PYTHON_COMPAT[*]} " == *" ${i} "* ]] || continue # if the corresponding use-flag is on, we are building it. if use_if_iuse "python_targets_${i}" ; then # ... so cache the impl and any corresponding multilib impls now. _python_nomultilib_impl_activate "${i}" found=1 fi done if [[ ${found} ]] ; then debug-print "${FUNCNAME}: generated _PYTHON_ACTIVE_NOMULTILIB_IMPL_CACHE: ($( mg-qm "${_PYTHON_ACTIVE_NOMULTILIB_IMPL_CACHE[@]}"))" debug-print "${FUNCNAME}: generated _PYTHON_ACTIVE_MULTILIB_IMPL_CACHE: ($( mg-qm "${_PYTHON_ACTIVE_MULTILIB_IMPL_CACHE[@]}"))" return 0 fi eerror "No Python implementation selected for the build. Please add one" eerror "of the following values to your PYTHON_TARGETS (in make.conf):" eerror eerror "${PYTHON_COMPAT[@]}" echo die "No supported Python implementation in PYTHON_TARGETS." } # @FUNCTION: python_gen_useflags # @USAGE: [...] # @DESCRIPTION: # Output a list of USE flags for Python implementations which # are both in PYTHON_COMPAT and match any of the patterns passed # as parameters to the function. # # Example: # @CODE # PYTHON_COMPAT=( python{2_7,3_2} ) # REQUIRED_USE="doc? ( || ( $(python_gen_useflags 'python2*') ) )" # @CODE # # Would be equivalent to: # @CODE # REQUIRED_USE="doc? ( || ( python_targets_python2_7 # python_targets_python2_7_x86_32 # python_targets_python2_7_x86_64 # python_targets_python2_7_x86_x32 # python_targets_python2_7_mips_n32 # python_targets_python2_7_mips_n64 # python_targets_python2_7_mips_o32 ) )" # @CODE python_gen_useflags() { debug-print-function ${FUNCNAME} "${@}" local impl pattern local matches=() for impl in "${PYTHON_COMPAT[@]}"; do _python_nomultilib_impl_supported "${impl}" || continue for pattern; do if [[ ${impl} == ${pattern} ]]; then matches+=( "python_targets_${impl}" ) break fi done done for impl in "${PYTHON_COMPAT_MULTILIB[@]}"; do _python_multilib_impl_support "${impl}" || continue for pattern; do if [[ ${impl} == ${pattern} ]]; then matches+=( "python_multilib_targets_${impl}" ) break fi done done echo "${matches[*]}" } # @FUNCTION: python_gen_cond_dep # @USAGE: [...] # @DESCRIPTION: # Output a list of -ies made conditional to USE flags # of Python implementations which are both in PYTHON_COMPAT and match # any of the patterns passed as the remaining parameters. # # Please note that USE constraints on the package itself need to be enforced # separately. Therefore, the dependency usually needs to use # some front-end usedep generator as well as this one. # # Example: # @CODE # PYTHON_COMPAT=( python{2_5,2_6,2_7} ) # RDEPEND="$(python_gen_cond_dep dev-python/unittest2 python2_5 python2_7_x86-x32)" # @CODE # # It will cause the variable to look like: # @CODE # RDEPEND="python_targets_python2_5? ( dev-python/unittest2 ) # python_targets_python2_7? ( dev-python/unittest2[abi_x86_x32(-)?] )" # @CODE python_gen_cond_dep() { debug-print-function ${FUNCNAME} "${@}" local impl pattern local matches=() local dep=${1} shift for impl in "${PYTHON_COMPAT[@]}"; do _python_nomultilib_impl_supported "${impl}" || continue for pattern; do if [[ ${impl} == ${pattern} ]]; then matches+=( "python_targets_${impl}? ( ${dep} )" ) break fi done done for impl in "${PYTHON_COMPAT_MULTILIB[@]}"; do _python_multilib_impl_supported "${impl}" || continue for pattern; do if [[ ${impl} == ${pattern} ]]; then matches+=( "python_multilib_targets_${impl}? ( ${dep}[abi_${impl}(-)?] )" ) break fi done done echo ${matches[@]} } # @ECLASS-VARIABLE: BUILD_DIR # @DESCRIPTION: # The current build directory. In global scope, it is supposed to # contain an initial build directory; if unset, it defaults to ${S}. # # In functions run by python_foreach_impl(), the BUILD_DIR is locally # set to an implementation-specific build directory. That path is # created through appending a hyphen and the implementation name # to the final component of the initial BUILD_DIR. # # Example value: # @CODE # ${WORKDIR}/foo-1.3-python2_6 # @CODE # @FUNCTION: python_copy_sources # @DESCRIPTION: # Create a single copy of the package sources for each enabled Python # implementation. # # The sources are always copied from initial BUILD_DIR (or S if unset) # to implementation-specific build directory matching BUILD_DIR used by # python_foreach_abi(). python_copy_sources() { debug-print-function ${FUNCNAME} "${@}" local MULTIBUILD_VARIANTS _python_obtain_impls multibuild_copy_sources } # @FUNCTION: _python_check_USE_PYTHON # @INTERNAL # @DESCRIPTION: # Check whether USE_PYTHON and PYTHON_TARGETS are in sync. Output # warnings if they are not. _python_check_USE_PYTHON() { debug-print-function ${FUNCNAME} "${@}" if [[ ! ${_PYTHON_USE_PYTHON_CHECKED} ]]; then _PYTHON_USE_PYTHON_CHECKED=1 # python-exec has profile-forced flags. if [[ ${CATEGORY}/${PN} == dev-lang/python-exec ]]; then return fi _try_eselect() { # The eselect solution will work only with one py2 & py3. local impl py2 py3 dis_py2 dis_py3 for impl in "${PYTHON_COMPAT[@]}"; do _python_nomultilib_impl_supported "${impl}" || continue if use "python_targets_${impl}"; then case "${impl}" in python2_*) if [[ ${py2+1} ]]; then debug-print "${FUNCNAME}: -> more than one py2: ${py2} ${impl}" return 1 fi py2=${impl/_/.} ;; python3_*) if [[ ${py3+1} ]]; then debug-print "${FUNCNAME}: -> more than one py3: ${py3} ${impl}" return 1 fi py3=${impl/_/.} ;; *) return 1 ;; esac else case "${impl}" in python2_*) dis_py2=1 ;; python3_*) dis_py3=1 ;; esac fi done # The eselect solution won't work if the disabled Python version # is installed. if [[ ! ${py2+1} && ${dis_py2} ]]; then debug-print "${FUNCNAME}: -> all py2 versions disabled" if ! has python2_7 "${PYTHON_COMPAT[@]}"; then debug-print "${FUNCNAME}: ---> package does not support 2.7" return 0 fi if has_version '=dev-lang/python-2*'; then debug-print "${FUNCNAME}: ---> but =python-2* installed!" return 1 fi fi if [[ ! ${py3+1} && ${dis_py3} ]]; then debug-print "${FUNCNAME}: -> all py3 versions disabled" if ! has python3_2 "${PYTHON_COMPAT[@]}"; then debug-print "${FUNCNAME}: ---> package does not support 3.2" return 0 fi if has_version '=dev-lang/python-3*'; then debug-print "${FUNCNAME}: ---> but =python-3* installed!" return 1 fi fi local warned # Now check whether the correct implementations are active. if [[ ${py2+1} ]]; then local sel_py2=$(eselect python show --python2) debug-print "${FUNCNAME}: -> py2 built: ${py2}, active: ${sel_py2}" if [[ ${py2} != ${sel_py2} ]]; then ewarn "Building package for ${py2} only while ${sel_py2} is active." ewarn "Please consider switching the active Python 2 interpreter:" ewarn ewarn " eselect python set --python2 ${py2}" warned=1 fi fi if [[ ${py3+1} ]]; then local sel_py3=$(eselect python show --python3) debug-print "${FUNCNAME}: -> py3 built: ${py3}, active: ${sel_py3}" if [[ ${py3} != ${sel_py3} ]]; then [[ ${warned} ]] && ewarn ewarn "Building package for ${py3} only while ${sel_py3} is active." ewarn "Please consider switching the active Python 3 interpreter:" ewarn ewarn " eselect python set --python3 ${py3}" warned=1 fi fi if [[ ${warned} ]]; then ewarn ewarn "Please note that after switching the active Python interpreter," ewarn "you may need to run 'python-updater' to rebuild affected packages." ewarn ewarn "For more information on PYTHON_TARGETS and python.eclass" ewarn "compatibility, please see the relevant Wiki article [1]." ewarn ewarn "[1] https://wiki.gentoo.org/wiki/Project:Python/PYTHON_TARGETS" fi } # If user has no USE_PYTHON, try to avoid it. if [[ ! ${USE_PYTHON} ]]; then debug-print "${FUNCNAME}: trying eselect solution ..." _try_eselect && return fi debug-print "${FUNCNAME}: trying USE_PYTHON solution ..." debug-print "${FUNCNAME}: -> USE_PYTHON=${USE_PYTHON}" local impl old=${USE_PYTHON} new=() removed=() for impl in "${PYTHON_COMPAT[@]}"; do _python_nomultilib_impl_supported "${impl}" || continue local abi case "${impl}" in python*) abi=${impl#python} ;; jython*) abi=${impl#jython}-jython ;; pypy*) abi=2.7-pypy-${impl#pypy} ;; *) die "Unexpected Python implementation: ${impl}" ;; esac abi=${abi/_/.} has "${abi}" ${USE_PYTHON} local has_abi=${?} use "python_targets_${impl}" local has_impl=${?} # 0 = has, 1 = does not have if [[ ${has_abi} == 0 && ${has_impl} == 1 ]]; then debug-print "${FUNCNAME}: ---> remove ${abi}" # remove from USE_PYTHON old=${old/${abi}/} removed+=( ${abi} ) elif [[ ${has_abi} == 1 && ${has_impl} == 0 ]]; then debug-print "${FUNCNAME}: ---> add ${abi}" # add to USE_PYTHON new+=( ${abi} ) fi done if [[ ${removed[@]} || ${new[@]} ]]; then old=( ${old} ) debug-print "${FUNCNAME}: -> old: ${old[@]}" debug-print "${FUNCNAME}: -> new: ${new[@]}" debug-print "${FUNCNAME}: -> removed: ${removed[@]}" if [[ ${USE_PYTHON} ]]; then ewarn "It seems that your USE_PYTHON setting lists different Python" ewarn "implementations than your PYTHON_TARGETS variable. Please consider" ewarn "using the following value instead:" ewarn ewarn " USE_PYTHON='\033[35m${old[@]}${new[@]+ \033[1m${new[@]}}\033[0m'" if [[ ${removed[@]} ]]; then ewarn ewarn "(removed \033[31m${removed[@]}\033[0m)" fi else ewarn "It seems that you need to set USE_PYTHON to make sure that legacy" ewarn "packages will be built with respect to PYTHON_TARGETS correctly:" ewarn ewarn " USE_PYTHON='\033[35;1m${new[@]}\033[0m'" fi ewarn ewarn "Please note that after changing the USE_PYTHON variable, you may need" ewarn "to run 'python-updater' to rebuild affected packages." ewarn ewarn "For more information on PYTHON_TARGETS and python.eclass" ewarn "compatibility, please see the relevant Wiki article [1]." ewarn ewarn "[1] https://wiki.gentoo.org/wiki/Project:Python/PYTHON_TARGETS" fi fi } # @FUNCTION: _python_obtain_impls # @INTERNAL # @DESCRIPTION: # Set up the enabled implementation list. _python_obtain_impls() { debug-print-function ${FUNCNAME} "${@}" if [[ ${PYTHON_COMPAT_OVERRIDE} ]]; then if [[ ! ${_PYTHON_COMPAT_OVERRIDE_WARNED} ]]; then ewarn "WARNING: PYTHON_COMPAT_OVERRIDE in effect. The following Python" ewarn "implementations will be enabled:" ewarn ewarn " ${PYTHON_COMPAT_OVERRIDE}" ewarn ewarn "Dependencies won't be satisfied, and PYTHON_TARGETS will be ignored." _PYTHON_COMPAT_OVERRIDE_WARNED=1 fi MULTIBUILD_VARIANTS=( ${PYTHON_COMPAT_OVERRIDE} ) return fi _python_cache_active_impls _python_check_USE_PYTHON MULTIBUILD_VARIANTS=() local impl ml_impl best_ml_abi=$(multilib_get_native_abi) for impl in "${_PYTHON_ACTIVE_NOMULTILIB_IMPL_CACHE}" ; do for ml_impl in "${_PYTHON_ACTIVE_MULTILIB_IMPL_CACHE}" ; do if [[ $(_python_strip_multilib_impl_abi ${ml_impl}) == ${impl} ]] ; then if [[ $(_python_impl_abi ${ml_impl}) == ${best_ml_abi} ]] ; then MULTIBUILD_VARIANTS+=("${impl}") else MULTIBUILD_VARIANTS+=("${ml_impl}") fi continue 2 fi done # no multilib version so the no-multilib version is to be treated as a variant. MULTIBUILD_VARAINTS+=("${impl}") done debug-print "${FUNCNAME}: result: MULTIBUILD_VARAINTS=($(mg-qm "${MULTIBUILD_VARIANTS[@]}"))" } # @FUNCTION: _python_multibuild_wrapper # @USAGE: [...] # @INTERNAL # @DESCRIPTION: # Calls python_multilib_automagic_wrapper for the # selected MULTIBUILD_VARIANT. _python_multibuild_wrapper() { debug-print-function ${FUNCNAME} "$(mg-qm "${@}")" python_multilib_automagic_wrapper "${MULTIBUILD_VARIANT}" "${@}" } # @FUNCTION: python_foreach_impl # @USAGE: [...] # @DESCRIPTION: # Run the given command for each of the enabled Python implementations. # If additional parameters are passed, they will be passed through # to the command. # # The function will return 0 status if all invocations succeed. # Otherwise, the return code from first failing invocation will # be returned. # # For each command being run, EPYTHON, PYTHON, BUILD_DIR, and a fuck-ton # of other variables and settings are exported to the command environment. # See python_multilib_automagic_wrapper in python-multilib-utils-r1 for # the gory details. python_foreach_impl() { debug-print-function ${FUNCNAME} "$(mg-qm "${@}")" local MULTIBUILD_VARIANTS _python_obtain_impls multibuild_foreach_variant _python_multibuild_wrapper "${@}" } # @FUNCTION: python_parallel_foreach_impl # @USAGE: [...] # @DESCRIPTION: # Run the given command for each of the enabled Python implementations. # If additional parameters are passed, they will be passed through # to the command. # # The function will return 0 status if all invocations succeed. # Otherwise, the return code from first failing invocation will # be returned. # # For each command being run, EPYTHON, PYTHON, BUILD_DIR, and a fuck-ton # of other variables and settings are exported to the command environment. # See python_multilib_automagic_wrapper in python-multilib-utils-r1 for # the gory details. # # Multiple invocations of the command will be run in parallel, up to # DISTUTILS_JOBS (defaulting to '-j' option argument from MAKEOPTS). python_parallel_foreach_impl() { debug-print-function ${FUNCNAME} "$(mg-qm "${@}")" local MULTIBUILD_JOBS=${MULTIBUILD_JOBS:-${DISTUTILS_JOBS}} local MULTIBUILD_VARIANTS _python_obtain_impls multibuild_parallel_foreach_variant _python_multibuild_wrapper "${@}" } # @FUNCTION: python_setup # @DESCRIPTION: # Find the best (most preferred) Python implementation enabled # and set the Python build environment up for it. # # This function needs to be used when Python is being called outside # of python_foreach_impl calls (e.g. for shared processes like doc # building). python_foreach_impl sets up the build environment itself. python_setup() { debug-print-function ${FUNCNAME} "${@}" python_export_best python_wrapper_setup } # @FUNCTION: python_export_best # @USAGE: [...] # @DESCRIPTION: # Find the best (most preferred) Python implementation enabled # and export given variables for it. If no variables are provided, # EPYTHON & PYTHON will be exported. python_export_best() { debug-print-function ${FUNCNAME} "${@}" [[ ${#} -gt 0 ]] || set -- EPYTHON PYTHON local best MULTIBUILD_VARIANTS _python_obtain_impls _python_set_best() { best=${MULTIBUILD_VARIANT} } multibuild_for_best_variant _python_set_best debug-print "${FUNCNAME}: Best implementation is: ${best}" python_export "${best}" "${@}" python_wrapper_setup } # @FUNCTION: python_replicate_script # @USAGE: ... # @DESCRIPTION: # Copy the given script to variants for all enabled Python # implementations, then replace it with a symlink to the wrapper. # # All specified files must start with a 'python' shebang. A file not # having a matching shebang will be refused. python_replicate_script() { debug-print-function ${FUNCNAME} "${@}" _python_replicate_script() { if _python_want_python_exec2; then local PYTHON_SCRIPTDIR python_export PYTHON_SCRIPTDIR ( exeinto "${PYTHON_SCRIPTDIR#${EPREFIX}}" doexe "${files[@]}" ) python_rewrite_shebang_multilib "${EPYTHON}" \ "${files[@]/*\//${D%/}/${PYTHON_SCRIPTDIR}/}" else local f for f in "${files[@]}"; do cp -p "${f}" "${f}-${EPYTHON}" || die done python_rewrite_shebang_multilib "${EPYTHON}" \ "${files[@]/%/-${EPYTHON}}" fi } local files=( "${@}" ) python_foreach_impl _python_replicate_script # install the wrappers local f for f; do _python_ln_rel "${ED%/}$(_python_get_wrapper_path)" "${f}" || die done } _PYTHON_MULTILIB_R1=1 fi