# Copyright 1999-2015 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # $Id$ # @ECLASS: python-utils-r1.eclass # @MAINTAINER: # Python team <python@gentoo.org> # @AUTHOR: # Author: Michał Górny <mgorny@gentoo.org> # Based on work of: Krzysztof Pawlik <nelchael@gentoo.org> # @BLURB: Utility functions for packages with Python parts. # @DESCRIPTION: # A utility eclass providing functions to query Python implementations, # install Python modules and scripts. # # This eclass does not set any metadata variables nor export any phase # functions. It can be inherited safely. # # For more information, please see the wiki: # https://wiki.gentoo.org/wiki/Project:Python/python-utils-r1 case "${EAPI:-0}" in 0|1|2|3|4|5|6) ;; *) die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}" ;; esac if [[ ${_PYTHON_ECLASS_INHERITED} ]]; then die 'python-r1 suite eclasses can not be used with python.eclass.' fi if [[ ! ${_PYTHON_UTILS_R1} ]]; then [[ ${EAPI:-0} == [012345] ]] && inherit eutils multilib inherit toolchain-funcs # @ECLASS-VARIABLE: _PYTHON_ALL_IMPLS # @INTERNAL # @DESCRIPTION: # All supported Python implementations, most preferred last. _PYTHON_ALL_IMPLS=( jython2_7 pypy pypy3 python2_7 python3_3 python3_4 python3_5 ) readonly _PYTHON_ALL_IMPLS # @FUNCTION: _python_impl_supported # @USAGE: <impl> # @INTERNAL # @DESCRIPTION: # Check whether the implementation <impl> (PYTHON_COMPAT-form) # is still supported. # # Returns 0 if the implementation is valid and supported. If it is # unsupported, returns 1 -- and the caller should ignore the entry. # If it is invalid, dies with an appopriate error messages. _python_impl_supported() { debug-print-function ${FUNCNAME} "${@}" [[ ${#} -eq 1 ]] || die "${FUNCNAME}: takes exactly 1 argument (impl)." local impl=${1} # keep in sync with _PYTHON_ALL_IMPLS! # (not using that list because inline patterns shall be faster) case "${impl}" in python2_7|python3_[345]|jython2_7) return 0 ;; pypy1_[89]|pypy2_0|python2_[56]|python3_[12]) return 1 ;; pypy|pypy3) if [[ ${EAPI:-0} == [01234] ]]; then die "PyPy is supported in EAPI 5 and newer only." fi ;; *) die "Invalid implementation in PYTHON_COMPAT: ${impl}" esac } # @FUNCTION: _python_set_impls # @INTERNAL # @DESCRIPTION: # Check PYTHON_COMPAT for well-formedness and validity, then set # two global variables: # # - _PYTHON_SUPPORTED_IMPLS containing valid implementations supported # by the ebuild (PYTHON_COMPAT - dead implementations), # # - and _PYTHON_UNSUPPORTED_IMPLS containing valid implementations that # are not supported by the ebuild. # # Implementations in both variables are ordered using the pre-defined # eclass implementation ordering. # # This function must be called once in global scope by an eclass # utilizing PYTHON_COMPAT. _python_set_impls() { local i if ! declare -p PYTHON_COMPAT &>/dev/null; then die 'PYTHON_COMPAT not declared.' fi if [[ $(declare -p PYTHON_COMPAT) != "declare -a"* ]]; then die 'PYTHON_COMPAT must be an array.' fi for i in "${PYTHON_COMPAT[@]}"; do # trigger validity checks _python_impl_supported "${i}" done _PYTHON_SUPPORTED_IMPLS=() _PYTHON_UNSUPPORTED_IMPLS=() for i in "${_PYTHON_ALL_IMPLS[@]}"; do if has "${i}" "${PYTHON_COMPAT[@]}"; then _PYTHON_SUPPORTED_IMPLS+=( "${i}" ) else _PYTHON_UNSUPPORTED_IMPLS+=( "${i}" ) fi done if [[ ${#_PYTHON_SUPPORTED_IMPLS[@]} -eq 0 ]]; then die "No supported implementation in PYTHON_COMPAT." fi readonly _PYTHON_SUPPORTED_IMPLS _PYTHON_UNSUPPORTED_IMPLS } # @ECLASS-VARIABLE: PYTHON # @DEFAULT_UNSET # @DESCRIPTION: # The absolute path to the current Python interpreter. # # This variable is set automatically in the following contexts: # # python-r1: Set in functions called by python_foreach_impl() or after # calling python_export_best(). # # python-single-r1: Set after calling python-single-r1_pkg_setup(). # # distutils-r1: Set within any of the python sub-phase functions. # # Example value: # @CODE # /usr/bin/python2.7 # @CODE # @ECLASS-VARIABLE: EPYTHON # @DEFAULT_UNSET # @DESCRIPTION: # The executable name of the current Python interpreter. # # This variable is set automatically in the following contexts: # # python-r1: Set in functions called by python_foreach_impl() or after # calling python_export_best(). # # python-single-r1: Set after calling python-single-r1_pkg_setup(). # # distutils-r1: Set within any of the python sub-phase functions. # # Example value: # @CODE # python2.7 # @CODE # @ECLASS-VARIABLE: PYTHON_SITEDIR # @DEFAULT_UNSET # @DESCRIPTION: # The path to Python site-packages directory. # # Set and exported on request using python_export(). # Requires a proper build-time dependency on the Python implementation. # # Example value: # @CODE # /usr/lib64/python2.7/site-packages # @CODE # @ECLASS-VARIABLE: PYTHON_INCLUDEDIR # @DEFAULT_UNSET # @DESCRIPTION: # The path to Python include directory. # # Set and exported on request using python_export(). # Requires a proper build-time dependency on the Python implementation. # # Example value: # @CODE # /usr/include/python2.7 # @CODE # @ECLASS-VARIABLE: PYTHON_LIBPATH # @DEFAULT_UNSET # @DESCRIPTION: # The path to Python library. # # Set and exported on request using python_export(). # Valid only for CPython. Requires a proper build-time dependency # on the Python implementation. # # Example value: # @CODE # /usr/lib64/libpython2.7.so # @CODE # @ECLASS-VARIABLE: PYTHON_CFLAGS # @DEFAULT_UNSET # @DESCRIPTION: # Proper C compiler flags for building against Python. Obtained from # pkg-config or python-config. # # Set and exported on request using python_export(). # Valid only for CPython. Requires a proper build-time dependency # on the Python implementation and on pkg-config. # # Example value: # @CODE # -I/usr/include/python2.7 # @CODE # @ECLASS-VARIABLE: PYTHON_LIBS # @DEFAULT_UNSET # @DESCRIPTION: # Proper C compiler flags for linking against Python. Obtained from # pkg-config or python-config. # # Set and exported on request using python_export(). # Valid only for CPython. Requires a proper build-time dependency # on the Python implementation and on pkg-config. # # Example value: # @CODE # -lpython2.7 # @CODE # @ECLASS-VARIABLE: PYTHON_CONFIG # @DEFAULT_UNSET # @DESCRIPTION: # Path to the python-config executable. # # Set and exported on request using python_export(). # Valid only for CPython. Requires a proper build-time dependency # on the Python implementation and on pkg-config. # # Example value: # @CODE # /usr/bin/python2.7-config # @CODE # @ECLASS-VARIABLE: PYTHON_PKG_DEP # @DEFAULT_UNSET # @DESCRIPTION: # The complete dependency on a particular Python package as a string. # # Set and exported on request using python_export(). # # Example value: # @CODE # dev-lang/python:2.7[xml] # @CODE # @ECLASS-VARIABLE: PYTHON_SCRIPTDIR # @DEFAULT_UNSET # @DESCRIPTION: # The location where Python scripts must be installed for current impl. # # Set and exported on request using python_export(). # # Example value: # @CODE # /usr/lib/python-exec/python2.7 # @CODE # @FUNCTION: python_export # @USAGE: [<impl>] <variables>... # @DESCRIPTION: # Set and export the Python implementation-relevant variables passed # as parameters. # # The optional first parameter may specify the requested Python # implementation (either as PYTHON_TARGETS value, e.g. python2_7, # or an EPYTHON one, e.g. python2.7). If no implementation passed, # the current one will be obtained from ${EPYTHON}. # # The variables which can be exported are: PYTHON, EPYTHON, # PYTHON_SITEDIR. They are described more completely in the eclass # variable documentation. python_export() { debug-print-function ${FUNCNAME} "${@}" local impl var case "${1}" in python*|jython*) impl=${1/_/.} shift ;; pypy|pypy3) impl=${1} shift ;; *) impl=${EPYTHON} if [[ -z ${impl} ]]; then die "python_export called without a python implementation and EPYTHON is unset" fi ;; esac debug-print "${FUNCNAME}: implementation: ${impl}" for var; do case "${var}" in EPYTHON) export EPYTHON=${impl} debug-print "${FUNCNAME}: EPYTHON = ${EPYTHON}" ;; PYTHON) export PYTHON=${EPREFIX}/usr/bin/${impl} debug-print "${FUNCNAME}: PYTHON = ${PYTHON}" ;; PYTHON_SITEDIR) [[ -n ${PYTHON} ]] || die "PYTHON needs to be set for ${var} to be exported, or requested before it" # sysconfig can't be used because: # 1) pypy doesn't give site-packages but stdlib # 2) jython gives paths with wrong case PYTHON_SITEDIR=$("${PYTHON}" -c 'import distutils.sysconfig; print(distutils.sysconfig.get_python_lib())') || die export PYTHON_SITEDIR debug-print "${FUNCNAME}: PYTHON_SITEDIR = ${PYTHON_SITEDIR}" ;; PYTHON_INCLUDEDIR) [[ -n ${PYTHON} ]] || die "PYTHON needs to be set for ${var} to be exported, or requested before it" PYTHON_INCLUDEDIR=$("${PYTHON}" -c 'import distutils.sysconfig; print(distutils.sysconfig.get_python_inc())') || die export PYTHON_INCLUDEDIR debug-print "${FUNCNAME}: PYTHON_INCLUDEDIR = ${PYTHON_INCLUDEDIR}" # Jython gives a non-existing directory if [[ ! -d ${PYTHON_INCLUDEDIR} ]]; then die "${impl} does not install any header files!" fi ;; PYTHON_LIBPATH) [[ -n ${PYTHON} ]] || die "PYTHON needs to be set for ${var} to be exported, or requested before it" PYTHON_LIBPATH=$("${PYTHON}" -c 'import os.path, sysconfig; print(os.path.join(sysconfig.get_config_var("LIBDIR"), sysconfig.get_config_var("LDLIBRARY")) if sysconfig.get_config_var("LDLIBRARY") else "")') || die export PYTHON_LIBPATH debug-print "${FUNCNAME}: PYTHON_LIBPATH = ${PYTHON_LIBPATH}" if [[ ! ${PYTHON_LIBPATH} ]]; then die "${impl} lacks a (usable) dynamic library" fi ;; PYTHON_CFLAGS) local val case "${impl}" in python*) # python-2.7, python-3.2, etc. val=$($(tc-getPKG_CONFIG) --cflags ${impl/n/n-}) || die ;; *) die "${impl}: obtaining ${var} not supported" ;; esac export PYTHON_CFLAGS=${val} debug-print "${FUNCNAME}: PYTHON_CFLAGS = ${PYTHON_CFLAGS}" ;; PYTHON_LIBS) local val case "${impl}" in python*) # python-2.7, python-3.2, etc. val=$($(tc-getPKG_CONFIG) --libs ${impl/n/n-}) || die ;; *) die "${impl}: obtaining ${var} not supported" ;; esac export PYTHON_LIBS=${val} debug-print "${FUNCNAME}: PYTHON_LIBS = ${PYTHON_LIBS}" ;; PYTHON_CONFIG) local flags val case "${impl}" in python*) [[ -n ${PYTHON} ]] || die "PYTHON needs to be set for ${var} to be exported, or requested before it" flags=$("${PYTHON}" -c 'import sysconfig; print(sysconfig.get_config_var("ABIFLAGS") or "")') || die val=${PYTHON}${flags}-config ;; *) die "${impl}: obtaining ${var} not supported" ;; esac export PYTHON_CONFIG=${val} debug-print "${FUNCNAME}: PYTHON_CONFIG = ${PYTHON_CONFIG}" ;; PYTHON_PKG_DEP) local d case ${impl} in python2.7) PYTHON_PKG_DEP='>=dev-lang/python-2.7.5-r2:2.7';; python3.3) PYTHON_PKG_DEP='>=dev-lang/python-3.3.2-r2:3.3';; python*) PYTHON_PKG_DEP="dev-lang/python:${impl#python}";; pypy) PYTHON_PKG_DEP='virtual/pypy:0=';; pypy3) PYTHON_PKG_DEP='virtual/pypy3:0=';; jython2.7) PYTHON_PKG_DEP='dev-java/jython:2.7';; *) die "Invalid implementation: ${impl}" esac # use-dep if [[ ${PYTHON_REQ_USE} ]]; then PYTHON_PKG_DEP+=[${PYTHON_REQ_USE}] fi export PYTHON_PKG_DEP debug-print "${FUNCNAME}: PYTHON_PKG_DEP = ${PYTHON_PKG_DEP}" ;; PYTHON_SCRIPTDIR) local dir export PYTHON_SCRIPTDIR=${EPREFIX}/usr/lib/python-exec/${impl} debug-print "${FUNCNAME}: PYTHON_SCRIPTDIR = ${PYTHON_SCRIPTDIR}" ;; *) die "python_export: unknown variable ${var}" esac done } # @FUNCTION: python_get_sitedir # @USAGE: [<impl>] # @DESCRIPTION: # Obtain and print the 'site-packages' path for the given # implementation. If no implementation is provided, ${EPYTHON} will # be used. # # If you just need to have PYTHON_SITEDIR set (and exported), then it is # better to use python_export() directly instead. python_get_sitedir() { debug-print-function ${FUNCNAME} "${@}" python_export "${@}" PYTHON_SITEDIR echo "${PYTHON_SITEDIR}" } # @FUNCTION: python_get_includedir # @USAGE: [<impl>] # @DESCRIPTION: # Obtain and print the include path for the given implementation. If no # implementation is provided, ${EPYTHON} will be used. # # If you just need to have PYTHON_INCLUDEDIR set (and exported), then it # is better to use python_export() directly instead. python_get_includedir() { debug-print-function ${FUNCNAME} "${@}" python_export "${@}" PYTHON_INCLUDEDIR echo "${PYTHON_INCLUDEDIR}" } # @FUNCTION: python_get_library_path # @USAGE: [<impl>] # @DESCRIPTION: # Obtain and print the Python library path for the given implementation. # If no implementation is provided, ${EPYTHON} will be used. # # Please note that this function can be used with CPython only. Use # in another implementation will result in a fatal failure. python_get_library_path() { debug-print-function ${FUNCNAME} "${@}" python_export "${@}" PYTHON_LIBPATH echo "${PYTHON_LIBPATH}" } # @FUNCTION: python_get_CFLAGS # @USAGE: [<impl>] # @DESCRIPTION: # Obtain and print the compiler flags for building against Python, # for the given implementation. If no implementation is provided, # ${EPYTHON} will be used. # # Please note that this function can be used with CPython only. # It requires Python and pkg-config installed, and therefore proper # build-time dependencies need be added to the ebuild. python_get_CFLAGS() { debug-print-function ${FUNCNAME} "${@}" python_export "${@}" PYTHON_CFLAGS echo "${PYTHON_CFLAGS}" } # @FUNCTION: python_get_LIBS # @USAGE: [<impl>] # @DESCRIPTION: # Obtain and print the compiler flags for linking against Python, # for the given implementation. If no implementation is provided, # ${EPYTHON} will be used. # # Please note that this function can be used with CPython only. # It requires Python and pkg-config installed, and therefore proper # build-time dependencies need be added to the ebuild. python_get_LIBS() { debug-print-function ${FUNCNAME} "${@}" python_export "${@}" PYTHON_LIBS echo "${PYTHON_LIBS}" } # @FUNCTION: python_get_PYTHON_CONFIG # @USAGE: [<impl>] # @DESCRIPTION: # Obtain and print the PYTHON_CONFIG location for the given # implementation. If no implementation is provided, ${EPYTHON} will be # used. # # Please note that this function can be used with CPython only. # It requires Python installed, and therefore proper build-time # dependencies need be added to the ebuild. python_get_PYTHON_CONFIG() { debug-print-function ${FUNCNAME} "${@}" python_export "${@}" PYTHON_CONFIG echo "${PYTHON_CONFIG}" } # @FUNCTION: python_get_scriptdir # @USAGE: [<impl>] # @DESCRIPTION: # Obtain and print the script install path for the given # implementation. If no implementation is provided, ${EPYTHON} will # be used. python_get_scriptdir() { debug-print-function ${FUNCNAME} "${@}" python_export "${@}" PYTHON_SCRIPTDIR echo "${PYTHON_SCRIPTDIR}" } # @FUNCTION: _python_ln_rel # @USAGE: <from> <to> # @INTERNAL # @DESCRIPTION: # Create a relative symlink. _python_ln_rel() { debug-print-function ${FUNCNAME} "${@}" local target=${1} local symname=${2} local tgpath=${target%/*}/ local sympath=${symname%/*}/ local rel_target= while [[ ${sympath} ]]; do local tgseg= symseg= while [[ ! ${tgseg} && ${tgpath} ]]; do tgseg=${tgpath%%/*} tgpath=${tgpath#${tgseg}/} done while [[ ! ${symseg} && ${sympath} ]]; do symseg=${sympath%%/*} sympath=${sympath#${symseg}/} done if [[ ${tgseg} != ${symseg} ]]; then rel_target=../${rel_target}${tgseg:+${tgseg}/} fi done rel_target+=${tgpath}${target##*/} debug-print "${FUNCNAME}: ${symname} -> ${target}" debug-print "${FUNCNAME}: rel_target = ${rel_target}" ln -fs "${rel_target}" "${symname}" } # @FUNCTION: python_optimize # @USAGE: [<directory>...] # @DESCRIPTION: # Compile and optimize Python modules in specified directories (absolute # paths). If no directories are provided, the default system paths # are used (prepended with ${D}). python_optimize() { debug-print-function ${FUNCNAME} "${@}" if [[ ${EBUILD_PHASE} == pre* || ${EBUILD_PHASE} == post* ]]; then eerror "The new Python eclasses expect the compiled Python files to" eerror "be controlled by the Package Manager. For this reason," eerror "the python_optimize function can be used only during src_* phases" eerror "(src_install most commonly) and not during pkg_* phases." echo die "python_optimize is not to be used in pre/post* phases" fi [[ ${EPYTHON} ]] || die 'No Python implementation set (EPYTHON is null).' local PYTHON=${PYTHON} [[ ${PYTHON} ]] || python_export PYTHON # default to sys.path if [[ ${#} -eq 0 ]]; then local f while IFS= read -r -d '' f; do # 1) accept only absolute paths # (i.e. skip '', '.' or anything like that) # 2) skip paths which do not exist # (python2.6 complains about them verbosely) if [[ ${f} == /* && -d ${D}${f} ]]; then set -- "${D}${f}" "${@}" fi done < <("${PYTHON}" -c 'import sys; print("\0".join(sys.path))' || die) debug-print "${FUNCNAME}: using sys.path: ${*/%/;}" fi local d for d; do # make sure to get a nice path without // local instpath=${d#${D}} instpath=/${instpath##/} case "${EPYTHON}" in python*) "${PYTHON}" -m compileall -q -f -d "${instpath}" "${d}" "${PYTHON}" -OO -m compileall -q -f -d "${instpath}" "${d}" ;; *) "${PYTHON}" -m compileall -q -f -d "${instpath}" "${d}" ;; esac done } # @ECLASS-VARIABLE: python_scriptroot # @DEFAULT_UNSET # @DESCRIPTION: # The current script destination for python_doscript(). The path # is relative to the installation root (${ED}). # # When unset, ${DESTTREE}/bin (/usr/bin by default) will be used. # # Can be set indirectly through the python_scriptinto() function. # # Example: # @CODE # src_install() { # local python_scriptroot=${GAMES_BINDIR} # python_foreach_impl python_doscript foo # } # @CODE # @FUNCTION: python_scriptinto # @USAGE: <new-path> # @DESCRIPTION: # Set the current scriptroot. The new value will be stored # in the 'python_scriptroot' environment variable. The new value need # be relative to the installation root (${ED}). # # Alternatively, you can set the variable directly. python_scriptinto() { debug-print-function ${FUNCNAME} "${@}" python_scriptroot=${1} } # @FUNCTION: python_doexe # @USAGE: <files>... # @DESCRIPTION: # Install the given executables into current python_scriptroot, # for the current Python implementation (${EPYTHON}). # # The executable will be wrapped properly for the Python implementation, # though no shebang mangling will be performed. python_doexe() { debug-print-function ${FUNCNAME} "${@}" local f for f; do python_newexe "${f}" "${f##*/}" done } # @FUNCTION: python_newexe # @USAGE: <path> <new-name> # @DESCRIPTION: # Install the given executable into current python_scriptroot, # for the current Python implementation (${EPYTHON}). # # The executable will be wrapped properly for the Python implementation, # though no shebang mangling will be performed. It will be renamed # to <new-name>. python_newexe() { debug-print-function ${FUNCNAME} "${@}" [[ ${EPYTHON} ]] || die 'No Python implementation set (EPYTHON is null).' [[ ${#} -eq 2 ]] || die "Usage: ${FUNCNAME} <path> <new-name>" if [[ ${EAPI:-0} == [0123] ]]; then die "python_do* and python_new* helpers are banned in EAPIs older than 4." fi local wrapd=${python_scriptroot:-${DESTTREE}/bin} local f=${1} local newfn=${2} local PYTHON_SCRIPTDIR d python_export PYTHON_SCRIPTDIR d=${PYTHON_SCRIPTDIR#${EPREFIX}} ( dodir "${wrapd}" exeinto "${d}" newexe "${f}" "${newfn}" || return ${?} ) # install the wrapper _python_ln_rel "${ED%/}"/usr/lib/python-exec/python-exec2 \ "${ED%/}/${wrapd}/${newfn}" || die # don't use this at home, just call python_doscript() instead if [[ ${_PYTHON_REWRITE_SHEBANG} ]]; then python_fix_shebang -q "${ED%/}/${d}/${newfn}" fi } # @FUNCTION: python_doscript # @USAGE: <files>... # @DESCRIPTION: # Install the given scripts into current python_scriptroot, # for the current Python implementation (${EPYTHON}). # # All specified files must start with a 'python' shebang. The shebang # will be converted, and the files will be wrapped properly # for the Python implementation. # # Example: # @CODE # src_install() { # python_foreach_impl python_doscript ${PN} # } # @CODE python_doscript() { debug-print-function ${FUNCNAME} "${@}" local _PYTHON_REWRITE_SHEBANG=1 python_doexe "${@}" } # @FUNCTION: python_newscript # @USAGE: <path> <new-name> # @DESCRIPTION: # Install the given script into current python_scriptroot # for the current Python implementation (${EPYTHON}), and name it # <new-name>. # # The file must start with a 'python' shebang. The shebang will be # converted, and the file will be wrapped properly for the Python # implementation. It will be renamed to <new-name>. # # Example: # @CODE # src_install() { # python_foreach_impl python_newscript foo.py foo # } # @CODE python_newscript() { debug-print-function ${FUNCNAME} "${@}" local _PYTHON_REWRITE_SHEBANG=1 python_newexe "${@}" } # @ECLASS-VARIABLE: python_moduleroot # @DEFAULT_UNSET # @DESCRIPTION: # The current module root for python_domodule(). The path can be either # an absolute system path (it must start with a slash, and ${ED} will be # prepended to it) or relative to the implementation's site-packages directory # (then it must start with a non-slash character). # # When unset, the modules will be installed in the site-packages root. # # Can be set indirectly through the python_moduleinto() function. # # Example: # @CODE # src_install() { # local python_moduleroot=bar # # installs ${PYTHON_SITEDIR}/bar/baz.py # python_foreach_impl python_domodule baz.py # } # @CODE # @FUNCTION: python_moduleinto # @USAGE: <new-path> # @DESCRIPTION: # Set the current module root. The new value will be stored # in the 'python_moduleroot' environment variable. The new value need # be relative to the site-packages root. # # Alternatively, you can set the variable directly. python_moduleinto() { debug-print-function ${FUNCNAME} "${@}" python_moduleroot=${1} } # @FUNCTION: python_domodule # @USAGE: <files>... # @DESCRIPTION: # Install the given modules (or packages) into the current # python_moduleroot. The list can mention both modules (files) # and packages (directories). All listed files will be installed # for all enabled implementations, and compiled afterwards. # # Example: # @CODE # src_install() { # # (${PN} being a directory) # python_foreach_impl python_domodule ${PN} # } # @CODE python_domodule() { debug-print-function ${FUNCNAME} "${@}" [[ ${EPYTHON} ]] || die 'No Python implementation set (EPYTHON is null).' if [[ ${EAPI:-0} == [0123] ]]; then die "python_do* and python_new* helpers are banned in EAPIs older than 4." fi local d if [[ ${python_moduleroot} == /* ]]; then # absolute path d=${python_moduleroot} else # relative to site-packages local PYTHON_SITEDIR=${PYTHON_SITEDIR} [[ ${PYTHON_SITEDIR} ]] || python_export PYTHON_SITEDIR d=${PYTHON_SITEDIR#${EPREFIX}}/${python_moduleroot} fi ( insinto "${d}" doins -r "${@}" || return ${?} ) python_optimize "${ED}/${d}" } # @FUNCTION: python_doheader # @USAGE: <files>... # @DESCRIPTION: # Install the given headers into the implementation-specific include # directory. This function is unconditionally recursive, i.e. you can # pass directories instead of files. # # Example: # @CODE # src_install() { # python_foreach_impl python_doheader foo.h bar.h # } # @CODE python_doheader() { debug-print-function ${FUNCNAME} "${@}" [[ ${EPYTHON} ]] || die 'No Python implementation set (EPYTHON is null).' if [[ ${EAPI:-0} == [0123] ]]; then die "python_do* and python_new* helpers are banned in EAPIs older than 4." fi local d PYTHON_INCLUDEDIR=${PYTHON_INCLUDEDIR} [[ ${PYTHON_INCLUDEDIR} ]] || python_export PYTHON_INCLUDEDIR d=${PYTHON_INCLUDEDIR#${EPREFIX}} ( insinto "${d}" doins -r "${@}" || return ${?} ) } # @FUNCTION: python_wrapper_setup # @USAGE: [<path> [<impl>]] # @DESCRIPTION: # Create proper 'python' executable and pkg-config wrappers # (if available) in the directory named by <path>. Set up PATH # and PKG_CONFIG_PATH appropriately. <path> defaults to ${T}/${EPYTHON}. # # The wrappers will be created for implementation named by <impl>, # or for one named by ${EPYTHON} if no <impl> passed. # # If the named directory contains a python symlink already, it will # be assumed to contain proper wrappers already and only environment # setup will be done. If wrapper update is requested, the directory # shall be removed first. python_wrapper_setup() { debug-print-function ${FUNCNAME} "${@}" local workdir=${1:-${T}/${EPYTHON}} local impl=${2:-${EPYTHON}} [[ ${workdir} ]] || die "${FUNCNAME}: no workdir specified." [[ ${impl} ]] || die "${FUNCNAME}: no impl nor EPYTHON specified." if [[ ! -x ${workdir}/bin/python ]]; then _python_check_dead_variables mkdir -p "${workdir}"/{bin,pkgconfig} || die # Clean up, in case we were supposed to do a cheap update. rm -f "${workdir}"/bin/python{,2,3,-config} || die rm -f "${workdir}"/bin/2to3 || die rm -f "${workdir}"/pkgconfig/python{,2,3}.pc || die local EPYTHON PYTHON PYTHON_CONFIG python_export "${impl}" EPYTHON PYTHON local pyver pyother if python_is_python3; then pyver=3 pyother=2 else pyver=2 pyother=3 fi # Python interpreter # note: we don't use symlinks because python likes to do some # symlink reading magic that breaks stuff # https://bugs.gentoo.org/show_bug.cgi?id=555752 cat > "${workdir}/bin/python" <<-_EOF_ || die #!/bin/sh exec "${PYTHON}" "\${@}" _EOF_ cp "${workdir}/bin/python" "${workdir}/bin/python${pyver}" || die chmod +x "${workdir}/bin/python" "${workdir}/bin/python${pyver}" || die local nonsupp=( "python${pyother}" "python${pyother}-config" ) # CPython-specific if [[ ${EPYTHON} == python* ]]; then python_export "${impl}" PYTHON_CONFIG cat > "${workdir}/bin/python-config" <<-_EOF_ || die #!/bin/sh exec "${PYTHON_CONFIG}" "\${@}" _EOF_ cp "${workdir}/bin/python-config" \ "${workdir}/bin/python${pyver}-config" || die chmod +x "${workdir}/bin/python-config" \ "${workdir}/bin/python${pyver}-config" || die # Python 2.6+. ln -s "${PYTHON/python/2to3-}" "${workdir}"/bin/2to3 || die # Python 2.7+. ln -s "${EPREFIX}"/usr/$(get_libdir)/pkgconfig/${EPYTHON/n/n-}.pc \ "${workdir}"/pkgconfig/python.pc || die ln -s python.pc "${workdir}"/pkgconfig/python${pyver}.pc || die else nonsupp+=( 2to3 python-config "python${pyver}-config" ) fi local x for x in "${nonsupp[@]}"; do cat >"${workdir}"/bin/${x} <<-_EOF_ || die #!/bin/sh echo "${x} is not supported by ${EPYTHON}" >&2 exit 127 _EOF_ chmod +x "${workdir}"/bin/${x} || die done # Now, set the environment. # But note that ${workdir} may be shared with something else, # and thus already on top of PATH. if [[ ${PATH##:*} != ${workdir}/bin ]]; then PATH=${workdir}/bin${PATH:+:${PATH}} fi if [[ ${PKG_CONFIG_PATH##:*} != ${workdir}/pkgconfig ]]; then PKG_CONFIG_PATH=${workdir}/pkgconfig${PKG_CONFIG_PATH:+:${PKG_CONFIG_PATH}} fi export PATH PKG_CONFIG_PATH fi } # @FUNCTION: python_is_python3 # @USAGE: [<impl>] # @DESCRIPTION: # Check whether <impl> (or ${EPYTHON}) is a Python3k variant # (i.e. uses syntax and stdlib of Python 3.*). # # Returns 0 (true) if it is, 1 (false) otherwise. python_is_python3() { local impl=${1:-${EPYTHON}} [[ ${impl} ]] || die "python_is_python3: no impl nor EPYTHON" [[ ${impl} == python3* || ${impl} == pypy3 ]] } # @FUNCTION: python_is_installed # @USAGE: [<impl>] # @DESCRIPTION: # Check whether the interpreter for <impl> (or ${EPYTHON}) is installed. # Uses has_version with a proper dependency string. # # Returns 0 (true) if it is, 1 (false) otherwise. python_is_installed() { local impl=${1:-${EPYTHON}} [[ ${impl} ]] || die "${FUNCNAME}: no impl nor EPYTHON" # for has_version local -x ROOT=/ case "${impl}" in pypy|pypy3) local append= if [[ ${PYTHON_REQ_USE} ]]; then append=[${PYTHON_REQ_USE}] fi # be happy with just the interpeter, no need for the virtual has_version "dev-python/${impl}${append}" \ || has_version "dev-python/${impl}-bin${append}" ;; *) local PYTHON_PKG_DEP python_export "${impl}" PYTHON_PKG_DEP has_version "${PYTHON_PKG_DEP}" ;; esac } # @FUNCTION: python_fix_shebang # @USAGE: [-f|--force] [-q|--quiet] <path>... # @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. Files with # other shebang will either be skipped when working recursively # on a directory or treated as error when specified explicitly. # # Shebangs matching explicitly current Python version will be left # unmodified. Shebangs requesting another Python version will be treated # as fatal error, unless --force is given. # # --force causes the function to replace even shebangs that require # incompatible Python version. --quiet causes the function not to list # modified files verbosely. python_fix_shebang() { debug-print-function ${FUNCNAME} "${@}" [[ ${EPYTHON} ]] || die "${FUNCNAME}: EPYTHON unset (pkg_setup not called?)" local force quiet while [[ ${@} ]]; do case "${1}" in -f|--force) force=1; shift;; -q|--quiet) quiet=1; shift;; --) shift; break;; *) break;; esac done [[ ${1} ]] || die "${FUNCNAME}: no paths given" local path f for path; do local any_correct any_fixed is_recursive [[ -d ${path} ]] && is_recursive=1 while IFS= read -r -d '' f; do local shebang i local error= from= # note: we can't ||die here since read will fail if file # has no newline characters IFS= read -r shebang <"${f}" # First, check if it's shebang at all... if [[ ${shebang} == '#!'* ]]; then local split_shebang=() read -r -a split_shebang <<<${shebang} || die # Match left-to-right in a loop, to avoid matching random # repetitions like 'python2.7 python2'. for i in "${split_shebang[@]}"; do case "${i}" in *"${EPYTHON}") debug-print "${FUNCNAME}: in file ${f#${D}}" debug-print "${FUNCNAME}: shebang matches EPYTHON: ${shebang}" # Nothing to do, move along. any_correct=1 from=${EPYTHON} break ;; *python|*python[23]) debug-print "${FUNCNAME}: in file ${f#${D}}" debug-print "${FUNCNAME}: rewriting shebang: ${shebang}" if [[ ${i} == *python2 ]]; then from=python2 if [[ ! ${force} ]]; then python_is_python3 "${EPYTHON}" && error=1 fi elif [[ ${i} == *python3 ]]; then from=python3 if [[ ! ${force} ]]; then python_is_python3 "${EPYTHON}" || error=1 fi else from=python fi break ;; *python[23].[0123456789]|*pypy|*pypy3|*jython[23].[0123456789]) # Explicit mismatch. if [[ ! ${force} ]]; then error=1 else case "${i}" in *python[23].[0123456789]) from="python[23].[0123456789]";; *pypy) from="pypy";; *pypy3) from="pypy3";; *jython[23].[0123456789]) from="jython[23].[0123456789]";; *) die "${FUNCNAME}: internal error in 2nd pattern match";; esac fi break ;; esac done fi if [[ ! ${error} && ! ${from} ]]; then # Non-Python shebang. Allowed in recursive mode, # disallowed when specifying file explicitly. [[ ${is_recursive} ]] && continue error=1 fi if [[ ! ${quiet} ]]; then einfo "Fixing shebang in ${f#${D}}." fi if [[ ! ${error} ]]; then # We either want to match ${from} followed by space # or at end-of-string. if [[ ${shebang} == *${from}" "* ]]; then sed -i -e "1s:${from} :${EPYTHON} :" "${f}" || die else sed -i -e "1s:${from}$:${EPYTHON}:" "${f}" || die fi any_fixed=1 else eerror "The file has incompatible shebang:" eerror " file: ${f#${D}}" eerror " current shebang: ${shebang}" eerror " requested impl: ${EPYTHON}" die "${FUNCNAME}: conversion of incompatible shebang requested" fi done < <(find -H "${path}" -type f -print0 || die) if [[ ! ${any_fixed} ]]; then local cmd=eerror [[ ${EAPI:-0} == [012345] ]] && cmd=eqawarn "${cmd}" "QA warning: ${FUNCNAME}, ${path#${D}} did not match any fixable files." if [[ ${any_correct} ]]; then "${cmd}" "All files have ${EPYTHON} shebang already." else "${cmd}" "There are no Python files in specified directory." fi [[ ${cmd} == eerror ]] && die "${FUNCNAME} did not match any fixable files (QA warning fatal in EAPI ${EAPI})" fi done } # @FUNCTION: _python_check_locale_sanity # @USAGE: <locale> # @RETURN: 0 if sane, 1 otherwise # @DESCRIPTION: # Check whether the specified locale sanely maps between lowercase # and uppercase ASCII characters. _python_check_locale_sanity() { local -x LC_CTYPE=${1} local IFS= local lc=( {a..z} ) local uc=( {A..Z} ) local input="${lc[*]}${uc[*]}" local output=$(tr '[:lower:][:upper:]' '[:upper:][:lower:]' <<<"${input}") [[ ${output} == "${uc[*]}${lc[*]}" ]] } # @FUNCTION: python_export_utf8_locale # @RETURN: 0 on success, 1 on failure. # @DESCRIPTION: # Attempts to export a usable UTF-8 locale in the LC_CTYPE variable. Does # nothing if LC_ALL is defined, or if the current locale uses a UTF-8 charmap. # This may be used to work around the quirky open() behavior of python3. python_export_utf8_locale() { debug-print-function ${FUNCNAME} "${@}" # If the locale program isn't available, just return. type locale >/dev/null || return 0 if [[ $(locale charmap) != UTF-8 ]]; then # Try English first, then everything else. local lang locales="en_US.UTF-8 $(locale -a)" for lang in ${locales}; do if [[ $(LC_ALL=${lang} locale charmap 2>/dev/null) == UTF-8 ]]; then if _python_check_locale_sanity "${lang}"; then export LC_CTYPE=${lang} if [[ -n ${LC_ALL} ]]; then export LC_NUMERIC=${LC_ALL} export LC_TIME=${LC_ALL} export LC_COLLATE=${LC_ALL} export LC_MONETARY=${LC_ALL} export LC_MESSAGES=${LC_ALL} export LC_PAPER=${LC_ALL} export LC_NAME=${LC_ALL} export LC_ADDRESS=${LC_ALL} export LC_TELEPHONE=${LC_ALL} export LC_MEASUREMENT=${LC_ALL} export LC_IDENTIFICATION=${LC_ALL} export LC_ALL= fi return 0 fi fi done ewarn "Could not find a UTF-8 locale. This may trigger build failures in" ewarn "some python packages. Please ensure that a UTF-8 locale is listed in" ewarn "/etc/locale.gen and run locale-gen." return 1 fi return 0 } # -- python.eclass functions -- _python_check_dead_variables() { local v for v in PYTHON_DEPEND PYTHON_USE_WITH{,_OR,_OPT} {RESTRICT,SUPPORT}_PYTHON_ABIS do if [[ ${!v} ]]; then die "${v} is invalid for python-r1 suite, please take a look @ https://wiki.gentoo.org/wiki/Project:Python/Python.eclass_conversion#Ebuild_head" fi done for v in PYTHON_{CPPFLAGS,CFLAGS,CXXFLAGS,LDFLAGS} do if [[ ${!v} ]]; then die "${v} is invalid for python-r1 suite, please take a look @ https://wiki.gentoo.org/wiki/Project:Python/Python.eclass_conversion#PYTHON_CFLAGS" fi done for v in PYTHON_TESTS_RESTRICTED_ABIS PYTHON_EXPORT_PHASE_FUNCTIONS \ PYTHON_VERSIONED_{SCRIPTS,EXECUTABLES} PYTHON_NONVERSIONED_EXECUTABLES do if [[ ${!v} ]]; then die "${v} is invalid for python-r1 suite" fi done for v in DISTUTILS_USE_SEPARATE_SOURCE_DIRECTORIES DISTUTILS_SETUP_FILES \ DISTUTILS_GLOBAL_OPTIONS DISTUTILS_SRC_TEST PYTHON_MODNAME do if [[ ${!v} ]]; then die "${v} is invalid for distutils-r1, please take a look @ https://wiki.gentoo.org/wiki/Project:Python/Python.eclass_conversion#${v}" fi done if [[ ${DISTUTILS_DISABLE_TEST_DEPENDENCY} ]]; then die "${v} is invalid for distutils-r1, please take a look @ https://wiki.gentoo.org/wiki/Project:Python/Python.eclass_conversion#DISTUTILS_SRC_TEST" fi # python.eclass::progress for v in PYTHON_BDEPEND PYTHON_MULTIPLE_ABIS PYTHON_ABI_TYPE \ PYTHON_RESTRICTED_ABIS PYTHON_TESTS_FAILURES_TOLERANT_ABIS \ PYTHON_CFFI_MODULES_GENERATION_COMMANDS do if [[ ${!v} ]]; then die "${v} is invalid for python-r1 suite" fi done } python_pkg_setup() { die "${FUNCNAME}() is invalid for python-r1 suite, please take a look @ https://wiki.gentoo.org/wiki/Project:Python/Python.eclass_conversion#pkg_setup" } python_convert_shebangs() { die "${FUNCNAME}() is invalid for python-r1 suite, please take a look @ https://wiki.gentoo.org/wiki/Project:Python/Python.eclass_conversion#python_convert_shebangs" } python_clean_py-compile_files() { die "${FUNCNAME}() is invalid for python-r1 suite" } python_clean_installation_image() { die "${FUNCNAME}() is invalid for python-r1 suite" } python_execute_function() { die "${FUNCNAME}() is invalid for python-r1 suite, please take a look @ https://wiki.gentoo.org/wiki/Project:Python/Python.eclass_conversion#python_execute_function" } python_generate_wrapper_scripts() { die "${FUNCNAME}() is invalid for python-r1 suite" } python_merge_intermediate_installation_images() { die "${FUNCNAME}() is invalid for python-r1 suite" } python_set_active_version() { die "${FUNCNAME}() is invalid for python-r1 suite, please take a look @ https://wiki.gentoo.org/wiki/Project:Python/Python.eclass_conversion#pkg_setup" } python_need_rebuild() { die "${FUNCNAME}() is invalid for python-r1 suite" } PYTHON() { die "${FUNCNAME}() is invalid for python-r1 suite, please take a look @ https://wiki.gentoo.org/wiki/Project:Python/Python.eclass_conversion#.24.28PYTHON.29.2C_.24.7BEPYTHON.7D" } python_get_implementation() { die "${FUNCNAME}() is invalid for python-r1 suite" } python_get_implementational_package() { die "${FUNCNAME}() is invalid for python-r1 suite" } python_get_libdir() { die "${FUNCNAME}() is invalid for python-r1 suite" } python_get_library() { die "${FUNCNAME}() is invalid for python-r1 suite" } python_get_version() { die "${FUNCNAME}() is invalid for python-r1 suite" } python_get_implementation_and_version() { die "${FUNCNAME}() is invalid for python-r1 suite" } python_execute_nosetests() { die "${FUNCNAME}() is invalid for python-r1 suite" } python_execute_py.test() { die "${FUNCNAME}() is invalid for python-r1 suite" } python_execute_trial() { die "${FUNCNAME}() is invalid for python-r1 suite" } python_enable_pyc() { die "${FUNCNAME}() is invalid for python-r1 suite" } python_disable_pyc() { die "${FUNCNAME}() is invalid for python-r1 suite" } python_mod_optimize() { die "${FUNCNAME}() is invalid for python-r1 suite, please take a look @ https://wiki.gentoo.org/wiki/Project:Python/Python.eclass_conversion#Python_byte-code_compilation" } python_mod_cleanup() { die "${FUNCNAME}() is invalid for python-r1 suite, please take a look @ https://wiki.gentoo.org/wiki/Project:Python/Python.eclass_conversion#Python_byte-code_compilation" } # python.eclass::progress python_abi_depend() { die "${FUNCNAME}() is invalid for python-r1 suite" } python_install_executables() { die "${FUNCNAME}() is invalid for python-r1 suite" } python_get_extension_module_suffix() { die "${FUNCNAME}() is invalid for python-r1 suite" } python_byte-compile_modules() { die "${FUNCNAME}() is invalid for python-r1 suite" } python_clean_byte-compiled_modules() { die "${FUNCNAME}() is invalid for python-r1 suite" } python_generate_cffi_modules() { die "${FUNCNAME}() is invalid for python-r1 suite" } _PYTHON_UTILS_R1=1 fi