diff --git a/.github/workflows/build-wheels-platforms.yml b/.github/workflows/build-wheels-platforms.yml index ce97ba8..cdc053e 100644 --- a/.github/workflows/build-wheels-platforms.yml +++ b/.github/workflows/build-wheels-platforms.yml @@ -28,6 +28,7 @@ jobs: - macOS ARM - Linux ARM64 - Linux ARMv7 + - Linux ARMv7 Legacy include: - os: Windows runner: windows-latest @@ -47,11 +48,14 @@ jobs: - os: Linux ARMv7 runner: ubuntu-latest arch: linux-armv7 + - os: Linux ARMv7 Legacy + runner: ubuntu-latest + arch: linux-armv7-legacy python-version: ['${{ needs.get-supported-versions.outputs.oldest_supported_python }}'] steps: - name: Set up QEMU for ARMv7 - if: matrix.os == 'Linux ARMv7' + if: matrix.os == 'Linux ARMv7' || matrix.os == 'Linux ARMv7 Legacy' uses: docker/setup-qemu-action@v3 with: platforms: linux/arm/v7 @@ -79,20 +83,20 @@ jobs: - name: Setup Python # Skip setting python on ARM because of missing compatibility: https://github.com/actions/setup-python/issues/108 - if: matrix.os != 'Linux ARMv7' + if: matrix.os != 'Linux ARMv7' && matrix.os != 'Linux ARMv7 Legacy' uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install build dependencies - if: matrix.os != 'Linux ARMv7' + if: matrix.os != 'Linux ARMv7' && matrix.os != 'Linux ARMv7 Legacy' run: | python -m pip install --upgrade pip python -m pip install -r build_requirements.txt - name: Get Tools versions - if: matrix.os != 'Linux ARMv7' + if: matrix.os != 'Linux ARMv7' && matrix.os != 'Linux ARMv7 Legacy' run: | python --version pip show pip setuptools @@ -136,8 +140,33 @@ jobs: python build_wheels.py " + - name: Build wheels for IDF - ARMv7 Legacy (in Docker) + # Build on Bullseye (glibc 2.31) for compatibility with older systems + # Note: Buster has Python 3.7 which is too old for our dependencies + if: matrix.os == 'Linux ARMv7 Legacy' + run: | + docker run --rm --platform linux/arm/v7 \ + -v $(pwd):/work \ + -w /work \ + -e MIN_IDF_MAJOR_VERSION=${{ needs.get-supported-versions.outputs.min_idf_major_version }} \ + -e MIN_IDF_MINOR_VERSION=${{ needs.get-supported-versions.outputs.min_idf_minor_version }} \ + -e GH_TOKEN="${GH_TOKEN}" \ + -e PIP_NO_CACHE_DIR=1 \ + python:${{ matrix.python-version }}-bullseye \ + bash -c " + set -e + python --version + # Install pip packages without cache to reduce memory usage + python -m pip install --no-cache-dir --upgrade pip + python -m pip install --no-cache-dir -r build_requirements.txt + bash os_dependencies/linux_arm.sh + # Source Rust environment after installation + . \$HOME/.cargo/env + python build_wheels.py + " + - name: Build wheels for IDF - Linux/macOS - if: matrix.os != 'Windows' && matrix.os != 'Linux ARMv7' + if: matrix.os != 'Windows' && matrix.os != 'Linux ARMv7' && matrix.os != 'Linux ARMv7 Legacy' run: | # Set ARCHFLAGS for macOS to prevent universal2 wheels if [ "${{ matrix.os }}" = "macOS ARM" ]; then diff --git a/.github/workflows/build-wheels-python-dependent.yml b/.github/workflows/build-wheels-python-dependent.yml index a207680..e8cfbc0 100644 --- a/.github/workflows/build-wheels-python-dependent.yml +++ b/.github/workflows/build-wheels-python-dependent.yml @@ -28,6 +28,7 @@ jobs: - macOS ARM - Linux ARM64 - Linux ARMv7 + - Linux ARMv7 Legacy include: - os: Windows runner: windows-latest @@ -47,6 +48,9 @@ jobs: - os: Linux ARMv7 runner: ubuntu-latest arch: linux-armv7 + - os: Linux ARMv7 Legacy + runner: ubuntu-latest + arch: linux-armv7-legacy python-version: ${{ fromJson(inputs.supported_python_versions) }} exclude: # Exclude oldest supported Python since it's already built in the platform builds @@ -62,10 +66,15 @@ jobs: os: Linux ARM64 - python-version: ${{ inputs.oldest_supported_python }} os: Linux ARMv7 + - python-version: ${{ inputs.oldest_supported_python }} + os: Linux ARMv7 Legacy + # Python 3.14 doesn't have bullseye images for ARM + - python-version: '3.14' + os: Linux ARMv7 Legacy steps: - name: Set up QEMU for ARMv7 - if: matrix.os == 'Linux ARMv7' + if: matrix.os == 'Linux ARMv7' || matrix.os == 'Linux ARMv7 Legacy' uses: docker/setup-qemu-action@v3 with: platforms: linux/arm/v7 @@ -75,19 +84,19 @@ jobs: - name: Setup Python # Skip setting python on ARMv7 (runs in Docker) - if: matrix.os != 'Linux ARMv7' + if: matrix.os != 'Linux ARMv7' && matrix.os != 'Linux ARMv7 Legacy' uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Get Python version - if: matrix.os != 'Linux ARMv7' + if: matrix.os != 'Linux ARMv7' && matrix.os != 'Linux ARMv7 Legacy' run: | python --version python -m pip install --upgrade pip - name: Install dependencies - if: matrix.os != 'Linux ARMv7' + if: matrix.os != 'Linux ARMv7' && matrix.os != 'Linux ARMv7 Legacy' run: python -m pip install -r build_requirements.txt - name: Install additional OS dependencies - Ubuntu @@ -138,8 +147,31 @@ jobs: python build_wheels_from_file.py dependent_requirements_${{ matrix.arch }} " + - name: Build Python dependent wheels - ARMv7 Legacy (in Docker) + # Build on Bullseye (glibc 2.31) for compatibility with older systems + if: matrix.os == 'Linux ARMv7 Legacy' + run: | + docker run --rm --platform linux/arm/v7 \ + -v $(pwd):/work \ + -w /work \ + -e PYO3_USE_ABI3_FORWARD_COMPATIBILITY=1 \ + -e GH_TOKEN="${GH_TOKEN}" \ + -e PIP_NO_CACHE_DIR=1 \ + python:${{ matrix.python-version }}-bullseye \ + bash -c " + set -e + python --version + # Install pip packages without cache to reduce memory usage + python -m pip install --no-cache-dir --upgrade pip + python -m pip install --no-cache-dir -r build_requirements.txt + bash os_dependencies/linux_arm.sh + # Source Rust environment after installation + . \$HOME/.cargo/env + python build_wheels_from_file.py dependent_requirements_${{ matrix.arch }} + " + - name: Build Python dependent wheels - Linux/macOS - if: matrix.os != 'Windows' && matrix.os != 'Linux ARMv7' + if: matrix.os != 'Windows' && matrix.os != 'Linux ARMv7' && matrix.os != 'Linux ARMv7 Legacy' run: | # Set ARCHFLAGS for macOS to prevent universal2 wheels if [ "${{ matrix.os }}" = "macOS ARM" ]; then diff --git a/.github/workflows/wheels-repair.yml b/.github/workflows/wheels-repair.yml index 0853022..9944fcc 100644 --- a/.github/workflows/wheels-repair.yml +++ b/.github/workflows/wheels-repair.yml @@ -23,6 +23,7 @@ jobs: - Linux x86_64 - Linux ARM64 - Linux ARMv7 + - Linux ARMv7 Legacy include: - platform: Windows runner: windows-latest @@ -58,6 +59,15 @@ jobs: qemu_platform: arm docker_platform: linux/arm/v7 arch: linux-armv7 + - platform: Linux ARMv7 Legacy + runner: ubuntu-latest + tool: auditwheel + manylinux_platform: idf-python-wheels-armv7l-legacy + docker_image: ghcr.io/espressif/github-esp-dockerfiles/idf-python-wheels-armv7l-legacy:v1 + setup_qemu: true + qemu_platform: arm + docker_platform: linux/arm/v7 + arch: linux-armv7-legacy steps: - name: Checkout repository @@ -66,7 +76,9 @@ jobs: - name: Download wheel artifacts uses: actions/download-artifact@v4 with: - pattern: wheels-download-directory-* + # Download only artifacts for this specific architecture to avoid mixing wheels + # (especially important for ARMv7 vs ARMv7 Legacy which produce same-named wheels) + pattern: wheels-download-directory-${{ matrix.arch }}-* path: ./downloaded_wheels merge-multiple: true @@ -145,6 +157,21 @@ jobs: python3 repair_wheels.py " + - name: Repair Linux ARMv7 Legacy wheels in manylinux container + if: matrix.platform == 'Linux ARMv7 Legacy' + run: | + docker run --rm \ + --platform ${{ matrix.docker_platform }} \ + -v $(pwd):/work \ + -w /work \ + ${{ matrix.docker_image }} \ + bash -c " + bash os_dependencies/linux_arm.sh + python3 -m pip install --upgrade pip + python3 -m pip install -r build_requirements.txt + python3 repair_wheels.py + " + - name: Re-upload artifacts with repaired wheels uses: actions/upload-artifact@v4 with: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index fa8ac3d..ad3c83c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -23,20 +23,21 @@ repos: - id: check-yaml - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.13.3 + rev: v0.14.10 hooks: - id: ruff-check args: [--fix, --exit-non-zero-on-fix] - id: ruff-format - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.18.2 + # pre-commit autoupdate --skip mypy (newer versions require Python 3.9+) + rev: v1.18.2 # frozen: minimum Python version compatibility hooks: - id: mypy additional_dependencies: ['types-all-latest'] - repo: https://github.com/espressif/conventional-precommit-linter - rev: v1.10.0 + rev: v1.11.0 hooks: - id: conventional-precommit-linter stages: [commit-msg] diff --git a/README.md b/README.md index d6eb67f..78686bd 100644 --- a/README.md +++ b/README.md @@ -141,4 +141,7 @@ The main file is `build-wheels-platforms.yml` which is scheduled to run periodic > Python dependent wheels are wheels which depend on the [CPython’s Application Binary Interface (ABI)](https://docs.python.org/3/c-api/stable.html). These are checked based on the [wheel filename format](https://peps.python.org/pep-0491/#file-format) where the `abi tag` is checked for `cp`. Such wheels need to be build also for all supported Python versions, not only for the minimum Python version supported by [ESP-IDF]. +## Docker files +Docker files are here just as a copy for better understanding in the scope of one repository. Actual Docker files are in its own repository where there are build and published from. https://github.com/espressif/github-esp-dockerfiles + [ESP-IDF]: https://github.com/espressif/esp-idf diff --git a/docker/Dockerfile.manylinux_armv7l_legacy b/docker/Dockerfile.manylinux_armv7l_legacy new file mode 100644 index 0000000..9da6f92 --- /dev/null +++ b/docker/Dockerfile.manylinux_armv7l_legacy @@ -0,0 +1,96 @@ +# Minimal manylinux-compatible Docker image for ARMv7l (32-bit ARM) +# Based on Debian Bullseye for older glibc compatibility (2.31) +# Use this for compatibility with older systems (e.g., older Raspberry Pi OS) + +FROM arm32v7/debian:bullseye + +LABEL maintainer="Espressif Systems" +LABEL description="Minimal manylinux-compatible environment for building Python wheels on ARMv7l (legacy glibc 2.31)" + +# Set environment variables +ENV DEBIAN_FRONTEND=noninteractive \ + LC_ALL=C.UTF-8 \ + LANG=C.UTF-8 + +# Install build dependencies and Python versions +RUN apt-get update && apt-get install -y \ + # Build essentials + build-essential \ + gcc \ + g++ \ + make \ + cmake \ + git \ + wget \ + curl \ + ca-certificates \ + patchelf \ + # Python build dependencies + libssl-dev \ + libffi-dev \ + libbz2-dev \ + libreadline-dev \ + libsqlite3-dev \ + libncurses5-dev \ + libncursesw5-dev \ + libgdbm-dev \ + liblzma-dev \ + tk-dev \ + zlib1g-dev \ + # Additional libraries commonly needed for wheels + libxml2-dev \ + libxslt1-dev \ + libyaml-dev \ + libglib2.0-dev \ + # PyGObject dependencies + libcairo2-dev \ + pkg-config \ + libgirepository1.0-dev \ + # dbus-python dependencies + libdbus-1-dev \ + libdbus-glib-1-dev \ + # Pillow dependencies (include both -dev and runtime libs for auditwheel) + libjpeg-dev \ + libpng-dev \ + libtiff-dev \ + libtiff5 \ + libfreetype6-dev \ + liblcms2-dev \ + libwebp-dev \ + libopenjp2-7-dev \ + libfribidi-dev \ + libharfbuzz-dev \ + libxcb1-dev \ + libxau-dev \ + brotli \ + libbrotli-dev \ + # Python from Debian repos (Bullseye provides 3.9) + python3 \ + python3-dev \ + python3-venv \ + python3-pip \ + && rm -rf /var/lib/apt/lists/* + +# Install pip and wheel tools +RUN python3 -m pip install --no-cache-dir --upgrade \ + pip \ + setuptools \ + wheel \ + auditwheel + +# Set up manylinux platform tag +# This makes auditwheel recognize the environment as manylinux-compatible +# Bullseye has glibc 2.31, so we use manylinux_2_31 +RUN echo "manylinux_2_31_armv7l" > /etc/system-release-cpe + +# Create a marker file for manylinux detection +RUN mkdir -p /opt/python && \ + echo "manylinux_2_31_armv7l" > /opt/python/PLATFORM + +# Set working directory +WORKDIR /workspace + +# Default Python +ENV PATH="/usr/bin:${PATH}" + +CMD ["/bin/bash"]