# Copyright 1999-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # $Header: $ # @ECLASS: python-multilib-single-r1 # @MAINTAINER: # Python team # @AUTHOR: # Greg Turner # Based on work of: Michał Górny # Based on work of: Krzysztof Pawlik # @BLURB: An eclass for Python packages not installed for multiple implementations. # @DESCRIPTION: # Multilib reimplementation of python-single-r1. # # This eclass extends the IUSE and REQUIRED_USE set by python-r1 # to request correct PYTHON_SINGLE_TARGET. It also provides # PYTHON_MULTILIB_USEDEP and PYTHON_MULTILIB_DEPS in a suitable form. # # Please note that packages support multiple Python implementations # (using python-r1 eclass or python-multilib-r1 eclass) can not depend # on packages not supporting them (using this eclass). # # Please note that python-multilib-single-r1 will always # inherit python-multilib-utils-r1 as well. Thus, all the functions defined # there can be used in the packages using python-single-r1, and there is no # need ever to inherit both. # # 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 # @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_REQ_USE_MULTILIB # @DEFAULT_UNSET # @DESCRIPTION: # The list of USEflags required to be enabled on the chosen Python # implementations, formed as a USE-dependency string. It should be valid # for all implementations in PYTHON_COMPAT_MULTILIB, so it may be necessary to # use USE defaults. # # This should be set before calling `inherit'. # # Example: # @CODE # PYTHON_REQ_USE_MULTILIB="gdbm,ncurses(-)?" # @CODE # # It will cause the Python dependencies to look like: # @CODE # python_single_target_pythonX_Y? ( dev-lang/python:X.Y[gdbm,ncurses(-)?,${PYTHON_MULTILIB_USEDEP}] ) # @CODE # @ECLASS-VARIABLE: PYTHON_MULTILIB_DEPS # @DESCRIPTION: # This is an framework-generated Python dependency string for all # implementations listed in PYTHON_COMPAT_MULTILIB. # # The dependency string is conditional on PYTHON_SINGLE_TARGET # and MULTILIB_USEDEP. # # Example use: # @CODE # RDEPEND="${PYTHON_MULTILIB_DEPS} # dev-foo/mydep" # DEPEND="${RDEPEND}" # @CODE # # Example value: # @CODE # FIXME # @CODE # @ECLASS-VARIABLE: PYTHON_MULTILIB_SINGLE_MODE # @DEFAULT_UNSET # @DESCRIPTION: # It is rather awkward for a descendant of python-single-r1 to support # multiple python ABIs as this will not make for trivial porting. # Rather than attempt a one-size-fits all solution, the python-multilib-r1 # version offers the following modes. Each of them may be activated by # placing its name into the PYTHON_MULTILIB_SINGLE_MODE variable before # inheriting pythong-multilib-single-r1. For example: # # @CODE@ # PYTHON_MULTILIB_SINGLE_MODE=flexible # inherit python-multilib-single-r1 # @CODE@ # # The supported modes and their descriptions follow: # # default: This mode is selected if the PYTHON_MULTILIB_SINGLE_MODE # variable is not set. In this mode, python-multilib-single-r1 acts # as similarly as possible to the python-single-r1 eclass in that, # really and truly, only a single no-multilib target may be selected, # and, if any corresponding multilib targets are enabled corresponding # to that target, one and only one of them must be selected as well. # The effective result of this arrangement is that literally a single # multilib or no-multilib python target will be active. In this mode, # the pkg_depend phase function is exported and the python environment # is established automatically there. This should minimize the pain # of porting existing python-multilib-single-r1 ebuilds, but it # will maximize the pain for multilib users who will be often pointlessly # prevented from enabling multiple multilib ABIs in a long chain of # interdependent ebuilds. In this mode, the requirement that multilib # abis match python-multilib abis is not enforced. # # flexible: although it will require a greater porting effort, this is # the most user-friendly mode. The requirement that multilib abis # match python ABIs is not enforced; in this mode, for example, it is # possible for the python_multilib_single_python2_7_x86_x32 use flag to # be enabled even when the abi_x86_x32 use flag is not enabled for the # same ebuid. This does not excuse the ebuild author or the user from # ensuring that correct dependencies are enforced; it simply divorces the # multilib ABI of the package from the multilib ABI of python. This # can be hard to do correctly so it's not recommended unless you're # sure you're able to get everything right. It only makes sense in cases # where the python interpreter is invoked by the package as an executable # and not linked to as a library, or when the python build flag may # be turned off on a per-multilib-ABI basis at configure time. # To use this mode, you will probably want to invoke python_foreach_impl # or python_parallel_foreach_impl, or to consume an eclass which invokes # those for you, in order to get all of the python ABIs correctly # be iterated through, activated, and worked with correctly. # # simple: This is the recommended setting for most ebuilds, even though # it is not the default since it is easier to port to the default mode # as a starting point. In this mode, a complete agreement between the # multilib-build multilib ABIs and the enabled multilib python ABIs is # enforced. In other words, if abi_x86_32 is enabled, and "python2_7" # is in PYTHON_TARGETS, then PYTHON_MULTILIB_SINGLE_TARGETS_PYTHON2_7_X86 # must contain "32", and, if PYTHON_MULTILIB_SINGLE_TARGETS_PYTHON2_7_X86 # contains "32", then ABI_X86 must contain 32 as well, and # PYTHON_TARGETS must contain "python2_7". # @ECLASS-VARIABLE: PYTHON_MULTILIB_USEDEP # @DESCRIPTION: # This is an eclass-generated USE-dependency string which can be used to # depend on another multilib Python package being built for the same Python # implementations. # # The generate USE-flag dependency specifier specification suitable for # use in dependency atoms for python dependencies. # # python-multilib-single-r1 (and maybe later, python-multilib-distutils-ng) # eclasses. It must not be used on packages using python.eclass. # # Example: # # @CODE # RDEPEND="dev-python/foo[${PYTHON_MULTILIB_USEDEP}]" # @CODE # # Example value: # @CODE # FIXME # @CODE # @ECLASS-VARIABLE: PYTHON_MULTILIB_REQUIRED_USE # @DESCRIPTION: # This is an eclass-generated required-use expression which ensures the following: # 1. Exactly one PYTHON_SINGLE_TARGET value has been enabled. # 2. The selected PYTHON_SINGLE_TARGET value is enabled in PYTHON_TARGETS. # 3. No PYTHON_MULTILIB_SINGLE_TARGETS target may be enabled which # does not corespond to the selected PYTHON_SINGLE_TARGET # 4. Each enabled PYTHON_MULTILIB_SINGLE_TARGETS value is enabled in # PYTHON_MULTILIB_TARGETS # 5. Each enabled multilib ABI target requires the corresponding # PYTHON_MULTILIB_SINGLE_TARGETS target to be enabled # if its corresponding PYTHON_SINGLE_TARGET is enabled. # 6. At least one PYTHON_MULTILIB_SINGLE_TARGET is enabed. # 7. Each enabled PYTHON_MULTILIB_SINGLE_TARGET requires # the corresponding multilib ABI target to be enabled. # # This expression should be utilized in an ebuild by including it in # REQUIRED_USE, optionally behind a use flag. # # Example use: # @CODE # REQUIRED_USE="python? ( ${PYTHON_MULTILIB_REQUIRED_USE} )" # @CODE # # Example value: # @CODE # # @CODE if [[ ! ${_PYTHON_MULTILIB_SINGLE_R1} ]] ; then if [[ ${_PYTHON_ANY_R1} ]]; then die 'python-multilib-single-r1.eclass can not be used with python-any-r1.eclass.' elif [[ ${_PYTHON_UTILS_R1} ]]; then die 'python-multilib-single-r1.eclass cannot be used with python-*-r1 no-multilib eclasses.' fi declare -p PYTHON_COMPAT &>/dev/null || \ die 'PYTHON_COMPAT not declared.' [[ ${_PYTHON_MULTILIB_R1} ]] || \ inherit python-multilib-r1 _python_single_multilib_set_globals() { debug-print-function ${FUNCNAME} "$@" local impls=() local i si abi uf PYTHON_MULTILIB_PKG_DEP i2 i3 : ${PYTHON_MULTILIB_SINGLE_MODE:=default} PYTHON_MULTILIB_DEPS= debug-print "${FUNCNAME}: ----------- nomultilib ----------" for i in "${PYTHON_COMPAT[@]}"; do _python_nomultilib_impl_supported "${i}" || continue # The chosen targets need to be in PYTHON_TARGETS as well. # This is in order to enforce correct dependencies on packages # supporting multiple implementations. PYTHON_MULTILIB_REQUIRED_USE+=" python_single_target_${i}? ( python_targets_${i}" # They are also incompatible with any multilib targets not corresponding # to this no-multilib target. Meanwhile, build composite deps requirements # specifying that simultaneously enabled multilib abis and no-multilib single # targets require the corresponding multilib single target to be enabled. for i2 in "${_CACHED_MULTILIB_FLAGS[@]}" ; do [[ ${PYTHON_MULTILIB_SINGLE_MODE} != flexible ]] && \ PYTHON_MULTILIB_REQUIRED_USE+=" abi_${i2}? ( python_multilib_single_targets_${i}_${i2} )" for i3 in "${PYTHON_COMPAT[@]}" ; do [[ ${i3} == ${i} ]] && continue PYTHON_MULTILIB_REQUIRED_USE+=" !python_multilib_single_targets_${i3}_${i2}" done done PYTHON_MULTILIB_REQUIRED_USE+=" ) " debug-print "${FUNCNAME}: (after no-multi) PYTHON_MULTILIB_REQUIRED_USE=\"${PYTHON_MULTILIB_REQUIRED_USE}\"" python_export "${i}" PYTHON_MULTILIB_PKG_DEP PYTHON_MULTILIB_DEPS+="python_single_target_${i}? ( ${PYTHON_MULTILIB_PKG_DEP} ) " impls+=( "${i}" ) done if [[ ${#impls[@]} -eq 0 ]]; then die "No supported implementation in PYTHON_COMPAT." fi debug-print "${FUNCNAME}: impls=(${impls[*]})" local flags_mt=( "${impls[@]/#/python_targets_}" ) debug-print "${FUNCNAME}: flags_mt=(${flags_mt[*]})" local flags=( "${impls[@]/#/python_single_target_}" ) debug-print "${FUNCNAME}: flags=(${flags[*]})" local optflags=${flags_mt[@]/%/(-)?} optflags+=,${flags[@]/%/(+)?} debug-print "${FUNCNAME}: optflags=(${optflags[*]})" IUSE="${flags_mt[*]} ${flags[*]}" debug-print "${FUNCNAME}: IUSE=\"${IUSE}\"" PYTHON_REQUIRED_USE+=" ^^ ( ${flags[*]} )" debug-print "${FUNCNAME}: PYTHON_REQUIRED_USE=\"${PYTHON_REQUIRED_USE}\"" PYTHON_MULTILIB_USEDEP=${optflags// /,} debug-print "${FUNCNAME}: PYTHON_MULTILIB_USEDEP=\"${PYTHON_MULTILIB_USEDEP}\"" PYTHON_MULTILIB_DEPS+=" dev-lang/python-exec:=[${PYTHON_MULTILIB_USEDEP}]" debug-print "${FUNCNAME}: PYTHON_MULTILIB_DEPS=\"${PYTHON_MULTILIB_DEPS}\"" # now do the multilib variables debug-print "${FUNCNAME}: ------------ multilib -----------" 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 as well. # # This is in order to enforce correct dependencies on packages # supporting multiple implementations. PYTHON_MULTILIB_REQUIRED_USE+=" python_multilib_single_targets_${i}? ( python_multilib_targets_${i} python_single_target_${si} " # in flexible mode the multilib abi needn't match the python multilib abi [[ ${PYTHON_MULTILIB_SINGLE_MODE} != flexible ]] && PYTHON_MULTILIB_REQUIRED_USE+="${uf} " PYTHON_MULTILIB_REQUIRED_USE+=") " python_export "${i2}" PYTHON_MULTILIB_PKG_DEP PYTHON_MULTILIB_DEPS+=" python_multilib_single_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_mt=( "${impls[@]/#/python_multilib_targets_}" ) debug-print "${FUNCNAME}: flags_mt=(${flags_mt[*]})" flags=( "${impls[@]/#/python_multilib_single_targets_}" ) debug-print "${FUNCNAME}: flags=(${flags[*]})" optflags=${flags_mt[@]/%/(-)?} optflags+=,${flags[@]/%/(+)?} debug-print "${FUNCNAME}: optflags=(${optflags[*]})" IUSE+=" ${flags_mt[*]} ${flags[*]}" debug-print "${FUNCNAME}: final value: IUSE=\"${IUSE}\"" # in default mode, at most a single multilib useflag is allowed to be selected [[ ${PYTHON_MULTILIB_SINGLE_MODE} == default ]] && PYTHON_MULTILIB_REQUIRED_USE+=" || ( ^^ ( ${flags[*]} ) ( ${flags[*]/#/!} ) )" debug-print "${FUNCNAME}: final value: PYTHON_MULTILIB_REQUIRED_USE=\"${PYTHON_MULTILIB_REQUIRED_USE}\"" PYTHON_MULTILIB_USEDEP+="${PYTHON_MULTILIB_USEDEP:+,}${optflags// /,}" debug-print "${FUNCNAME}: PYTHON_MULTILIB_USEDEP=\"${PYTHON_MULTILIB_USEDEP}\"" # 1) well, python-exec would suffice as an RDEP # but no point in making this overcomplex, BDEP doesn't hurt anyone PYTHON_MULTILIB_DEPS+=" dev-lang/python-exec:=[${PYTHON_MULTILIB_USEDEP}]" debug-print "${FUNCNAME}: final result: PYTHON_MULTILIB_DEPS=\"${PYTHON_MULTILIB_DEPS}\"" } _python_single_multilib_set_globals # @FUNCTION: python_setup # @DESCRIPTION: # There's such thing here. Don't call this. python_setup() { die "\"${FUNCNAME}\"? Don't know him. Try the eclass a few inodes down the dirent, maybe." } # @FUNCTION: python_multilib_single_foreach_python # @DESCRIPTION: # Determine what the selected Python implementation is, specializing for # any active multilib-build ABI. Set the Python build environment up; then, # run whatever was passed in as an argument. Then, put things roughly back # the way they were before. #python_multilib_single_foreach_python() { # debug-print-function ${FUNCNAME} "${@}" # # local EPYTHON PYTHON # # local impl nomulti_impl= # # for impl in "${_PYTHON_ALL_IMPLS_NOMULTILIB[@]}"; do # if has "${impl}" "${PYTHON_COMPAT[@]}" \ # && use "python_single_target_${impl}" # then # if [[ ${EPYTHON} ]]; then # eerror "Your PYTHON_SINGLE_TARGET setting lists more than a single Python" # eerror "implementation. Please set it to just one value. If you need" # eerror "to override the value for a single package, please use package.env" # eerror "or an equivalent solution (man 5 portage)." # echo # die "More than one implementation in PYTHON_SINGLE_TARGET." # fi # # if ! use "python_targets_${impl}"; then # eerror "The implementation chosen as PYTHON_SINGLE_TARGET must be added" # eerror "to PYTHON_TARGETS as well. This is in order to ensure that" # eerror "dependencies are satisfied correctly. We're sorry" # eerror "for the inconvenience." # echo # die "Build target (${impl}) not in PYTHON_TARGETS." # fi # EPYTHON=$(epythonize ${impl}) # nomulti_impl="${impl}" # debug-print "${FUNCNAME}: Found matching no-multilib impl \"${impl}\"" # fi # done # # if [[ ! ${EPYTHON} ]]; then # eerror "No Python implementation selected for the build. Please set" # eerror "the PYTHON_SINGLE_TARGET variable in your make.conf to one" # eerror "of the following values:" # eerror # eerror "${PYTHON_COMPAT[@]}" # echo # die "No supported Python implementation in PYTHON_SINGLE_TARGET." # fi # # # great, we're GTG for no-multilib. Anything better out in multilib-land? # if [[ "${MULTILIB_BUILD_ABI}" ]] ; then # local other_epython other_impl abi_flag=$(multilib_abi_flag "${MULTILIB_BUILD_ABI}") # abi_flag="${abi_flag#abi_}" # if [[ ${abi_flag} ]] ; then # other_impl="${nomulti_impl}_${abi_flag}" # if has "${other_impl}" "${PYTHON_COMPAT_MULTILIB[@]}" \ # && use "python_multilib_single_targets_${other_impl}" # then # other_epython=$(epythonize "${other_impl}") # if [[ ${other_epython} != ${EPYTHON} ]]; then # debug-print "${FUNCNAME}: \"${EPYTHON}\" (nomulti) vs \"${other_epython}\" (multi)?" # # # a wee sanity check # local sother_epython=$(_python_strip_epython_abi "${other_epython}") # if [[ ${EPYTHON} != ${sother_epython} ]] ; then # eerror "The python implementation \"${other_impl}\" appears in your" # eerror "PYTHON_MULTILIB_SINGLE_TARGETS_... and seems to correspond to" # eerror "the value \"${nomulti_impl}\" in PYTHON_SINGLE_TARGET. However," # eerror "the epython's don't seem to have the same relationship:" # eerror "EPYTHON=\"${EPYTHON}\";other_epython=\"${other_epython}\";sother_epython=\"${sother_epython}\"." # eerror "That's not even supposed to be possible!" # echo # die "${FUNCNAME}: Some kinda bug in the framework, it seems." # fi # fi # fi # debug-print "${FUNCNAME}: Yay, declaring multilib victory:" # debug-print "${FUNCNAME}: EPYTHON multilib-abi-adjusted from \"${EPYTHON}\" to \"${other_epython}\"" # EPYTHON=${other_epython} # fi # fi # # # multilib or not, doesn't matter from here on out. # local PATH="${PATH}" PKG_CONFIG_PATH="${PKG_CONFIG_PATH}" # export PATH PKG_CONFIG_PATH # python_export EPYTHON PYTHON # python_wrapper_setup # "$@" #} # @FUNCTION: python_fix_shebang # @USAGE: ... # @DESCRIPTION: # Replace the shebang in Python scripts with the current Python # implementation (EPYTHON). If a directory is passed, works recursively # on all Python scripts. # # Only files having a 'python' shebang will be modified; other files # will be skipped. If a script has a complete shebang matching # the chosen interpreter version, it is left unmodified. If a script has # a complete shebang matching other version, the command dies. python_fix_shebang() { debug-print-function ${FUNCNAME} "${@}" [[ ${1} ]] || die "${FUNCNAME}: no paths given" [[ ${EPYTHON} ]] || die "${FUNCNAME}: EPYTHON unset (pkg_setup not called?)" local path f for path; do while IFS= read -r -d '' f; do local shebang=$(head -n 1 "${f}") case "${shebang}" in '#!'*${EPYTHON}*) debug-print "${FUNCNAME}: in file ${f#${D}}" debug-print "${FUNCNAME}: shebang matches EPYTHON: ${shebang}" ;; '#!'*python[23].[0123456789]*|'#!'*pypy-c*|'#!'*jython*) debug-print "${FUNCNAME}: in file ${f#${D}}" debug-print "${FUNCNAME}: incorrect specific shebang: ${shebang}" die "${f#${D}} has a specific Python shebang not matching EPYTHON" ;; '#!'*python*) debug-print "${FUNCNAME}: in file ${f#${D}}" debug-print "${FUNCNAME}: rewriting shebang: ${shebang}" einfo "Fixing shebang in ${f#${D}}" python_rewrite_shebang_multilib "${f}" esac done < <(find "${path}" -type f -print0) done } python_multilib_single_with_abi_python() { # obtain the abis list _python_cache_active_impls _python_check_USE_PYTHON local impl mp_impl for impl in "${_PYTHON_ACTIVE_NOMULTILIB_IMPL_CACHE}" ; do for ml_impl in "${_PYTHON_ACTIVE_MULTILIB_IMPL_CACHE}" ; do debug-print "${FUNCNAME}: checking impl=\"${impl}\" ml_impl=\"${ml_impl}\" strip_impl_abi -> \"$(_python_strip_multilib_impl_abi ${ml_impl})\" impl_abi -> \"$(_python_impl_abi ${ml_impl})\"" if [[ $(_python_strip_multilib_impl_abi ${ml_impl}) == ${impl} ]] ; then if [[ $(_python_impl_abi ${ml_impl}) == ${ABI:-${DEFAULT_ABI:-default}} ]] ; then if [[ $(_python_impl_abi ${ml_impl}) == ${DEFAULT_ABI:-${ABI:-default}} ]] ; then debug-print "${FUNCNAME}: got it: invoking python_multilib_automagic_wrapper \"\${impl}\" \"\$@\"" python_multilib_automagic_wrapper "${impl}" "$@" else debug-print "${FUNCNAME}: got it: invoking python_multilib_automagic_wrapper \"\${ml_impl}\" \"\$@\"" python_multilib_automagic_wrapper "${ml_impl}" "$@" fi return $? fi fi done debug-print "${FUNCNAME}: got it (no-ml): invoking python_multilib_automagic_wrapper \"\${impl}\" \"\$@\"" if [[ $(_python_impl_abi ${impl}) == ${ABI:-${DEFAULT_ABI:-default}} ]] ; then python_multilib_automagic_wrapper "${impl}" "$@" return $? fi done die "${FUNCNAME}: cant figure out correct impl" } _PYTHON_MULTILIB_SINGLE_R1=1 fi