Prhub

#41149 [CI/Build] Auto-detect manylinux ABI tag for nightly wheels

原始 PR 作者 Harry-Chen 合并时间 2026-04-29 15:37 文件变更 8 提交数 3 评论 15 代码增减 +352 / -49

执行摘要

自动检测 wheel 的 manylinux 标签,消除升级漂移

PR body 指出:原 pipeline 硬编码 manylinux_2_31manylinux_2_35,当升级 Ubuntu 基础镜像时,静默生成标签错误的 wheel,且 CI 中无信号检查漂移。此 PR 采用 auditwheel 内部的 analyze_wheel_abi API 根据 ELF 文件实际引用的 glibc 符号版本推导平台标签,使标签始终跟踪实际需求。

值得精读,尤其是 detect-manylinux-tag.py 中如何绕过 auditwheel repair 的限制直接调用内部 API 的设计,以及 lib/manylinux.sh 中通过容器化固定环境的权衡。该 PR 提供了基础设施可靠性的良好范例。

讨论亮点

Copilot 指出 detect_platform_tag 缺少错误处理,建议 main 中捕获异常并输出简洁错误。作者已添加 try/except 块。
Copilot 和 Gemini 均建议固定 auditwheel 版本,因为脚本依赖内部 API。作者在 lib/manylinux.sh 中固定为 6.6.0。
Gemini 认为 analyze_wheel_abi 签名不正确且 sym_policy.name 缺少架构后缀。作者回复 False Positive,保留当前实现。
Copilot 指出 lib/manylinux.sh 无条件设置 EXIT 陷阱会覆盖调用者陷阱。作者后续提交优化了陷阱链逻辑(捕获已有陷阱并在清理后运行)。

实现拆解

  1. 新增 detect-manylinux-tag.py:使用 auditwheel.wheel_abi.analyze_wheel_abi 检测 wheel 兼容的精确平台标签,并原位重命名 wheel。它只提取 sym_policy.name,而不像 auditwheel repair 那样尝试嫁接外部共享库。main() 包含友好的错误处理。
  2. 新增 lib/manylinux.sh:为标签检测提供容器化环境。它启动一个长期运行的 python:3.12-slim 容器,安装固定版本 auditwheel(6.6.0),然后通过 docker exec 调用检测脚本。容器由 EXIT 陷阱清理。
  3. 新增 lib/select-python.sh:提供 select_python 函数,优先使用主机 python3(如果 ≥3.12),否则退回到 docker python:3-slim
  4. 更新 upload-nightly-wheels.sh:移除硬编码参数和手动替换逻辑,改为 source manylinux.sh 并调用 apply_manylinux_tag
  5. 更新 upload-rocm-wheels.sh:类似地,接入 manylinux.shselect-python.sh,移除旧有的 MANYLINUX_VERSION 硬编码。
  6. 更新 generate-and-upload-nightly-index.sh:使用 select-python.sh 替代重复的 Python 版本检测逻辑。
  7. 更新 release-pipeline.yaml:移除传递给 upload-nightly-wheels.sh 的 manylinux 参数,因为标签现在由脚本自动确定。
文件 模块 状态 重要度
.buildkite/scripts/detect-manylinux-tag.py 构建脚本 added 8.66
.buildkite/scripts/lib/manylinux.sh 构建脚本 added 5.91
.buildkite/scripts/upload-rocm-wheels.sh 构建脚本 modified 4.6
.buildkite/scripts/upload-nightly-wheels.sh 构建脚本 modified 4.79
.buildkite/scripts/generate-and-upload-nightly-index.sh 构建脚本 modified 3.86
.buildkite/release-pipeline.yaml CI 配置 modified 3.81
.buildkite/scripts/lib/select-python.sh 构建脚本 added 4.44
.gitignore 其他 modified 2.0

关键符号

detect_platform_tag rename_wheel main apply_manylinux_tag select_python

关键源码片段

.buildkite/scripts/lib/manylinux.sh core-logic

核心 shell 帮助库,提供容器化 auditwheel 环境,实现 apply_manylinux_tag 函数。

