summaryrefslogtreecommitdiff
path: root/eclass
diff options
context:
space:
mode:
Diffstat (limited to 'eclass')
-rw-r--r--eclass/Manifest.gzbin39583 -> 39576 bytes
-rw-r--r--eclass/distutils-r1.eclass112
-rw-r--r--eclass/python-utils-r1.eclass14
3 files changed, 118 insertions, 8 deletions
diff --git a/eclass/Manifest.gz b/eclass/Manifest.gz
index 0bb99df36da5..495d2358ba33 100644
--- a/eclass/Manifest.gz
+++ b/eclass/Manifest.gz
Binary files differ
diff --git a/eclass/distutils-r1.eclass b/eclass/distutils-r1.eclass
index a67122a59a33..71b80fafe1a5 100644
--- a/eclass/distutils-r1.eclass
+++ b/eclass/distutils-r1.eclass
@@ -189,6 +189,18 @@ esac
# ${DISTUTILS_DEPS}"
# @CODE
+# @ECLASS_VARIABLE: DISTUTILS_ALLOW_WHEEL_REUSE
+# @DEFAULT_UNSET
+# @USER_VARIABLE
+# @DESCRIPTION:
+# If set to a non-empty value, the eclass is allowed to reuse a wheel
+# that was built for a prior Python implementation, provided that it is
+# compatible with the current one, rather than building a new one.
+#
+# This is an optimization that can avoid the overhead of calling into
+# the build system in pure Python packages and packages using the stable
+# Python ABI.
+
if [[ -z ${_DISTUTILS_R1_ECLASS} ]]; then
_DISTUTILS_R1_ECLASS=1
@@ -267,7 +279,7 @@ _distutils_set_globals() {
;;
scikit-build-core)
bdep+='
- >=dev-python/scikit-build-core-0.8.2[${PYTHON_USEDEP}]
+ >=dev-python/scikit-build-core-0.9.4[${PYTHON_USEDEP}]
'
;;
setuptools)
@@ -1343,6 +1355,10 @@ distutils_wheel_install() {
\) -delete || die
}
+# @VARIABLE: DISTUTILS_WHEEL_PATH
+# @DESCRIPTION:
+# Path to the wheel created by distutils_pep517_install.
+
# @FUNCTION: distutils_pep517_install
# @USAGE: <root>
# @DESCRIPTION:
@@ -1350,7 +1366,8 @@ distutils_wheel_install() {
# backend and install it into <root>.
#
# This function is intended for expert use only. It does not handle
-# wrapping executables.
+# wrapping executables. The wheel path is returned
+# in DISTUTILS_WHEEL_PATH variable.
distutils_pep517_install() {
debug-print-function ${FUNCNAME} "${@}"
[[ ${#} -eq 1 ]] || die "${FUNCNAME} takes exactly one argument: root"
@@ -1440,17 +1457,21 @@ distutils_pep517_install() {
"${DISTUTILS_ARGS[@]}"
)
- # NB: we need to pass strings for boolean fields
- # https://github.com/scikit-build/scikit-build-core/issues/707
+ local -x NINJAOPTS=$(get_NINJAOPTS)
config_settings=$(
"${EPYTHON}" - "${cmake_args[@]}" <<-EOF || die
import json
+ import os
+ import shlex
import sys
+
+ ninjaopts = shlex.split(os.environ["NINJAOPTS"])
print(json.dumps({
+ "build.tool-args": ninjaopts,
"cmake.args": ";".join(sys.argv[1:]),
"cmake.build-type": "${CMAKE_BUILD_TYPE}",
- "cmake.verbose": "true",
- "install.strip": "false",
+ "cmake.verbose": True,
+ "install.strip": False,
}))
EOF
)
@@ -1523,8 +1544,19 @@ distutils_pep517_install() {
[[ -n ${wheel} ]] || die "No wheel name returned"
distutils_wheel_install "${root}" "${WHEEL_BUILD_DIR}/${wheel}"
+
+ DISTUTILS_WHEEL_PATH=${WHEEL_BUILD_DIR}/${wheel}
}
+# @VARIABLE: DISTUTILS_WHEELS
+# @DESCRIPTION:
+# An associative array of wheels created as a result
+# of distutils-r1_python_compile invocations, mapped to the source
+# directories. Note that this includes only wheels implicitly created
+# by the eclass, and not wheels created as a result of direct
+# distutils_pep517_install calls in the ebuild.
+declare -g -A DISTUTILS_WHEELS=()
+
# @FUNCTION: distutils-r1_python_compile
# @USAGE: [additional-args...]
# @DESCRIPTION:
@@ -1534,6 +1566,7 @@ distutils_pep517_install() {
#
# If DISTUTILS_USE_PEP517 is set to any other value, builds a wheel
# using the PEP517 backend and installs it into ${BUILD_DIR}/install.
+# Path to the wheel is then added to DISTUTILS_WHEELS array.
#
# In legacy mode, runs 'esetup.py build'. Any parameters passed to this
# function will be appended to setup.py invocation, i.e. passed
@@ -1568,7 +1601,34 @@ distutils-r1_python_compile() {
esac
if [[ ${DISTUTILS_USE_PEP517} ]]; then
+ if [[ ${DISTUTILS_ALLOW_WHEEL_REUSE} ]]; then
+ local whl
+ for whl in "${!DISTUTILS_WHEELS[@]}"; do
+ # use only wheels corresponding to the current directory
+ if [[ ${PWD} != ${DISTUTILS_WHEELS["${whl}"]} ]]; then
+ continue
+ fi
+
+ # 1. Use pure Python wheels only if we're not expected
+ # to build extensions. Otherwise, we may end up
+ # not building the extension at all when e.g. PyPy3
+ # is built without one.
+ #
+ # 2. For CPython, we can reuse stable ABI wheels. Note
+ # that this relies on the assumption that we're building
+ # from the oldest to the newest implementation,
+ # and the wheels are forward-compatible.
+ if [[ ( ! ${DISTUTILS_EXT} && ${whl} == *py3-none-any* ) ||
+ ( ${EPYTHON} == python* && ${whl} == *-abi3-* ) ]]
+ then
+ distutils_wheel_install "${BUILD_DIR}/install" "${whl}"
+ return
+ fi
+ done
+ fi
+
distutils_pep517_install "${BUILD_DIR}/install"
+ DISTUTILS_WHEELS+=( "${DISTUTILS_WHEEL_PATH}" "${PWD}" )
fi
}
@@ -2004,6 +2064,44 @@ distutils-r1_src_configure() {
return ${ret}
}
+# @FUNCTION: _distutils-r1_compare_installed_files
+# @INTERNAL
+# @DESCRIPTION:
+# Verify the the match between files installed between this and previous
+# implementation.
+_distutils-r1_compare_installed_files() {
+ debug-print-function ${FUNCNAME} "${@}"
+
+ # QA check requires diff(1).
+ if ! type -P diff &>/dev/null; then
+ return
+ fi
+
+ # Perform the check only if at least one potentially reusable wheel
+ # has been produced. Nonpure packages (e.g. NumPy) may install
+ # interpreter configuration details into sitedir.
+ if [[ ${!DISTUTILS_WHEELS[*]} != *-none-any.whl* &&
+ ${!DISTUTILS_WHEELS[*]} != *-abi3-*.whl ]]; then
+ return
+ fi
+
+ local sitedir=${BUILD_DIR}/install$(python_get_sitedir)
+ if [[ -n ${_DISTUTILS_PREVIOUS_SITE} ]]; then
+ diff -dur \
+ --exclude=__pycache__ \
+ --exclude='*.dist-info' \
+ --exclude="*$(get_modname)" \
+ "${_DISTUTILS_PREVIOUS_SITE}" "${sitedir}"
+ if [[ ${?} -ne 0 ]]; then
+ eqawarn "Package creating at least one pure Python wheel installs different"
+ eqawarn "Python files between implementations. See diff in build log, above"
+ eqawarn "this message."
+ fi
+ fi
+
+ _DISTUTILS_PREVIOUS_SITE=${sitedir}
+}
+
# @FUNCTION: _distutils-r1_post_python_compile
# @INTERNAL
# @DESCRIPTION:
@@ -2038,6 +2136,8 @@ _distutils-r1_post_python_compile() {
find "${bindir}" -type f -exec sed -i \
-e "1s@^#!\(${EPREFIX}/usr/bin/\(python\|pypy\)\)@#!${root}\1@" \
{} + || die
+
+ _distutils-r1_compare_installed_files
fi
}
diff --git a/eclass/python-utils-r1.eclass b/eclass/python-utils-r1.eclass
index 275ac3a96523..c47565fa1db2 100644
--- a/eclass/python-utils-r1.eclass
+++ b/eclass/python-utils-r1.eclass
@@ -1321,6 +1321,15 @@ _python_check_occluded_packages() {
# Specifies the number of jobs for parallel (pytest-xdist) test runs.
# When unset, defaults to -j from MAKEOPTS, or the current nproc.
+# @ECLASS_VARIABLE: EPYTEST_FLAGS
+# @USER_VARIABLE
+# @DEFAULT_UNSET
+# @DESCRIPTION:
+# Additional flags to pass to pytest. This is intended to be set
+# in the environment when debugging packages (options such as -x or -s
+# are useful here), rather than globally. It must not be set
+# in ebuilds.
+
# @FUNCTION: epytest
# @USAGE: [<args>...]
# @DESCRIPTION:
@@ -1432,10 +1441,10 @@ epytest() {
for x in "${EPYTEST_IGNORE[@]}"; do
args+=( --ignore "${x}" )
done
- set -- "${EPYTHON}" -m pytest "${args[@]}" "${@}"
+ set -- "${EPYTHON}" -m pytest "${args[@]}" "${@}" ${EPYTEST_FLAGS}
echo "${@}" >&2
- "${@}" || die -n "pytest failed with ${EPYTHON}"
+ "${@}"
local ret=${?}
# remove common temporary directories left over by pytest plugins
@@ -1446,6 +1455,7 @@ epytest() {
find "${BUILD_DIR}" -name '*-pytest-*.pyc' -delete || die
fi
+ [[ ${ret} -ne 0 ]] && die -n "pytest failed with ${EPYTHON}"
return ${ret}
}