python-any-r1.eclass (10656B)
1 # Copyright 1999-2022 Gentoo Authors 2 # Distributed under the terms of the GNU General Public License v2 3 4 # @ECLASS: python-any-r1.eclass 5 # @MAINTAINER: 6 # Python team <python@gentoo.org> 7 # @AUTHOR: 8 # Author: Michał Górny <mgorny@gentoo.org> 9 # Based on work of: Krzysztof Pawlik <nelchael@gentoo.org> 10 # @SUPPORTED_EAPIS: 6 7 8 11 # @PROVIDES: python-utils-r1 12 # @BLURB: An eclass for packages having build-time dependency on Python. 13 # @DESCRIPTION: 14 # A minimal eclass for packages which need any Python interpreter 15 # installed without a need for explicit choice and invariability. 16 # This usually involves packages requiring Python at build-time 17 # but having no other relevance to it. 18 # 19 # This eclass provides a minimal PYTHON_DEPS variable with a dependency 20 # string on any of the supported Python implementations. It also exports 21 # pkg_setup() which finds the best supported implementation and sets it 22 # as the active one. 23 # 24 # Optionally, you can define a python_check_deps() function. It will 25 # be called by the eclass with EPYTHON set to each matching Python 26 # implementation and it is expected to check whether the implementation 27 # fulfills the package requirements. You can use the locally exported 28 # PYTHON_USEDEP or PYTHON_SINGLE_USEDEP to check USE-dependencies 29 # of relevant packages. It should return a true value (0) if the Python 30 # implementation fulfills the requirements, a false value (non-zero) 31 # otherwise. 32 # 33 # Please note that python-any-r1 will always inherit python-utils-r1 34 # as well. Thus, all the functions defined there can be used in the 35 # packages using python-any-r1, and there is no need ever to inherit 36 # both. 37 # 38 # For more information, please see the Python Guide: 39 # https://projects.gentoo.org/python/guide/ 40 41 case "${EAPI:-0}" in 42 [0-5]) die "Unsupported EAPI=${EAPI:-0} (too old) for ${ECLASS}" ;; 43 [6-8]) ;; 44 *) die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}" ;; 45 esac 46 47 if [[ ! ${_PYTHON_ANY_R1} ]]; then 48 49 if [[ ${_PYTHON_R1} ]]; then 50 die 'python-any-r1.eclass can not be used with python-r1.eclass.' 51 elif [[ ${_PYTHON_SINGLE_R1} ]]; then 52 die 'python-any-r1.eclass can not be used with python-single-r1.eclass.' 53 fi 54 55 inherit python-utils-r1 56 57 fi 58 59 EXPORT_FUNCTIONS pkg_setup 60 61 # @ECLASS_VARIABLE: PYTHON_COMPAT 62 # @REQUIRED 63 # @DESCRIPTION: 64 # This variable contains a list of Python implementations the package 65 # supports. It must be set before the `inherit' call. It has to be 66 # an array. 67 # 68 # Example: 69 # @CODE 70 # PYTHON_COMPAT=( python{2_5,2_6,2_7} ) 71 # @CODE 72 73 # @ECLASS_VARIABLE: PYTHON_COMPAT_OVERRIDE 74 # @USER_VARIABLE 75 # @DEFAULT_UNSET 76 # @DESCRIPTION: 77 # This variable can be used when working with ebuilds to override 78 # the in-ebuild PYTHON_COMPAT. It is a string naming the implementation 79 # which will be used to build the package. It needs to be specified 80 # in the calling environment, and not in ebuilds. 81 # 82 # It should be noted that in order to preserve metadata immutability, 83 # PYTHON_COMPAT_OVERRIDE does not affect dependencies. The value of 84 # EPYTHON and eselect-python preferences are ignored. Dependencies need 85 # to be satisfied manually. 86 # 87 # Example: 88 # @CODE 89 # PYTHON_COMPAT_OVERRIDE='pypy' emerge -1v dev-python/bar 90 # @CODE 91 92 # @ECLASS_VARIABLE: PYTHON_REQ_USE 93 # @DEFAULT_UNSET 94 # @DESCRIPTION: 95 # The list of USEflags required to be enabled on the Python 96 # implementations, formed as a USE-dependency string. It should be valid 97 # for all implementations in PYTHON_COMPAT, so it may be necessary to 98 # use USE defaults. 99 # 100 # Example: 101 # @CODE 102 # PYTHON_REQ_USE="gdbm,ncurses(-)?" 103 # @CODE 104 # 105 # It will cause the Python dependencies to look like: 106 # @CODE 107 # || ( dev-lang/python:X.Y[gdbm,ncurses(-)?] ... ) 108 # @CODE 109 110 # @ECLASS_VARIABLE: PYTHON_DEPS 111 # @OUTPUT_VARIABLE 112 # @DESCRIPTION: 113 # This is an eclass-generated Python dependency string for all 114 # implementations listed in PYTHON_COMPAT. 115 # 116 # Any of the supported interpreters will satisfy the dependency. 117 # 118 # Example use: 119 # @CODE 120 # BDEPEND="${PYTHON_DEPS}" 121 # @CODE 122 # 123 # Example value: 124 # @CODE 125 # || ( dev-lang/python:2.7[gdbm] 126 # dev-lang/python:2.6[gdbm] ) 127 # @CODE 128 129 # @ECLASS_VARIABLE: PYTHON_USEDEP 130 # @OUTPUT_VARIABLE 131 # @DESCRIPTION: 132 # An eclass-generated USE-dependency string for the currently tested 133 # implementation. It is set locally for python_check_deps() call. 134 # 135 # The generated USE-flag list is compatible with packages using 136 # python-r1 eclass. For python-single-r1 dependencies, 137 # use PYTHON_SINGLE_USEDEP. 138 # 139 # Example use: 140 # @CODE 141 # python_check_deps() { 142 # python_has_version "dev-python/foo[${PYTHON_USEDEP}]" 143 # } 144 # @CODE 145 # 146 # Example value: 147 # @CODE 148 # python_targets_python3_7(-) 149 # @CODE 150 151 # @ECLASS_VARIABLE: PYTHON_SINGLE_USEDEP 152 # @OUTPUT_VARIABLE 153 # @DESCRIPTION: 154 # An eclass-generated USE-dependency string for the currently tested 155 # implementation. It is set locally for python_check_deps() call. 156 # 157 # The generated USE-flag list is compatible with packages using 158 # python-single-r1 eclass. For python-r1 dependencies, 159 # use PYTHON_USEDEP. 160 # 161 # Example use: 162 # @CODE 163 # python_check_deps() { 164 # python_has_version "dev-python/bar[${PYTHON_SINGLE_USEDEP}]" 165 # } 166 # @CODE 167 # 168 # Example value: 169 # @CODE 170 # python_single_target_python3_7(-) 171 # @CODE 172 173 _python_any_set_globals() { 174 local usestr deps i PYTHON_PKG_DEP 175 [[ ${PYTHON_REQ_USE} ]] && usestr="[${PYTHON_REQ_USE}]" 176 177 _PYTHON_ALLOW_PY27=1 \ 178 _python_set_impls 179 180 for i in "${_PYTHON_SUPPORTED_IMPLS[@]}"; do 181 _python_export "${i}" PYTHON_PKG_DEP 182 183 # note: need to strip '=' slot operator for || deps 184 deps="${PYTHON_PKG_DEP/:0=/:0} ${deps}" 185 done 186 deps="|| ( ${deps})" 187 188 if [[ ${PYTHON_DEPS+1} ]]; then 189 if [[ ${PYTHON_DEPS} != "${deps}" ]]; then 190 eerror "PYTHON_DEPS have changed between inherits (PYTHON_REQ_USE?)!" 191 eerror "Before: ${PYTHON_DEPS}" 192 eerror "Now : ${deps}" 193 die "PYTHON_DEPS integrity check failed" 194 fi 195 else 196 PYTHON_DEPS=${deps} 197 readonly PYTHON_DEPS 198 fi 199 200 if [[ ! ${PYTHON_REQUIRED_USE+1} ]]; then 201 # fake var to catch mistaken usage 202 PYTHON_REQUIRED_USE='I-DO-NOT-EXIST-IN-PYTHON-ANY-R1' 203 readonly PYTHON_REQUIRED_USE 204 fi 205 } 206 _python_any_set_globals 207 unset -f _python_any_set_globals 208 209 if [[ ! ${_PYTHON_ANY_R1} ]]; then 210 211 # @FUNCTION: python_gen_any_dep 212 # @USAGE: <dependency-block> 213 # @DESCRIPTION: 214 # Generate an any-of dependency that enforces a version match between 215 # the Python interpreter and Python packages. <dependency-block> needs 216 # to list one or more dependencies with verbatim '${PYTHON_USEDEP}' 217 # or '${PYTHON_SINGLE_USEDEP}' references (quoted!) that will get 218 # expanded inside the function. 219 # 220 # This should be used along with an appropriate python_check_deps() 221 # that checks which of the any-of blocks were matched. 222 # 223 # Example use: 224 # @CODE 225 # BDEPEND="$(python_gen_any_dep ' 226 # dev-python/foo[${PYTHON_SINGLE_USEDEP}] 227 # || ( dev-python/bar[${PYTHON_USEDEP}] 228 # dev-python/baz[${PYTHON_USEDEP}] )')" 229 # 230 # python_check_deps() { 231 # python_has_version "dev-python/foo[${PYTHON_SINGLE_USEDEP}]" \ 232 # && { python_has_version "dev-python/bar[${PYTHON_USEDEP}]" \ 233 # || python_has_version "dev-python/baz[${PYTHON_USEDEP}]"; } 234 # } 235 # @CODE 236 # 237 # Example value: 238 # @CODE 239 # || ( 240 # ( 241 # dev-lang/python:3.7 242 # dev-python/foo[python_single_target_python3_7(-)] 243 # || ( dev-python/bar[python_targets_python3_7(-) 244 # dev-python/baz[python_targets_python3_7(-) ) 245 # ) 246 # ( 247 # dev-lang/python:3.8 248 # dev-python/foo[python_single_target_python3_8(-)] 249 # || ( dev-python/bar[python_targets_python3_8(-)] 250 # dev-python/baz[python_targets_python3_8(-)] ) 251 # ) 252 # ) 253 # @CODE 254 python_gen_any_dep() { 255 debug-print-function ${FUNCNAME} "${@}" 256 257 local depstr=${1} 258 [[ ${depstr} ]] || die "No dependency string provided" 259 260 local i PYTHON_PKG_DEP out= 261 for i in "${_PYTHON_SUPPORTED_IMPLS[@]}"; do 262 local PYTHON_USEDEP="python_targets_${i}(-)" 263 local PYTHON_SINGLE_USEDEP="python_single_target_${i}(-)" 264 _python_export "${i}" PYTHON_PKG_DEP 265 266 local i_depstr=${depstr//\$\{PYTHON_USEDEP\}/${PYTHON_USEDEP}} 267 i_depstr=${i_depstr//\$\{PYTHON_SINGLE_USEDEP\}/${PYTHON_SINGLE_USEDEP}} 268 # note: need to strip '=' slot operator for || deps 269 out="( ${PYTHON_PKG_DEP%=} ${i_depstr} ) ${out}" 270 done 271 echo "|| ( ${out})" 272 } 273 274 # @FUNCTION: python_setup 275 # @DESCRIPTION: 276 # Determine what the best installed (and supported) Python 277 # implementation is, and set the Python build environment up for it. 278 # 279 # This function will call python_check_deps() if defined. 280 python_setup() { 281 debug-print-function ${FUNCNAME} "${@}" 282 283 # support developer override 284 if [[ ${PYTHON_COMPAT_OVERRIDE} ]]; then 285 local impls=( ${PYTHON_COMPAT_OVERRIDE} ) 286 [[ ${#impls[@]} -eq 1 ]] || die "PYTHON_COMPAT_OVERRIDE must name exactly one implementation for python-any-r1" 287 288 ewarn "WARNING: PYTHON_COMPAT_OVERRIDE in effect. The following Python" 289 ewarn "implementation will be used:" 290 ewarn 291 ewarn " ${PYTHON_COMPAT_OVERRIDE}" 292 ewarn 293 ewarn "Dependencies won't be satisfied, and EPYTHON/eselect-python will be ignored." 294 295 _python_export "${impls[0]}" EPYTHON PYTHON 296 _python_wrapper_setup 297 einfo "Using ${EPYTHON} to build (via PYTHON_COMPAT_OVERRIDE)" 298 return 299 fi 300 301 # first, try ${EPYTHON}... maybe it's good enough for us. 302 local epython_impl=${EPYTHON/./_} 303 if [[ ${epython_impl} ]]; then 304 if ! has "${epython_impl}" "${_PYTHON_SUPPORTED_IMPLS[@]}"; then 305 if ! has "${epython_impl}" "${_PYTHON_ALL_IMPLS[@]}"; then 306 ewarn "Invalid EPYTHON: ${EPYTHON}" 307 else 308 einfo "EPYTHON (${EPYTHON}) not supported by the package" 309 fi 310 elif _python_run_check_deps "${epython_impl}"; then 311 _python_export EPYTHON PYTHON 312 _python_wrapper_setup 313 einfo "Using ${EPYTHON} to build (via EPYTHON)" 314 return 315 fi 316 fi 317 318 # fallback to the best installed impl. 319 # (reverse iteration over _PYTHON_SUPPORTED_IMPLS) 320 local i 321 for (( i = ${#_PYTHON_SUPPORTED_IMPLS[@]} - 1; i >= 0; i-- )); do 322 local impl=${_PYTHON_SUPPORTED_IMPLS[i]} 323 # avoid checking EPYTHON twice 324 [[ ${impl} == ${epython_impl} ]] && continue 325 _python_export "${impl}" EPYTHON PYTHON 326 if _python_run_check_deps "${impl}"; then 327 _python_wrapper_setup 328 einfo "Using ${EPYTHON} to build (via PYTHON_COMPAT iteration)" 329 return 330 fi 331 done 332 333 eerror "No Python implementation found for the build. This is usually" 334 eerror "a bug in the ebuild. Please report it to bugs.gentoo.org" 335 eerror "along with the build log." 336 echo 337 die "No supported Python implementation installed." 338 } 339 340 # @FUNCTION: python-any-r1_pkg_setup 341 # @DESCRIPTION: 342 # Runs python_setup during from-source installs. 343 # 344 # In a binary package installs is a no-op. If you need Python in pkg_* 345 # phases of a binary package, call python_setup directly. 346 python-any-r1_pkg_setup() { 347 debug-print-function ${FUNCNAME} "${@}" 348 349 [[ ${MERGE_TYPE} != binary ]] && python_setup 350 } 351 352 _PYTHON_ANY_R1=1 353 fi