[XPU][CI/Release][3/N] Add xpu wheel release to release pipeline (#52108)

Signed-off-by: Kunshang Ji <kunshang.ji@intel.com> Signed-off-by: Kunshang Ji <jikunshang95@gmail.com>

Kunshang Ji committed Aug 14, 2026 at 14:00 UTC 8e6d8e4f6a0c84db0d79129ab648492edf640fe2
6 files changed +99 -29
.buildkite/release-pipeline.yaml
+15 -1
@@ -164,7 +164,21 @@ steps:
164 env:
165 DOCKER_BUILDKIT: "1"
166
167 - - label: "Publish XPU Triton shim index"
167 + - label: "Build wheel - x86_64 - XPU"
168 + depends_on: ~
169 + id: build-wheel-x86-xpu
170 + agents:
171 + queue: cpu_queue_release
172 + commands:
173 + - "DOCKER_BUILDKIT=1 docker build --build-arg max_jobs=16 --build-arg GIT_REPO_CHECK=1 --tag vllm-ci:build-image --target vllm-build --progress plain -f docker/Dockerfile.xpu ."
174 + - "mkdir artifacts"
175 + - "docker run --rm -v $(pwd)/artifacts:/artifacts_host vllm-ci:build-image bash -c 'cp -r dist /artifacts_host && chmod -R a+rw /artifacts_host'"
176 + - "bash .buildkite/scripts/upload-nightly-wheels.sh"
177 + - 'bash .buildkite/scripts/annotate-build-artifact.sh "$$BUILDKITE_LABEL" "s3://vllm-wheels/$$BUILDKITE_COMMIT/$(cd artifacts/dist && echo *.whl)" release-wheels'
178 + env:
179 + DOCKER_BUILDKIT: "1"
180 +
181 + - label: "Publish and stage XPU Triton shim"
182 key: publish-xpu-triton-shim
183 depends_on: ~
184 agents:
.buildkite/scripts/generate-and-upload-nightly-index.sh
+3 -4
@@ -53,11 +53,10 @@ if [[ "${UPDATE_NIGHTLY_INDEX:-1}" == "1" && \
53 aws s3 cp --recursive "$INDICES_OUTPUT_DIR/" "s3://$BUCKET/nightly/"
54 fi
55
56 -# detect version from any wheel in the commit directory
57 -# download the first wheel we find to extract version metadata
58 -first_wheel_key=$($PYTHON -c "import json; obj=json.load(open('$obj_json')); print(next((c['Key'] for c in obj.get('Contents', []) if c['Key'].endswith('.whl')), ''))")
56 +# detect version from a vLLM wheel in the commit directory
57 +first_wheel_key=$($PYTHON -c "import json; obj=json.load(open('$obj_json')); print(next((c['Key'] for c in obj.get('Contents', []) if c['Key'].rsplit('/', 1)[-1].startswith('vllm-') and c['Key'].endswith('.whl')), ''))")
58 if [[ -z "$first_wheel_key" ]]; then
60 - echo "Error: No wheels found in $S3_COMMIT_PREFIX"
59 + echo "Error: No vLLM wheel found in $S3_COMMIT_PREFIX"
60 exit 1
61 fi
62 first_wheel=$(basename "$first_wheel_key")
.buildkite/scripts/generate-nightly-index.py
+7 -3
@@ -91,9 +91,9 @@ def parse_from_filename(file: str) -> WheelFileInfo:
91 else:
92 if "+" in version:
93 version_part, suffix = version.split("+", 1)
94 - # Only treat known patterns as variants (rocmXXX, cuXXX, cpu)
94 + # Only treat known patterns as variants (rocmXXX, cuXXX, cpu, xpu)
95 # Git hashes and other suffixes are NOT variants
96 - if suffix.startswith(("rocm", "cu", "cpu")):
96 + if suffix.startswith(("rocm", "cu", "cpu", "xpu")):
97 variant = suffix
98 version = version_part
99 # Otherwise keep the full version string (variant stays None)
@@ -429,7 +429,11 @@ if __name__ == "__main__":
429 if PY_VERSION_RE.match(version):
430 # upload-wheels.sh ensures no "dev" is in args.version
431 wheel_files = list(
432 - filter(lambda x: version in x and "dev" not in x, wheel_files)
432 + filter(
433 + lambda x: (version in x and "dev" not in x)
434 + or (x.startswith("triton-") and "+xpu-" in x),
435 + wheel_files,
436 + )
437 )
438 print(f"Non-nightly version detected, wheel files used: {wheel_files}")
439 else:
.buildkite/scripts/xpu/publish-triton-shim.sh
+11 -3
@@ -11,12 +11,17 @@ readonly WHEEL_SHA256="3c822f73e9870512f59a6ecf5dc305a4bcab11fa623f9ce91011f6043
11 readonly WHEEL_FILENAME="${WHEEL_URL##*/}"
12 readonly ENCODED_WHEEL_FILENAME="${WHEEL_FILENAME/+/%2B}"
13 readonly S3_PREFIX="s3://${BUCKET}/${PREFIX}/"
14 +readonly COMMIT="${BUILDKITE_COMMIT:-}"
15 readonly DRY_RUN="${DRY_RUN:-0}"
16
17 if [[ "$DRY_RUN" != "0" && "$DRY_RUN" != "1" ]]; then
18 echo "DRY_RUN must be 0 or 1" >&2
19 exit 2
20 fi
21 +if [[ "$DRY_RUN" == "0" && ! "$COMMIT" =~ ^[0-9a-f]{40}$ ]]; then
22 + echo "BUILDKITE_COMMIT must be a full lowercase commit hash" >&2
23 + exit 2
24 +fi
25
26 cd "$(dirname "${BASH_SOURCE[0]}")/../../.."
27
@@ -70,9 +75,9 @@ sed 's/import regex as re/import re/' \
75 # shellcheck disable=SC2086
76 $PYTHON "$index_generator" \
77 --version "$PREFIX" \
73 - --wheel-dir "$PREFIX" \
78 + --wheel-dir "$work_dir/$PREFIX" \
79 --current-objects "$objects_path" \
75 - --output-dir "$index_output_dir" \
80 + --output-dir "$work_dir" \
81 --comment "XPU Triton shim"
82
83 grep -Fq 'href="triton/"' "$index_output_dir/index.html"
@@ -87,4 +92,7 @@ if [[ "$DRY_RUN" == "1" ]]; then
92 else
93 aws s3 cp --recursive "$index_output_dir/" "$S3_PREFIX"
94 echo "Published XPU Triton shim index to https://wheels.vllm.ai/$PREFIX/"
90 -fi
\ No newline at end of file
95 + aws s3 cp "$S3_PREFIX$WHEEL_FILENAME" \
96 + "s3://$BUCKET/$COMMIT/$WHEEL_FILENAME"
97 + echo "Staged XPU Triton shim for https://wheels.vllm.ai/$COMMIT/xpu/"
98 +fi
docker/Dockerfile.xpu
+30 -3
@@ -129,6 +129,35 @@ CMD ["/bin/bash"]
129 ######################### UCX + NIXL BUILD STAGE #########################
130 # Build UCX and NIXL in a dedicated stage so compiler/autotools layers are
131 # never included in the final runtime image (mirrors ROCm's build_rixl stage).
132 +######################### WHEEL BUILD STAGE #########################
133 +# Produces a standalone dist/*.whl artifact (used by the release pipeline's
134 +# "Build wheel - XPU" step), independent of the runtime image below.
135 +FROM vllm-base AS vllm-build
136 +
137 +ARG GIT_REPO_CHECK=0
138 +
139 +RUN --mount=type=cache,target=/root/.cache/uv \
140 + --mount=type=bind,src=requirements/common.txt,target=/workspace/vllm/requirements/common.txt \
141 + --mount=type=bind,src=requirements/xpu.txt,target=/workspace/vllm/requirements/xpu.txt \
142 + uv pip install grpcio-tools protobuf nanobind && \
143 + uv pip install -r /workspace/vllm/requirements/xpu.txt
144 +
145 +# Keep source-dependent layers near the end so frequent code-only changes
146 +# don't invalidate heavy dependency layers.
147 +COPY . .
148 +
149 +# Drop the pre-built Rust artifacts into the source tree. setup.py detects
150 +# them and ships them as-is, skipping the local Rust build.
151 +COPY --from=rust-build /workspace/vllm/vllm-rs vllm/vllm-rs
152 +COPY --from=rust-build /workspace/vllm/_rust_*.so vllm/
153 +
154 +RUN --mount=type=bind,source=.git,target=.git \
155 + if [ "$GIT_REPO_CHECK" != 0 ]; then bash tools/check_repo.sh; fi
156 +
157 +RUN --mount=type=cache,target=/root/.cache/uv \
158 + --mount=type=bind,source=.git,target=.git \
159 + VLLM_TARGET_DEVICE=xpu python3 setup.py bdist_wheel --dist-dir=dist --py-limited-api=cp38
160 +
161 FROM vllm-base AS ucx-nixl-build
162
163 ARG UCX_VERSION=v1.21.0-rc2
@@ -201,9 +230,7 @@ RUN --mount=type=cache,target=/root/.cache/uv \
230 --mount=type=bind,src=requirements/test/xpu.txt,target=/workspace/vllm/requirements/test/xpu.txt \
231 uv pip install grpcio-tools protobuf nanobind && \
232 uv pip install -r /workspace/vllm/requirements/xpu.txt && \
204 - uv pip install --no-build-isolation -r /workspace/vllm/requirements/test/xpu.txt && \
205 - uv pip uninstall triton triton-xpu && \
206 - uv pip install triton-xpu==3.7.2
233 + uv pip install --no-build-isolation -r /workspace/vllm/requirements/test/xpu.txt
234
235 # Keep source-dependent layers near the end so frequent code-only changes
236 # don't invalidate heavy dependency and UCX/NIXL layers.
docs/getting_started/installation/gpu.xpu.inc.md
+33 -15
@@ -20,7 +20,26 @@ There is no extra information on creating a new Python environment for this devi
20 --8<-- [end:set-up-using-python]
21 --8<-- [start:pre-built-wheels]
22
23 -Currently, there are no pre-built XPU wheels.
23 +Pre-built vLLM XPU wheels are published to `wheels.vllm.ai`. Each XPU wheel
24 +index also contains the `triton==3.7.2+xpu` shim described below. PyTorch XPU
25 +packages are served from the PyTorch XPU index, so both index URLs are needed.
26 +
27 +#### Install the latest code
28 +
29 +To install the wheel built from the latest main branch:
30 +
31 +```bash
32 +uv pip install vllm --extra-index-url https://wheels.vllm.ai/nightly/xpu --extra-index-url https://download.pytorch.org/whl/xpu --index-strategy unsafe-best-match
33 +```
34 +
35 +#### Install specific revisions
36 +
37 +If you want to access the wheels for previous commits (e.g. to bisect the behavior change, performance regression), you can specify the commit hash in the URL:
38 +
39 +```bash
40 +export VLLM_COMMIT=730bd35378bf2a5b56b6d3a45be28b3092d26519 # use full commit hash from the main branch
41 +uv pip install vllm --extra-index-url https://wheels.vllm.ai/${VLLM_COMMIT}/xpu --extra-index-url https://download.pytorch.org/whl/xpu --index-strategy unsafe-best-match
42 +```
43
44 --8<-- [end:pre-built-wheels]
45 --8<-- [start:build-wheel-from-source]
@@ -36,25 +55,24 @@ pip install --upgrade pip
55 pip install -v -r requirements/xpu.txt
56 ```
57
39 -- Then, install the correct Triton package for Intel XPU.
40 -
41 - The default `triton` package (for NVIDIA GPUs) may be installed as a transitive dependency (e.g., via `xgrammar`). For Intel XPU, you must replace it with `triton-xpu`:
42 -
43 - ```bash
44 - pip uninstall -y triton triton-xpu
45 - pip install triton-xpu==3.7.2 --extra-index-url https://download.pytorch.org/whl/xpu
46 - ```
47 -
48 - !!! note
49 - - `triton` (without suffix) is for NVIDIA GPUs only. On XPU, using it instead of `triton-xpu` can cause correctness or runtime issues.
50 - - For torch 2.13 (the version used in `requirements/xpu.txt`), the matching package is `triton-xpu==3.7.2`. If you use a different version of torch, check the corresponding `triton-xpu` version in [docker/Dockerfile.xpu](https://github.com/vllm-project/vllm/blob/main/docker/Dockerfile.xpu).
51 -
52 -- Finally, build and install vLLM XPU backend:
58 +- Then, install vLLM XPU backend:
59
60 ```bash
61 VLLM_TARGET_DEVICE=xpu pip install --no-build-isolation -e . -v
62 ```
63
64 +!!! note
65 + `requirements/xpu.txt` pins `triton==3.7.2+xpu`, a compatibility shim
66 + hosted on `https://wheels.vllm.ai/xpu` that transparently resolves to
67 + the real Intel XPU implementation (`triton-xpu`). This exists because
68 + some transitive dependencies (e.g. `xgrammar`) unconditionally
69 + require a distribution literally named `triton`, which otherwise
70 + resolves to the NVIDIA-only PyPI `triton` package on XPU and can
71 + cause correctness or runtime issues. No manual uninstall/reinstall of
72 + `triton`/`triton-xpu` is needed; both `pip install` and `uv pip
73 + install --index-strategy unsafe-best-match` resolve the correct
74 + package automatically.
75 +
76 --8<-- [end:build-wheel-from-source]
77 --8<-- [start:pre-built-images]
78