"/usr/bin/env bash
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
#
# Shared helper for rewriting a wheel's platform tag from the generic
# ``linux_<arch>`` to the correct ``manylinux_<major>_<minor>_<arch>``.
# After sourcing, call ``apply_manylinux_tag <wheel>`` on each wheel
# that still carries the generic tag; the renamed path is printed on
# stdout (logs go to stderr).
#
# Why a pinned Docker container instead of using whatever Python
# happens to be on the agent:
# - vLLM's release agents are heterogeneous -- they don't agree on
#   a Python minor version, and we can't rely on a particular
#   ``auditwheel`` being installed.
# - ``detect-manylinux-tag.py`` reads ``auditwheel.wheel_abi`` and
#   ``Policy.sym_policy``, which are *internal* APIs without a
#   stability promise. Pinning both Python and auditwheel makes the
#   detected tag a function of the inputs alone, and shifts version
#   bumps from "implicit drift" to "deliberate, retested change".
# - Other release scripts already use the python:3-slim image
#   when the agent's interpreter is too old; this is the same idea
#   made stricter.if [[ -n "${_MANYLINUX_LIB_SOURCED:-}" ]]; then
    return 0
fi
_MANYLINUX_LIB_SOURCED=1# 固定 Python 和 auditwheel 版本,确保检测结果可重现
_MANYLINUX_PYTHON_IMAGE="python:3.12-slim"
_MANYLINUX_AUDITWHEEL_VERSION="6.6.0"# 解析脚本自身目录(解析符号链接后的规范路径)
_MANYLINUX_LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
_MANYLINUX_DETECT_SCRIPT="$(cd "${_MANYLINUX_LIB_DIR}/.." && pwd -P)/detect-manylinux-tag.py"
_MANYLINUX_CWD="$(pwd -P)"docker pull --quiet "$_MANYLINUX_PYTHON_IMAGE" >/dev/null# 启动一个长驻的 helper 容器,只安装一次 auditwheel,
# 后续对每个 wheel 通过 docker exec 调用
# ...(后续为创建容器、安装 auditwheel、定义 apply_manylinux_tag 函数等)

评论区精华

错误处理 正确性

Copilot 指出 detect_platform_tag 缺少错误处理,建议 main 中捕获异常并输出简洁错误。

结论:作者已添加 try/except 块。 · 已解决

auditwheel 版本固定 测试

Copilot 和 Gemini 均建议固定 auditwheel 版本,因为脚本依赖内部 API。

结论:作者在 lib/manylinux.sh 中固定为 6.6.0。 · 已解决

API 签名争议 正确性

Gemini 认为 analyze_wheel_abi 签名不正确且 sym_policy.name 缺少架构后缀。

结论:作者回复 False Positive,保留当前实现。 · dismissed

EXIT 陷阱覆盖 设计

Copilot 指出 lib/manylinux.sh 无条件设置 EXIT 陷阱会覆盖调用者陷阱。

结论:作者后续提交优化了陷阱链逻辑(捕获已有陷阱并在清理后运行)。 · 已解决

风险与影响

  1. 依赖 auditwheel 内部 APIanalyze_wheel_abisym_policy 是 auditwheel 的非公开 API,版本升级可能破坏兼容性。已通过固定版本和容器化缓解。
  2. 缺少测试覆盖:本次变更未包含自动化测试,仅靠手动测试和 CI artifact 检查。
  3. 容器环境网络依赖:manylinux.sh 需要拉取 Docker 镜像和 pip 安装 auditwheel,网络不稳定可能导致 CI 失败。
  4. Python 版本要求 ≥3.12:select-python.sh 优先使用本地 Python,但若主机版本不足且 Docker 拉取失败,则无法完成检测。

影响所有 nightly 和 release wheel 的构建与上传流程,确保 wheel 平台标签与二进制文件实际使用的 glibc 版本匹配,避免上传到 PyPI 索引时被 pip 拒绝。团队需要定期维护 auditwheel 版本,并在基础镜像升级时触发 re-tag 验证。

依赖 auditwheel 内部 API 缺少测试覆盖 容器环境网络依赖 Python 版本要求 ≥3.12

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论