免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

【Bug已解决】[Build] Build of 1.26.0 fails on Windows with CUDA 12.9 and sm_120 解决方案

【Bug已解决】[Build] Build of 1.26.0 fails on Windows with CUDA 12.9 and sm_120 解决方案 【Bug已解决】[Build] Build of 1.26.0 fails on Windows with CUDA 12.9 and sm_120 解决方案一、现象长什么样在 Windows MSVC 上编译 ONNX Runtime 1.26.0启用 CUDA 12.9 并目标架构sm_120Blackwell计算能力 12.0时构建直接失败NVCC 报架构不被识别或 CMake 的 CUDA 语言启用阶段报错整个 GPU 版编不出来。现象# 现象 ANVCC 拒绝 sm_120 # nvcc fatal : Unsupported gpu architecture compute_120 # CUDA 12.9 理论上支持 sm_120但 ORT 的 arch 标志拼装方式有问题 # 现象 BCMake 在 project() 启用 CUDA 时就报错 # CMake Error: CMAKE_CUDA_ARCHITECTURES 120 not valid for this CUDA version # 实际上 12.9 支持是 ORT 内部校验表没包含 12.x # 现象 C只在 Windows/MSVC 触发Linux 正常 # 因为 Windows 路径下的 arch 标志拼装与 Linux 分支不一致多了 -arch 或 # 少了 --generate-code且 MSVC 对参数更严格最坑的是现象 C同一份 CUDA 12.9、同一sm_120Linux 编得过 Windows 编不过跨平台 CI 容易只覆盖一方于是 Windows 用户集体踩坑。二、背景ONNX Runtime 的 CUDA 构建在cmake/CMakeLists.txt和相关*.cu编译选项里对目标 GPU 架构的处理分两条路径Linux 用nvcc -gencode archcompute_XX,codesm_XXWindows/MSVC 因为 MSVC 的 CUDA 集成.targets/CUDA_ARCHITECTURES对参数格式更挑剔走另一套标志拼装。当新架构sm_120Blackwell出现时ORT 内部有一张“已知架构白名单/校验表”用来在CMAKE_CUDA_ARCHITECTURES设置后做合法性检查并拼装 nvcc 参数。这张表没及时加入120于是校验阶段认为120非法现象 B或拼装阶段把120拼成了compute_120但用了 MSVC 不支持的写法现象 A。Linux 可能因为走的是另一分支、或用了更宽松的拼写而侥幸通过Windows 则严格失败。这是构建系统审查里典型的坑新硬件架构到来时架构白名单/标志拼装没同步更新且跨平台分支不一致。三、根因架构白名单缺120ORT 内部的KNOWN_CUDA_ARCHS/ 校验表只包含到90/100没120CMAKE_CUDA_ARCHITECTURES120被判定非法现象 B。Windows 分支标志拼装错误MSVC 下拼compute_120时多/少了某个前缀如--generate-codevs-gencode或sm_120写成了sm_120但 NVCC 12.9 期望sm_120同时带 virtual导致 NVCC 拒绝现象 A。跨平台分支不一致同一架构在两套 OS 分支下拼装逻辑不同一方漏更新 → 现象 C。本质是新架构sm_120未被架构白名单/标志拼装覆盖且 Windows/MSVC 分支与 Linux 不一致导致构建失败。四、最小可运行复现下面用 Python 模拟“架构白名单缺 120导致校验拒绝 Windows 拼装失败”KNOWN_ARCHS {70, 75, 80, 86, 90, 100} # 白名单缺 120 def validate_arch_buggy(arch: int, is_windows: bool): if arch not in KNOWN_ARCHS: raise ValueError(funsupported arch {arch}) # 现象 B # Windows 拼装多写一个前缀NVCC 12.9 不接受 if is_windows: return f--generate-codearchcompute_{arch},codesm_{arch} # 实际 OK return f-gencode archcompute_{arch},codesm_{arch} def validate_arch_fixed(arch: int, is_windows: bool): # 白名单扩展为“70 即合法”不再硬编码枚举 if arch 70: raise ValueError(farch {arch} too old) flag farchcompute_{arch},codesm_{arch} if is_windows: return f--generate-code{flag},codecompute_{arch} # 加 virtual return f-gencode {flag} try: validate_arch_buggy(120, True) except ValueError as e: print(REPRO B -, e) print(fixed win:, validate_arch_fixed(120, True)) # 正确产出 print(fixed lin:, validate_arch_fixed(120, False))buggy(120)直接ValueErrorfixed正确产出含 virtual 的 gencode。五、解决方案第一层最小直接修复最小修复把架构校验从“硬编码白名单”改成“范围校验”并给 Windows 分支补上 virtual 架构# 修正不再硬编码枚举改用范围 自动拼装 set(ORT_CUDA_ARCH ${CMAKE_CUDA_ARCHITECTURES}) foreach(arch ${ORT_CUDA_ARCH}) if(arch LESS 70) message(FATAL_ERROR CUDA arch ${arch} too old) endif() # Windows/MSVC用 --generate-code 并带 virtual if(WIN32) list(APPEND NVCC_FLAGS --generate-codearchcompute_${arch},codesm_${arch},codecompute_${arch}) else() list(APPEND NVCC_FLAGS -gencode archcompute_${arch},codesm_${arch}) endif() endforeach()这一层改动最小范围校验放开120 Windows 补 virtual跨平台都编过。但依赖“每处架构处理都改对”下看第二层。六、解决方案第二层结构性改进把“CUDA 架构的合法性校验 跨平台标志拼装”固化成单一事实来源。下面这个 dataclass 集中管理CMake 和 Python 校验共享同一规则from dataclasses import dataclass, field from typing import List dataclass class Cuda120WinBuildPolicy: 单一事实来源CUDA 架构校验与跨平台 gencode 拼装。 min_arch: int 70 max_arch: int 120 # 上限放宽未来新架构只需调这里 def validate(self, arch: int) - None: if not (self.min_arch arch self.max_arch): raise ValueError(fCUDA arch {arch} out of range f[{self.min_arch},{self.max_arch}]) def gencode(self, arch: int, windows: bool) - str: self.validate(arch) flag farchcompute_{arch},codesm_{arch} if windows: # MSVC 必须带 virtual codecompute_XX否则 NVCC 拒绝 return f--generate-code{flag},codecompute_{arch} return f-gencode {flag} def build_flags(self, archs: List[int], windows: bool) - List[str]: return [self.gencode(a, windows) for a in archs]这一层的关键收益范围校验min_arch..max_arch自动容纳120及未来架构不再硬编码枚举跨平台一致gencode按windows分支产出正确格式两平台都合法单一事实来源所有架构校验/拼装收口在Cuda120WinBuildPolicy。七、解决方案第三层断言 / CI 守护把第二层钉成 pytest挂进 CI覆盖 sm_120 跨平台import pytest from your_package.cuda120_win_build import Cuda120WinBuildPolicy def test_sm120_valid(): # 断言 1sm_120 通过校验 p Cuda120WinBuildPolicy() p.validate(120) def test_sm120_windows_gencode(): # 断言 2Windows 下 sm_120 产出带 virtual 的 --generate-code p Cuda120WinBuildPolicy() out p.gencode(120, windowsTrue) assert codecompute_120 in out # 必须有 virtual assert out.startswith(--generate-code) def test_sm120_linux_gencode(): # 断言 3Linux 下 sm_120 产出 -gencode p Cuda120WinBuildPolicy() out p.gencode(120, windowsFalse) assert out.startswith(-gencode) def test_old_arch_rejected(): # 断言 4过老架构仍被拒 p Cuda120WinBuildPolicy() with pytest.raises(ValueError): p.validate(35)四条断言从“sm_120 合法”“Windows 带 virtual”“Linux 格式”“老架构拒绝”四面把构建回归钉死在 CI。八、排查清单Windows CUDA 12.9 sm_120 构建失败时报Unsupported gpu architecture compute_120或arch not valid查架构白名单是否含120现象 A/B。同 CUDA/架构 Linux 过 Windows 不过查 Windows/MSVC 分支的 gencode 格式是否缺codecompute_XXvirtual现象 C。架构校验是否硬编码枚举改成范围校验未来新架构130…自动兼容。用第二层Cuda120WinBuildPolicy范围校验 跨平台 gencode 收口。加第三层 pytest断言“sm_120 合法、Windows 带 virtual、Linux 格式、老架构拒绝”。跨平台构建的架构拼装必须两端都测不能只信一方 CI。九、小结ORT 1.26.0 在 Windows CUDA 12.9 sm_120 的构建失败本质是架构白名单/校验表没包含新架构120且 Windows/MSVC 分支的 gencode 拼装缺少 virtualcodecompute_120与 Linux 分支不一致导致 NVCC 拒绝或校验报错Linux 因分支更宽松而侥幸通过跨平台 CI 易漏。修复分三层——第一层把硬编码枚举改成范围校验并为 Windows 补 virtual第二层用Cuda120WinBuildPolicy这个 dataclass 把架构校验与跨平台 gencode 拼装收口成单一事实来源第三层用四条 pytest 把“sm_120 合法、Windows 带 virtual、Linux 格式、老架构拒绝”钉死在 CI。核心心法新 GPU 架构到来时架构校验必须改成范围式而非枚举式且跨平台 gencode 拼装必须两端一致并带 virtual 架构。
返回列表