[Build] Fix CUDA arch detection producing kernel-less builds on SM121 (#49904)

Ayushman Singh committed Jul 28, 2026 at 01:01 UTC 74587939b17b4eb3ba281ec9ca43f93aa230a3cb
3 files changed +40 -9
CMakeLists.txt
+9 -4
@@ -219,10 +219,8 @@ if(VLLM_GPU_LANG STREQUAL "CUDA")
219 # the set of architectures we want to compile for and remove the from the
220 # CMAKE_CUDA_FLAGS so that they are not applied globally.
221 #
222 - # `+PTX` in TORCH_CUDA_ARCH_LIST is not preserved here. It is emitted by torch
223 - # as `code=compute_*`, while extract_unique_cuda_archs_ascending() records only
224 - # `arch=compute_*`. If a kernel really needs PTX, add `+PTX` to that kernel's
225 - # component-specific arch list below.
222 + # `+PTX` in TORCH_CUDA_ARCH_LIST is not preserved here. If a kernel really
223 + # needs PTX, add `+PTX` to that kernel's component-specific arch list below.
224 #
225 clear_cuda_arches(CUDA_ARCH_FLAGS)
226 extract_unique_cuda_archs_ascending(CUDA_ARCHS "${CUDA_ARCH_FLAGS}")
@@ -232,6 +230,13 @@ if(VLLM_GPU_LANG STREQUAL "CUDA")
230 cuda_archs_loose_intersection(CUDA_ARCHS
231 "${CUDA_SUPPORTED_ARCHS}" "${CUDA_ARCHS}")
232 message(STATUS "CUDA supported target architectures: ${CUDA_ARCHS}")
233 + if(NOT CUDA_ARCHS)
234 + message(FATAL_ERROR
235 + "No supported CUDA architectures; the build would produce a binary "
236 + "with no usable kernels. Detected gencode flags: ${CUDA_ARCH_FLAGS}; "
237 + "supported: ${CUDA_SUPPORTED_ARCHS}. "
238 + "Set TORCH_CUDA_ARCH_LIST for your GPU (e.g. 12.0).")
239 + endif()
240 else()
241 #
242 # For other GPU targets override the GPU architectures detected by cmake/torch
cmake/utils.cmake
+6 -5
@@ -241,14 +241,15 @@ endmacro()
241 # `<major>.<minor>`, dedupes them and then sorts them in ascending order and
242 # stores them in `OUT_ARCHES`.
243 #
244 -# Example:
245 -# CUDA_ARCH_FLAGS="-gencode arch=compute_75,code=sm_75;...;-gencode arch=compute_90a,code=sm_90a"
246 -# extract_unique_cuda_archs_ascending(OUT_ARCHES CUDA_ARCH_FLAGS)
247 -# OUT_ARCHES="7.5;...;9.0"
244 +# Prefer `code=sm_*`; fall back to `arch=compute_*` for PTX-only flags.
245 +# This handles mismatches such as `arch=compute_20,code=sm_121`.
246 function(extract_unique_cuda_archs_ascending OUT_ARCHES CUDA_ARCH_FLAGS)
247 set(_CUDA_ARCHES)
248 foreach(_ARCH ${CUDA_ARCH_FLAGS})
251 - string(REGEX MATCH "arch=compute_\([0-9]+[af]?\)" _COMPUTE ${_ARCH})
249 + string(REGEX MATCH "code=sm_\([0-9]+[af]?\)" _COMPUTE ${_ARCH})
250 + if (NOT _COMPUTE)
251 + string(REGEX MATCH "arch=compute_\([0-9]+[af]?\)" _COMPUTE ${_ARCH})
252 + endif()
253 if (_COMPUTE)
254 set(_COMPUTE ${CMAKE_MATCH_1})
255 endif()
tests/test_cmake_utils.py
+25
@@ -21,3 +21,28 @@ endif()
21 )
22
23 subprocess.run(["cmake", "-P", script], check=True)
24 +
25 +
26 +def test_extract_archs_prefers_sass_target_over_corrupted_virtual_arch(
27 + tmp_path: Path,
28 +):
29 + """torch's autodetection can emit a bogus arch=compute_* half (e.g.
30 + capability 12.1 corrupted to arch=compute_20,code=sm_121); the SASS
31 + target must win, while PTX-only entries keep the virtual arch."""
32 + repo_root = Path(__file__).parents[1]
33 + script = tmp_path / "test_extract_archs.cmake"
34 + script.write_text(
35 + f"""
36 +cmake_minimum_required(VERSION 3.26)
37 +include("{repo_root / "cmake" / "utils.cmake"}")
38 +extract_unique_cuda_archs_ascending(actual
39 + "-gencode arch=compute_20,code=sm_121;\
40 +-gencode arch=compute_80,code=sm_80;\
41 +-gencode arch=compute_80,code=compute_80")
42 +if(NOT "${{actual}}" STREQUAL "8.0;12.1")
43 + message(FATAL_ERROR "Expected '8.0;12.1', got '${{actual}}'")
44 +endif()
45 +"""
46 + )
47 +
48 + subprocess.run(["cmake", "-P", script], check=True)