feat: 添加 ARM64 manylinux wheel 构建选项

复用现有 Docker 和 Nuitka 流程,隔离架构镜像并支持 aarch64 标签。已通过 47 项测试、代码及文档门禁,并完成 Python 3.10 ARM64 wheel 构建、隔离导入与内容审计。
This commit is contained in:
ykcheungab
2026-10-14 16:08:54 +08:00
parent 3953747f17
commit bb15b750fb
11 changed files with 192 additions and 19 deletions
+2 -2
View File
@@ -76,7 +76,7 @@ def _validate_pypi_linux_environment() -> None:
if sys.platform != "linux":
raise SystemExit(
"[ERROR] --target pypi-linux must run inside a Linux manylinux container "
"(for example quay.io/pypa/manylinux_2_28_x86_64 via Docker Desktop)."
"(manylinux_2_28_x86_64 or manylinux_2_28_aarch64 via Docker Desktop)."
)
if sys.version_info[:2] not in PYPI_LINUX_PYTHON_VERSIONS:
supported = ", ".join(f"{major}.{minor}" for major, minor in PYPI_LINUX_PYTHON_VERSIONS)
@@ -153,7 +153,7 @@ def build(*, target: str = "internal", verify: bool | None = None) -> Path:
if target == "pypi-linux" and not is_compliant_manylinux_wheel(final_candidate):
raise SystemExit(
f"[ERROR] Wheel is not PyPI-compliant: {final_candidate.name}. "
"Expected a manylinux_2_17_x86_64 (or newer) platform tag."
"Expected a supported manylinux x86_64 or aarch64 platform tag."
)
# Keep a durable copy under dist/repaired for upload tooling.
+2 -1
View File
@@ -1,7 +1,8 @@
# manylinux_2_28: modern glibc baseline with binary wheels for numpy/scipy/opencv.
# Prefer this over manylinux2014 — recent NumPy requires GCC >= 10.3 and will try
# (and fail) to build from source on the older image.
FROM quay.io/pypa/manylinux_2_28_x86_64:latest
ARG MANYLINUX_ARCH=x86_64
FROM quay.io/pypa/manylinux_2_28_${MANYLINUX_ARCH}:latest
ENV PIP_DISABLE_PIP_VERSION_CHECK=1 \
PIP_ROOT_USER_ACTION=ignore \
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
# Runs inside quay.io/pypa/manylinux_2_28_x86_64 with the repo mounted at /src.
# Runs inside the selected manylinux_2_28 image with the repo mounted at /src.
# Builds one Nuitka wheel per CPython ABI listed in ORISYS_PYTHON_TAGS.
set -euo pipefail
+24 -5
View File
@@ -1,21 +1,24 @@
# Build PyPI-compliant manylinux wheels for CPython 3.10/3.11/3.12 using Docker Desktop.
# Build x86_64 or aarch64 manylinux wheels using Docker Desktop.
#
# Usage (from repo root, PowerShell):
# .\build\wheel\docker\run.ps1
# .\build\build_manylinux_docker.ps1 # compatibility wrapper
# .\build\wheel\docker\run.ps1 -Architecture aarch64 -PythonVersions 3.10
#
# From cmd.exe:
# powershell -ExecutionPolicy Bypass -File .\build\build_manylinux_docker.ps1
# powershell -ExecutionPolicy Bypass -File .\build\wheel\docker\run.ps1
param(
[ValidateSet("pypi-linux", "internal")]
[string]$Target = "pypi-linux",
[string]$PythonVersions = "3.10,3.11,3.12",
[ValidateSet("x86_64", "aarch64")]
[string]$Architecture = "x86_64",
[switch]$SkipImageBuild,
[string]$ImageName = "orisys-manylinux"
[string]$ImageName = ""
)
$ErrorActionPreference = "Stop"
$Architecture = $Architecture.ToLowerInvariant()
function Convert-ToManylinuxTag {
param([string]$Version)
@@ -45,11 +48,17 @@ if ($tags.Count -eq 0) {
throw "No Python versions specified."
}
$pythonTags = [string]::Join(",", $tags)
$dockerArchitecture = if ($Architecture -eq "aarch64") { "arm64" } else { "amd64" }
$dockerPlatform = "linux/$dockerArchitecture"
if ([string]::IsNullOrWhiteSpace($ImageName)) {
$ImageName = if ($Architecture -eq "aarch64") { "orisys-manylinux-aarch64" } else { "orisys-manylinux" }
}
Write-Host "=== Orisys manylinux Docker build ==="
Write-Host "Repo: $RepoRoot"
Write-Host "Target: $Target"
Write-Host "Image: $ImageName"
Write-Host "Architecture: $Architecture ($dockerPlatform)"
Write-Host "Python tags: $pythonTags"
# Docker Desktop must be in Linux container mode for manylinux.
@@ -71,15 +80,25 @@ $dockerfile = "build/wheel/docker/Dockerfile.manylinux"
if (-not $SkipImageBuild) {
Write-Host "`n=== Building Docker image ==="
docker build -f $dockerfile -t $ImageName .
docker build --platform $dockerPlatform --build-arg "MANYLINUX_ARCH=$Architecture" -f $dockerfile -t $ImageName .
if ($LASTEXITCODE -ne 0) {
throw "docker build failed"
}
}
# A custom or reused image must contain the requested architecture.
$imageArchitecture = docker image inspect --format "{{.Architecture}}" $ImageName
if ($LASTEXITCODE -ne 0) {
throw "Cannot inspect image '$ImageName'. Rebuild without -SkipImageBuild."
}
if ($imageArchitecture -ne $dockerArchitecture) {
throw "Image '$ImageName' architecture is '$imageArchitecture'; expected '$dockerArchitecture'. Rebuild without -SkipImageBuild."
}
Write-Host "`n=== Running manylinux container ==="
# Mount the repo so artifacts land under dist/repaired and SDK/<version>/ on the host.
docker run --rm `
--platform $dockerPlatform `
-e "ORISYS_BUILD_TARGET=$Target" `
-e "ORISYS_PYTHON_TAGS=$pythonTags" `
-v "${RepoRoot}:/src" `
+4 -4
View File
@@ -16,7 +16,7 @@ from common.paths import sdk_dir
# PyPI rejects bare tags like "manylinux_x86_64"; require a glibc ABI version.
_MANYLINUX_TAG_RE = re.compile(
r"(?:manylinux2014|manylinux_2_(?:17|24|27|28|31|34|35))_x86_64"
r"(?:manylinux2014|manylinux_2_(?:17|24|27|28|31|34|35))_(?:x86_64|aarch64)(?=\.|$)"
)
# Source of the PyPI project description (see read_long_description).
@@ -155,7 +155,7 @@ def _ensure_auditwheel() -> None:
def is_compliant_manylinux_wheel(wheel_path: Path) -> bool:
"""True if the wheel filename uses a PyPI-accepted manylinux x86_64 tag."""
"""True if the wheel filename uses a supported manylinux x86_64 or aarch64 tag."""
return bool(_MANYLINUX_TAG_RE.search(wheel_path.name))
@@ -200,8 +200,8 @@ def repair_linux_wheel(wheel_path: Path, repair_dir: Path) -> Path:
names = ", ".join(path.name for path in repaired)
raise RuntimeError(
"auditwheel repair did not produce a PyPI-compliant manylinux tag. "
f"Got: {names}. Rebuild inside quay.io/pypa/manylinux_2_28_x86_64 "
"(or manylinux2014_x86_64) instead of a generic Linux host."
f"Got: {names}. Rebuild inside the manylinux_2_28 image for the "
"target architecture instead of a generic Linux host."
)
final = compliant[0]