|
| 1 | +#!/usr/bin/env bash |
| 2 | +# Build numpy wheels for preview CPython versions (e.g. 3.15 / 3.15t) inside a |
| 3 | +# manylinux builder image and upload them to download.pytorch.org. |
| 4 | +# |
| 5 | +# Why this exists: |
| 6 | +# numpy does not yet publish cp315 wheels on PyPI. When torch preview-Python |
| 7 | +# wheels are built or smoke-tested, pip tries to resolve numpy and falls back |
| 8 | +# to building it from an sdist, which fails in the constrained build/test |
| 9 | +# environment. Pre-building numpy here and hosting it on the pytorch index |
| 10 | +# lets those installs resolve a real wheel instead. |
| 11 | +# |
| 12 | +# This must run inside a pytorch manylinux builder image that ships the target |
| 13 | +# interpreters under /opt/python (e.g. pytorch/manylinux2_28-builder:cpu). |
| 14 | +# |
| 15 | +# Required env: |
| 16 | +# ARCH x86_64 | aarch64 |
| 17 | +# Optional env: |
| 18 | +# NUMPY_VERSION numpy version to build (default: 2.5.1) |
| 19 | +# PYTHON_VERSIONS space separated (default: "3.15 3.15t") |
| 20 | +# CHANNELS download.pytorch.org channels (default: "nightly test") |
| 21 | +# MANYWHEEL_VERSION manylinux platform tag version (default: 2_28) |
| 22 | +# DRY_RUN "true" builds but does not upload (default: true) |
| 23 | + |
| 24 | +set -euo pipefail |
| 25 | + |
| 26 | +NUMPY_VERSION="${NUMPY_VERSION:-2.5.1}" |
| 27 | +PYTHON_VERSIONS="${PYTHON_VERSIONS:-3.15 3.15t}" |
| 28 | +CHANNELS="${CHANNELS:-nightly test}" |
| 29 | +MANYWHEEL_VERSION="${MANYWHEEL_VERSION:-2_28}" |
| 30 | +DRY_RUN="${DRY_RUN:-true}" |
| 31 | +ARCH="${ARCH:?ARCH must be set (x86_64|aarch64)}" |
| 32 | + |
| 33 | +PLAT="manylinux_${MANYWHEEL_VERSION}_${ARCH}" |
| 34 | +BUILD_DIR="/tmp/numpy-preview-build" |
| 35 | +WHEELHOUSE="${BUILD_DIR}/wheelhouse" |
| 36 | + |
| 37 | +rm -rf "${BUILD_DIR}" |
| 38 | +mkdir -p "${WHEELHOUSE}" |
| 39 | + |
| 40 | +# 3.15 -> cp315 ; 3.15t -> cp315t |
| 41 | +cp_tag() { |
| 42 | + local ver="$1" suffix="" |
| 43 | + if [[ "${ver}" == *t ]]; then |
| 44 | + suffix="t" |
| 45 | + ver="${ver%t}" |
| 46 | + fi |
| 47 | + echo "cp${ver//./}${suffix}" |
| 48 | +} |
| 49 | + |
| 50 | +# cp315 -> /opt/python/cp315-cp315/bin/python |
| 51 | +py_bin() { |
| 52 | + local tag |
| 53 | + tag="$(cp_tag "$1")" |
| 54 | + echo "/opt/python/${tag}-${tag}/bin/python" |
| 55 | +} |
| 56 | + |
| 57 | +echo "==> numpy==${NUMPY_VERSION} arch=${ARCH} plat=${PLAT}" |
| 58 | +echo "==> python versions: ${PYTHON_VERSIONS}" |
| 59 | +echo "==> channels: ${CHANNELS} dry_run=${DRY_RUN}" |
| 60 | + |
| 61 | +for pyver in ${PYTHON_VERSIONS}; do |
| 62 | + tag="$(cp_tag "${pyver}")" |
| 63 | + py="$(py_bin "${pyver}")" |
| 64 | + |
| 65 | + if [[ ! -x "${py}" ]]; then |
| 66 | + echo "::error::Interpreter for ${pyver} not found at ${py}" |
| 67 | + exit 1 |
| 68 | + fi |
| 69 | + |
| 70 | + echo "==> Building numpy==${NUMPY_VERSION} for ${tag} (${py})" |
| 71 | + work="${BUILD_DIR}/${tag}" |
| 72 | + mkdir -p "${work}" |
| 73 | + |
| 74 | + "${py}" -m pip install --upgrade pip auditwheel |
| 75 | + |
| 76 | + # --no-binary forces a source build against this exact interpreter so the |
| 77 | + # produced extension modules target the preview CPython ABI. |
| 78 | + "${py}" -m pip wheel --no-deps --no-binary numpy \ |
| 79 | + --wheel-dir "${work}" "numpy==${NUMPY_VERSION}" |
| 80 | + |
| 81 | + # numpy's source build emits a linux_<arch> tagged wheel that bundles OpenBLAS |
| 82 | + # but references libgfortran/libquadmath from the toolchain; auditwheel vendors |
| 83 | + # those in and rewrites the platform tag to a compliant manylinux tag. |
| 84 | + for whl in "${work}"/numpy-*.whl; do |
| 85 | + echo " auditwheel repair ${whl##*/} -> ${PLAT}" |
| 86 | + "${py}" -m auditwheel repair \ |
| 87 | + --plat "${PLAT}" \ |
| 88 | + --wheel-dir "${WHEELHOUSE}" \ |
| 89 | + "${whl}" |
| 90 | + done |
| 91 | +done |
| 92 | + |
| 93 | +echo "==> Built wheels:" |
| 94 | +ls -la "${WHEELHOUSE}" |
| 95 | + |
| 96 | +if [[ "${DRY_RUN}" == "true" ]]; then |
| 97 | + echo "==> DRY RUN: skipping upload to download.pytorch.org" |
| 98 | + exit 0 |
| 99 | +fi |
| 100 | + |
| 101 | +# Upload to s3://pytorch/whl/<channel>/ with the same public-read ACL and |
| 102 | +# checksum metadata the binary upload workflow uses for torch wheels. |
| 103 | +for channel in ${CHANNELS}; do |
| 104 | + dest="s3://pytorch/whl/${channel}/" |
| 105 | + echo "==> Uploading to ${dest}" |
| 106 | + for pkg in "${WHEELHOUSE}"/numpy-*.whl; do |
| 107 | + shm_id="$(sha256sum "${pkg}" | awk '{print $1}')" |
| 108 | + aws s3 cp "${pkg}" "${dest}" \ |
| 109 | + --acl public-read \ |
| 110 | + --metadata "checksum-sha256=${shm_id}" |
| 111 | + done |
| 112 | +done |
| 113 | + |
| 114 | +echo "==> Done. Run the 'Update S3 HTML indices' workflow (or wait for the" |
| 115 | +echo " hourly cron) to publish numpy in the whl/<channel> package indices." |
0 commit comments