Windows 下再次成功复现编译并打包 MMCV 2.2.0 CUDA 算子 [torch 2.9.1+cu130] 复盘

本文记录 LiveTalking 项目中在 Windows 下成功编译、验证、打包 mmcv 2.2.0 CUDA 算子的完整过程。目标是让后续遇到同类环境时,可以照着脚本和检查项复现,而不是重新试错。

open-mmlab / mmcv 仓库

在这里插入图片描述

如果您无法完成编译,请参考纯 Python+CPU 安装方法
MMCV Python 3.12 安装记录

在旧版组件下编译 [torch 2.7.1+cu126]
我们如何在 Windows 上成功编译 MMCV CUDA 算子

MMCV 编译前必做
MMCV 预防性短路径编译策略

多版本 CUDA+cuDNN 共存及切换策略
Windows CMD 多版本 CUDA & cuDNN 一键切换管理方案
Windows 多版本 CUDA + cuDNN 环境配置完全指南

Windows 本地编译 CUDA 扩展 Wheel 完全指南
Windows 本地编译 CUDA Extension Wheel 完全指南

最终结果

本次已经完成三件事:

  1. 成功编译 mmcv._ext CUDA 扩展。
  2. 成功通过 MMCV 基础导入、扩展导入、CUDA ops、图像 I/O、MMEngine Config 验证。
  3. 成功打包 wheel 并保存依赖到 wheelhouse

成功产物:

J:\PythonProjects4\LiveTalking\mmcv\mmcv\_ext.cp312-win_amd64.pyd
J:\PythonProjects4\LiveTalking\wheelhouse\mmcv-2.2.0-cp312-cp312-win_amd64.whl
J:\PythonProjects4\LiveTalking\wheelhouse\requirements-lock.txt

成功日志:

J:\PythonProjects4\LiveTalking\logs\build_mmcv_20260606_235910.log
J:\PythonProjects4\LiveTalking\logs\pack_mmcv_wheel_20260607_004534.log

在这里插入图片描述

验证命令和结果:

.\.venv\Scripts\python.exe -c "import mmcv; print(mmcv.__version__); print(mmcv.__file__)"
2.2.0
J:\PythonProjects4\LiveTalking\mmcv\mmcv\__init__.py

在这里插入图片描述

验证方法请见下文的第 8 章
我们如何在 Windows 上成功编译 MMCV CUDA 算子

.\.venv\Scripts\python.exe -c "import mmcv._ext; print('MMCV ext: OK')"
.\.venv\Scripts\python.exe -c "from mmcv.ops import DeformConv2d; print('CUDA ops: OK')"
.\.venv\Scripts\python.exe -c "from mmcv import imread; print('Image I/O: OK')"
.\.venv\Scripts\python.exe -c "from mmengine.config import Config; print('MMEngine Config: OK')"

验证扩展模块
验证 CUDA 算子
验证图像 I/O
验证 Config 系统

MMCV ext: OK
CUDA ops: OK
Image I/O: OK
MMEngine Config: OK

在这里插入图片描述

成功环境

项目根目录:

J:\PythonProjects4\LiveTalking

本地源码:

cd J:\PythonProjects4\LiveTalking\
git clone https://github.com/open-mmlab/mmcv.git
cd mmcv

Python / PyTorch / MMCV:

Python 3.12.11
torch 2.9.1+cu130
torch.version.cuda = 13.0
mmcv 2.2.0

CUDA Toolkit:

C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.0
nvcc release 13.0, V13.0.88

cuDNN:

C:\Program Files\NVIDIA\CUDNN\v9.14
C:\Program Files\NVIDIA\CUDNN\v9.14\bin\13.0
C:\Program Files\NVIDIA\CUDNN\v9.14\include

Visual Studio / MSVC:

C:\Program Files\Microsoft Visual Studio\18\Insiders\VC\Auxiliary\Build\vcvars64.bat
C:\Program Files\Microsoft Visual Studio\18\Insiders\VC\Tools\MSVC\14.50.35717
cl version 19.50.35721

GPU 架构:

TORCH_CUDA_ARCH_LIST=8.6

一键编译

建议从普通 cmd.exe 打开,不要从 VS2022 Developer Prompt 打开。脚本会自己调用正确的 VS 2026 Insiders vcvars64.bat

cd /d J:\PythonProjects4\LiveTalking
.venv\Scripts\activate.bat
subst Z: /D
subst Z: "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.0"
subst
rmdir /s /q mmcv\build
tools\build_mmcv.cmd

如果 subst Z: /Drmdir /s /q mmcv\build 提示不存在,可以忽略。

编译前应确认:

subst

期望至少包含:

M:\: => J:\PythonProjects4\LiveTalking\mmcv
Z:\: => C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.0

tools\build_mmcv.cmd 会自动保存日志:

J:\PythonProjects4\LiveTalking\logs\build_mmcv_YYYYMMDD_HHMMSS.log

tools\build_mmcv.cmd 全量脚本示例:

@echo off
setlocal EnableExtensions EnableDelayedExpansion

set "ROOT=J:\PythonProjects4\LiveTalking"
set "LOG_DIR=%ROOT%\logs"
set "MMCV_ROOT=%ROOT%\mmcv"
set "PYTHON_EXE=%ROOT%\.venv\Scripts\python.exe"
set "CUDA_ROOT=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.0"
set "CUDA_DRIVE=Z:"
set "CUDA_SHORT=Z:\"
set "VCVARS=C:\Program Files\Microsoft Visual Studio\18\Insiders\VC\Auxiliary\Build\vcvars64.bat"

if not "%~1"=="--logged" (
  if not exist "%LOG_DIR%" mkdir "%LOG_DIR%"
  for /f %%i in ('powershell -NoProfile -Command "Get-Date -Format yyyyMMdd_HHmmss"') do set "LOG_TS=%%i"
  set "LOG_FILE=%LOG_DIR%\build_mmcv_!LOG_TS!.log"
  echo Writing build log: !LOG_FILE!
  call "%~f0" --logged > "!LOG_FILE!" 2>&1
  set "BUILD_EXIT=%ERRORLEVEL%"
  type "!LOG_FILE!"
  echo.
  echo Build log saved: !LOG_FILE!
  exit /b !BUILD_EXIT!
)

if not exist "%PYTHON_EXE%" (
  echo Python not found: %PYTHON_EXE%
  exit /b 1
)

if not exist "%VCVARS%" (
  echo vcvars64.bat not found: %VCVARS%
  exit /b 1
)

if not exist "%CUDA_ROOT%\bin\nvcc.exe" (
  echo nvcc not found: %CUDA_ROOT%\bin\nvcc.exe
  exit /b 1
)

subst M: "%MMCV_ROOT%" >nul 2>nul
subst %CUDA_DRIVE% "%CUDA_ROOT%" >nul 2>nul

if not exist "M:\tmp" mkdir "M:\tmp"
if not exist "M:\torch_ext" mkdir "M:\torch_ext"
if not exist "M:\cuda_cache" mkdir "M:\cuda_cache"
if not exist "M:\pip_cache" mkdir "M:\pip_cache"
if not exist "%CUDA_DRIVE%\bin\nvcc.exe" (
  echo nvcc not found after subst: %CUDA_DRIVE%\bin\nvcc.exe
  exit /b 1
)

set "INCLUDE="
set "LIB="
set "LIBPATH="
set "VSCMD_VER="
set "VSCMD_ARG_TGT_ARCH="
set "VSCMD_ARG_HOST_ARCH="
set "VSCMD_ARG_APP_PLAT="
set "VSCMD_START_DIR="
set "VSINSTALLDIR="
set "VCINSTALLDIR="
set "VCToolsInstallDir="
set "WindowsSdkDir="
set "WindowsLibPath="
set "UniversalCRTSdkDir="
set "UCRTVersion="
call "%VCVARS%" || exit /b 1

set "DISTUTILS_USE_SDK=1"
set "MSSdk=1"
set "CUDA_HOME=%CUDA_SHORT%"
set "CUDA_PATH=%CUDA_SHORT%"
set "CUDA_ROOT=%CUDA_SHORT%"
set "CudaToolkitDir=%CUDA_SHORT%"
set "CUDNN_HOME=C:\Program Files\NVIDIA\CUDNN\v9.14"
set "CUDNN_PATH=C:\Program Files\NVIDIA\CUDNN\v9.14\bin\13.0"
set "PATH=%CUDA_DRIVE%\bin;C:\Program Files\Microsoft Visual Studio\18\Insiders\Common7\IDE\CommonExtensions\Microsoft\CMake\Ninja;%PATH%"
set "TMP=M:\tmp"
set "TEMP=M:\tmp"
set "TORCH_EXTENSIONS_DIR=M:\torch_ext"
set "CUDA_CACHE_PATH=M:\cuda_cache"
set "PIP_CACHE_DIR=M:\pip_cache"
set "MMCV_CUDA_ARGS=-allow-unsupported-compiler"
set "MAX_JOBS=1"
set "TORCH_CUDA_ARCH_LIST=8.6"

cd /d M:\
echo Using python: %PYTHON_EXE%
echo Using CUDA_HOME: %CUDA_HOME%
where nvcc
where cl
cl /Bv
echo Using tmp: %TMP%
echo Using torch extensions cache: %TORCH_EXTENSIONS_DIR%
echo Using CUDA cache: %CUDA_CACHE_PATH%

call "%PYTHON_EXE%" setup.py build_ext --inplace -j 1
set "BUILD_EXIT=%ERRORLEVEL%"

exit /b %BUILD_EXIT%

在这里插入图片描述

一键打包 wheel

编译成功并验证通过后,运行:

rmdir /s /q mmcv\build
tools\pack_mmcv_wheel.cmd

tools\pack_mmcv_wheel.cmd 全量脚本示例:

@echo off
setlocal EnableExtensions EnableDelayedExpansion

set "ROOT=J:\PythonProjects4\LiveTalking"
set "LOG_DIR=%ROOT%\logs"
set "MMCV_ROOT=%ROOT%\mmcv"
set "PYTHON_EXE=%ROOT%\.venv\Scripts\python.exe"
set "CUDA_ROOT=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.0"
set "CUDA_DRIVE=Z:"
set "CUDA_SHORT=Z:\"
set "VCVARS=C:\Program Files\Microsoft Visual Studio\18\Insiders\VC\Auxiliary\Build\vcvars64.bat"
set "WHEELHOUSE=%ROOT%\wheelhouse"
set "NINJA_DIR=C:\Program Files\Microsoft Visual Studio\18\Insiders\Common7\IDE\CommonExtensions\Microsoft\CMake\Ninja"

if not "%~1"=="--logged" (
  if not exist "%LOG_DIR%" mkdir "%LOG_DIR%"
  for /f %%i in ('powershell -NoProfile -Command "Get-Date -Format yyyyMMdd_HHmmss"') do set "LOG_TS=%%i"
  set "LOG_FILE=%LOG_DIR%\pack_mmcv_wheel_!LOG_TS!.log"
  echo Writing wheel pack log: !LOG_FILE!
  call "%~f0" --logged > "!LOG_FILE!" 2>&1
  set "PACK_EXIT=%ERRORLEVEL%"
  type "!LOG_FILE!"
  echo.
  echo Wheel pack log saved: !LOG_FILE!
  exit /b !PACK_EXIT!
)

if not exist "%PYTHON_EXE%" (
  echo Python not found: %PYTHON_EXE%
  exit /b 1
)

if not exist "%VCVARS%" (
  echo vcvars64.bat not found: %VCVARS%
  exit /b 1
)

if not exist "%CUDA_ROOT%\bin\nvcc.exe" (
  echo nvcc not found: %CUDA_ROOT%\bin\nvcc.exe
  exit /b 1
)

if not exist "%WHEELHOUSE%" mkdir "%WHEELHOUSE%"

subst M: "%MMCV_ROOT%" >nul 2>nul
subst %CUDA_DRIVE% "%CUDA_ROOT%" >nul 2>nul

if not exist "M:\tmp" mkdir "M:\tmp"
if not exist "M:\torch_ext" mkdir "M:\torch_ext"
if not exist "M:\cuda_cache" mkdir "M:\cuda_cache"
if not exist "M:\pip_cache" mkdir "M:\pip_cache"
if not exist "%CUDA_DRIVE%\bin\nvcc.exe" (
  echo nvcc not found after subst: %CUDA_DRIVE%\bin\nvcc.exe
  exit /b 1
)

set "INCLUDE="
set "LIB="
set "LIBPATH="
set "VSCMD_VER="
set "VSCMD_ARG_TGT_ARCH="
set "VSCMD_ARG_HOST_ARCH="
set "VSCMD_ARG_APP_PLAT="
set "VSCMD_START_DIR="
set "VSINSTALLDIR="
set "VCINSTALLDIR="
set "VCToolsInstallDir="
set "WindowsSdkDir="
set "WindowsLibPath="
set "UniversalCRTSdkDir="
set "UCRTVersion="
call "%VCVARS%" || exit /b 1

set "DISTUTILS_USE_SDK=1"
set "MSSdk=1"
set "CUDA_HOME=%CUDA_SHORT%"
set "CUDA_PATH=%CUDA_SHORT%"
set "CUDA_ROOT=%CUDA_SHORT%"
set "CudaToolkitDir=%CUDA_SHORT%"
set "CUDNN_HOME=C:\Program Files\NVIDIA\CUDNN\v9.14"
set "CUDNN_PATH=C:\Program Files\NVIDIA\CUDNN\v9.14\bin\13.0"
set "PATH=%CUDA_DRIVE%\bin;%NINJA_DIR%;%PATH%"
set "TMP=M:\tmp"
set "TEMP=M:\tmp"
set "TORCH_EXTENSIONS_DIR=M:\torch_ext"
set "CUDA_CACHE_PATH=M:\cuda_cache"
set "PIP_CACHE_DIR=M:\pip_cache"
set "MMCV_CUDA_ARGS=-allow-unsupported-compiler"
set "MAX_JOBS=1"
set "TORCH_CUDA_ARCH_LIST=8.6"

cd /d M:\ || exit /b 1

echo Using python: %PYTHON_EXE%
echo Using CUDA_HOME: %CUDA_HOME%
where nvcc
where cl
cl /Bv
echo Using tmp: %TMP%
echo Using torch extensions cache: %TORCH_EXTENSIONS_DIR%
echo Using CUDA cache: %CUDA_CACHE_PATH%
echo Wheel output: %WHEELHOUSE%

call "%PYTHON_EXE%" setup.py build_ext --inplace -j 1 || exit /b 1
call "%PYTHON_EXE%" setup.py bdist_wheel --dist-dir "%WHEELHOUSE%" || exit /b 1

echo Downloading build/runtime dependencies...
call "%PYTHON_EXE%" -m pip download -d "%WHEELHOUSE%" ^
  addict ^
  mmengine ^
  numpy ^
  opencv-python ^
  packaging ^
  Pillow ^
  pyyaml ^
  regex ^
  yapf ^
  setuptools ^
  wheel ^
  Cython ^
  ninja || exit /b 1

call "%PYTHON_EXE%" -m pip freeze > "%WHEELHOUSE%\requirements-lock.txt" || exit /b 1

echo.
echo Saved files to: %WHEELHOUSE%
echo Note: torch and CUDA are not bundled by this script.
exit /b 0

脚本会:

  1. 复用成功编译环境。
  2. 重新执行 build_ext --inplace
  3. 执行 bdist_wheel
  4. 下载构建和运行依赖到 wheelhouse
  5. 输出 requirements-lock.txt

成功后确认:

dir wheelhouse

在这里插入图片描述

关键文件:

mmcv-2.2.0-cp312-cp312-win_amd64.whl
requirements-lock.txt

在这里插入图片描述

打包日志:

J:\PythonProjects4\LiveTalking\logs\pack_mmcv_wheel_YYYYMMDD_HHMMSS.log

离线或半离线安装思路

在目标环境中,如果 torch / CUDA 已经按同版本准备好,可以使用:

pip install --no-index --find-links wheelhouse mmcv

或者直接安装 wheel:

pip install wheelhouse\mmcv-2.2.0-cp312-cp312-win_amd64.whl

注意:当前 pack_mmcv_wheel.cmd 明确不保存 torch 和 CUDA Toolkit。torch 与 CUDA 需要按项目目标环境单独安装和匹配。

在这里插入图片描述

关键脚本

本次最终使用两个脚本:

tools\build_mmcv.cmd
tools\pack_mmcv_wheel.cmd

它们的核心策略一致:

set "CUDA_ROOT=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.0"
set "CUDA_DRIVE=Z:"
set "CUDA_SHORT=Z:\"
set "VCVARS=C:\Program Files\Microsoft Visual Studio\18\Insiders\VC\Auxiliary\Build\vcvars64.bat"

并显式设置:

set "DISTUTILS_USE_SDK=1"
set "MSSdk=1"
set "CUDA_HOME=Z:\"
set "CUDA_PATH=Z:\"
set "CUDA_ROOT=Z:\"
set "CudaToolkitDir=Z:\"
set "CUDNN_HOME=C:\Program Files\NVIDIA\CUDNN\v9.14"
set "CUDNN_PATH=C:\Program Files\NVIDIA\CUDNN\v9.14\bin\13.0"
set "TMP=M:\tmp"
set "TEMP=M:\tmp"
set "TORCH_EXTENSIONS_DIR=M:\torch_ext"
set "CUDA_CACHE_PATH=M:\cuda_cache"
set "PIP_CACHE_DIR=M:\pip_cache"
set "MMCV_CUDA_ARGS=-allow-unsupported-compiler"
set "MAX_JOBS=1"
set "TORCH_CUDA_ARCH_LIST=8.6"

短路径映射策略

Windows 下编译 CUDA 扩展时,真正危险的不只是 CUDA 安装路径,而是构建系统拼出来的长路径,例如:

J:\PythonProjects4\LiveTalking\mmcv\build\temp.win-amd64-cpython-312\Release\mmcv\ops\csrc\pytorch\cuda\fused_spconv_ops_cuda.obj

nvcc + cl + ninja 在处理深层目标文件、依赖文件、临时文件时容易出现路径过长或写入失败。

本次采用的短路径:

subst M: J:\PythonProjects4\LiveTalking\mmcv
subst Z: "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.0"

映射后:

源码根目录: M:\
构建目录:   M:\build\...
临时目录:   M:\tmp
PyTorch 扩展缓存: M:\torch_ext
CUDA 缓存: M:\cuda_cache
pip 缓存:  M:\pip_cache
CUDA:      Z:\
nvcc:      Z:\bin\nvcc.exe
include:   Z:\include

这能同时缩短:

  1. 源码路径。
  2. 构建输出路径。
  3. 临时文件路径。
  4. CUDA Toolkit 路径。
  5. PyTorch / CUDA / pip 缓存路径。

为什么 CUDA_HOME=Z:\ 而不是 CUDA_HOME=Z:

之前脚本使用裸盘符:

set "CUDA_HOME=Z:"

PyTorch 的 torch.utils.cpp_extension 在拼路径时可能生成:

Z:bin\nvcc
Z:include

这不是我们想要的绝对路径。最终改为:

set "CUDA_HOME=Z:\"
set "CUDA_PATH=Z:\"
set "CUDA_ROOT=Z:\"
set "CudaToolkitDir=Z:\"

这样编译命令稳定生成:

Z:\bin\nvcc
Z:\include

为什么要清理 VS 环境变量

如果从 VS2022 Developer Prompt 启动,环境里可能已经存在:

INCLUDE
LIB
LIBPATH
VSCMD_VER
VSINSTALLDIR
VCINSTALLDIR
VCToolsInstallDir
WindowsSdkDir

即使脚本后续调用 VS 2026 vcvars64.bat,旧的 VS2022 include/lib 仍可能混入编译命令,导致工具链错位。

因此脚本在调用 vcvars64.bat 前先清理:

set "INCLUDE="
set "LIB="
set "LIBPATH="
set "VSCMD_VER="
set "VSCMD_ARG_TGT_ARCH="
set "VSCMD_ARG_HOST_ARCH="
set "VSCMD_ARG_APP_PLAT="
set "VSCMD_START_DIR="
set "VSINSTALLDIR="
set "VCINSTALLDIR="
set "VCToolsInstallDir="
set "WindowsSdkDir="
set "WindowsLibPath="
set "UniversalCRTSdkDir="
set "UCRTVersion="
call "%VCVARS%" || exit /b 1

验证重点:

where cl
cl /Bv

成功时应看到:

C:\Program Files\Microsoft Visual Studio\18\Insiders\VC\Tools\MSVC\14.50.35717\bin\Hostx64\x64\cl.exe

而不是:

D:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.42.34433\...

mmcv/setup.py 的关键修改

本次编译不是只靠环境变量完成,还修改了 mmcv/setup.py 的构建入口。

1. 允许控制 Ninja

原始代码直接使用:

cmd_class = {'build_ext': BuildExtension}

修改为:

use_ninja = os.getenv('MMCV_USE_NINJA', '1') != '0'
if hasattr(BuildExtension, 'with_options'):
    cmd_class = {'build_ext': BuildExtension.with_options(use_ninja=use_ninja)}
else:
    cmd_class = {'build_ext': BuildExtension}

作用:

  1. 保持默认使用 Ninja。
  2. 必要时可以通过 MMCV_USE_NINJA=0 禁用 Ninja 做排错。

2. Windows CUDA 编译时补 USE_CUDA

PyTorch 2.9.1 的头文件 torch/csrc/dynamo/compiled_autograd.h 中有 Windows CUDA 保护分支:

#if defined(_WIN32) && (defined(USE_CUDA) || defined(USE_ROCM))

但 MMCV 原始构建只定义了:

MMCV_WITH_CUDA

没有定义:

USE_CUDA

结果 fused_spconv_ops_cuda.cu 编译时进入了不适合 Windows CUDA 的模板分支,触发:

torch/csrc/dynamo/compiled_autograd.h(1134): error C2872: "std"

最终在 setup.py 的 CUDA 分支中加入:

if platform.system() == 'Windows':
    define_macros += [('USE_CUDA', None)]

成功后失败命令中应出现:

-DUSE_CUDA

这个补丁是本次 torch 2.9.1+cu130 + CUDA 13.0 + Windows + MMCV 2.2.0 成功编译的关键。

mmcv/setup.py 全量脚本示例:

import glob
import os
import platform
import re
from pkg_resources import DistributionNotFound, get_distribution, parse_version
from setuptools import find_packages, setup

EXT_TYPE = ''
try:
    import torch

    if torch.__version__ == 'parrots':
        from parrots.utils.build_extension import BuildExtension

        EXT_TYPE = 'parrots'
    elif (hasattr(torch, 'is_mlu_available') and torch.is_mlu_available()) or \
            os.getenv('FORCE_MLU', '0') == '1':
        from torch_mlu.utils.cpp_extension import BuildExtension

        EXT_TYPE = 'pytorch'
    elif (hasattr(torch, 'is_musa_available') and torch.is_musa_available()) \
            or os.getenv('FORCE_MUSA', '0') == '1':
        from torch_musa.utils.musa_extension import BuildExtension

        EXT_TYPE = 'pytorch'
    else:
        from torch.utils.cpp_extension import BuildExtension

        EXT_TYPE = 'pytorch'
    use_ninja = os.getenv('MMCV_USE_NINJA', '1') != '0'
    if hasattr(BuildExtension, 'with_options'):
        cmd_class = {'build_ext': BuildExtension.with_options(use_ninja=use_ninja)}
    else:
        cmd_class = {'build_ext': BuildExtension}
except ModuleNotFoundError:
    cmd_class = {}
    print('Skip building ext ops due to the absence of torch.')


def choose_requirement(primary, secondary):
    """If some version of primary requirement installed, return primary, else
    return secondary."""
    try:
        name = re.split(r'[!<>=]', primary)[0]
        get_distribution(name)
    except DistributionNotFound:
        return secondary

    return str(primary)


def get_version():
    version_file = 'mmcv/version.py'
    with open(version_file, encoding='utf-8') as f:
        exec(compile(f.read(), version_file, 'exec'))
    return locals()['__version__']


def parse_requirements(fname='requirements/runtime.txt', with_version=True):
    """Parse the package dependencies listed in a requirements file but strips
    specific versioning information.
    Args:
        fname (str): path to requirements file
        with_version (bool, default=False): if True include version specs
    Returns:
        List[str]: list of requirements items
    CommandLine:
        python -c "import setup; print(setup.parse_requirements())"
    """
    import sys
    from os.path import exists
    require_fpath = fname

    def parse_line(line):
        """Parse information from a line in a requirements text file."""
        if line.startswith('-r '):
            # Allow specifying requirements in other files
            target = line.split(' ')[1]
            for info in parse_require_file(target):
                yield info
        else:
            info = {'line': line}
            if line.startswith('-e '):
                info['package'] = line.split('#egg=')[1]
            else:
                # Remove versioning from the package
                pat = '(' + '|'.join(['>=', '==', '>']) + ')'
                parts = re.split(pat, line, maxsplit=1)
                parts = [p.strip() for p in parts]

                info['package'] = parts[0]
                if len(parts) > 1:
                    op, rest = parts[1:]
                    if ';' in rest:
                        # Handle platform specific dependencies
                        # http://setuptools.readthedocs.io/en/latest/setuptools.html#declaring-platform-specific-dependencies
                        version, platform_deps = map(str.strip,
                                                     rest.split(';'))
                        info['platform_deps'] = platform_deps
                    else:
                        version = rest  # NOQA
                    info['version'] = (op, version)
            yield info

    def parse_require_file(fpath):
        with open(fpath) as f:
            for line in f.readlines():
                line = line.strip()
                if line and not line.startswith('#'):
                    yield from parse_line(line)

    def gen_packages_items():
        if exists(require_fpath):
            for info in parse_require_file(require_fpath):
                parts = [info['package']]
                if with_version and 'version' in info:
                    parts.extend(info['version'])
                if not sys.version.startswith('3.4'):
                    # apparently package_deps are broken in 3.4
                    platform_deps = info.get('platform_deps')
                    if platform_deps is not None:
                        parts.append(';' + platform_deps)
                item = ''.join(parts)
                yield item

    packages = list(gen_packages_items())
    return packages


install_requires = parse_requirements()

try:
    # OpenCV installed via conda.
    import cv2  # NOQA: F401

    major, minor, *rest = cv2.__version__.split('.')
    if int(major) < 3:
        raise RuntimeError(
            f'OpenCV >=3 is required but {cv2.__version__} is installed')
except ImportError:
    # If first not installed install second package
    CHOOSE_INSTALL_REQUIRES = [('opencv-python-headless>=3',
                                'opencv-python>=3')]
    for main, secondary in CHOOSE_INSTALL_REQUIRES:
        install_requires.append(choose_requirement(main, secondary))


def get_extensions():
    extensions = []

    if os.getenv('MMCV_WITH_OPS', '1') == '0':
        return extensions

    if EXT_TYPE == 'parrots':
        ext_name = 'mmcv._ext'
        from parrots.utils.build_extension import Extension

        # new parrots op impl do not use MMCV_USE_PARROTS
        # define_macros = [('MMCV_USE_PARROTS', None)]
        define_macros = []
        include_dirs = []
        op_files = glob.glob('./mmcv/ops/csrc/pytorch/cuda/*.cu') + \
                   glob.glob('./mmcv/ops/csrc/pytorch/cpu/*.cpp') + \
                   glob.glob('./mmcv/ops/csrc/parrots/*.cpp')
        include_dirs.append(os.path.abspath('./mmcv/ops/csrc/common'))
        include_dirs.append(os.path.abspath('./mmcv/ops/csrc/common/cuda'))
        op_files.remove('./mmcv/ops/csrc/pytorch/cuda/iou3d_cuda.cu')
        op_files.remove('./mmcv/ops/csrc/pytorch/cpu/bbox_overlaps_cpu.cpp')
        op_files.remove('./mmcv/ops/csrc/pytorch/cuda/bias_act_cuda.cu')
        cuda_args = os.getenv('MMCV_CUDA_ARGS')
        extra_compile_args = {
            'nvcc': [cuda_args, '-std=c++14'] if cuda_args else ['-std=c++14'],
            'cxx': ['-std=c++14'],
        }
        if torch.cuda.is_available() or os.getenv('FORCE_CUDA', '0') == '1':
            define_macros += [('MMCV_WITH_CUDA', None)]
            extra_compile_args['nvcc'] += [
                '-D__CUDA_NO_HALF_OPERATORS__',
                '-D__CUDA_NO_HALF_CONVERSIONS__',
                '-D__CUDA_NO_HALF2_OPERATORS__',
            ]
        ext_ops = Extension(
            name=ext_name,
            sources=op_files,
            include_dirs=include_dirs,
            define_macros=define_macros,
            extra_compile_args=extra_compile_args,
            cuda=True,
            pytorch=True)
        extensions.append(ext_ops)
    elif EXT_TYPE == 'pytorch':
        ext_name = 'mmcv._ext'
        from torch.utils.cpp_extension import CppExtension, CUDAExtension

        # prevent ninja from using too many resources
        try:
            import psutil
            num_cpu = len(psutil.Process().cpu_affinity())
            cpu_use = max(4, num_cpu - 1)
        except (ModuleNotFoundError, AttributeError):
            cpu_use = 4

        os.environ.setdefault('MAX_JOBS', str(cpu_use))
        define_macros = []

        # Before PyTorch1.8.0, when compiling CUDA code, `cxx` is a
        # required key passed to PyTorch. Even if there is no flag passed
        # to cxx, users also need to pass an empty list to PyTorch.
        # Since PyTorch1.8.0, it has a default value so users do not need
        # to pass an empty list anymore.
        # More details at https://github.com/pytorch/pytorch/pull/45956
        extra_compile_args = {'cxx': []}

        if platform.system() != 'Windows':
            if parse_version(torch.__version__) <= parse_version('1.12.1'):
                extra_compile_args['cxx'] = ['-std=c++14']
            else:
                extra_compile_args['cxx'] = ['-std=c++17']
        else:
            if parse_version(torch.__version__) <= parse_version('1.12.1'):
                extra_compile_args['cxx'] = ['/std:c++14']
            else:
                extra_compile_args['cxx'] = ['/std:c++17']

        include_dirs = []
        library_dirs = []
        libraries = []

        extra_objects = []
        extra_link_args = []
        is_rocm_pytorch = False
        try:
            from torch.utils.cpp_extension import ROCM_HOME
            is_rocm_pytorch = True if ((torch.version.hip is not None) and
                                       (ROCM_HOME is not None)) else False
        except ImportError:
            pass

        if os.getenv('MMCV_WITH_DIOPI', '0') == '1':
            import mmengine  # NOQA: F401
            from mmengine.utils.version_utils import digit_version
            assert digit_version(mmengine.__version__) >= digit_version(
                '0.7.4'), f'mmengine >= 0.7.4 is required \
                but {mmengine.__version__} is installed'

            print(f'Compiling {ext_name} with CPU and DIPU')
            define_macros += [('MMCV_WITH_DIOPI', None)]
            define_macros += [('DIOPI_ATTR_WEAK', None)]
            op_files = glob.glob('./mmcv/ops/csrc/pytorch/*.cpp') + \
                       glob.glob('./mmcv/ops/csrc/pytorch/cpu/*.cpp')
            extension = CppExtension
            include_dirs.append(os.path.abspath('./mmcv/ops/csrc/common'))
            dipu_root = os.getenv('DIPU_ROOT')
            diopi_path = os.getenv('DIOPI_PATH')
            dipu_path = os.getenv('DIPU_PATH')
            vendor_include_dirs = os.getenv('VENDOR_INCLUDE_DIRS')
            nccl_include_dirs = os.getenv('NCCL_INCLUDE_DIRS')
            pytorch_dir = os.getenv('PYTORCH_DIR')
            include_dirs.append(dipu_root)
            include_dirs.append(diopi_path + '/include')
            include_dirs.append(dipu_path + '/dist/include')
            include_dirs.append(vendor_include_dirs)
            include_dirs.append(pytorch_dir + 'torch/include')
            if nccl_include_dirs:
                include_dirs.append(nccl_include_dirs)
            library_dirs += [dipu_root]
            libraries += ['torch_dipu']
        elif is_rocm_pytorch or torch.cuda.is_available() or os.getenv(
                'FORCE_CUDA', '0') == '1':
            if is_rocm_pytorch:
                define_macros += [('MMCV_WITH_HIP', None)]
            define_macros += [('MMCV_WITH_CUDA', None)]
            if platform.system() == 'Windows':
                define_macros += [('USE_CUDA', None)]
            cuda_args = os.getenv('MMCV_CUDA_ARGS')
            extra_compile_args['nvcc'] = [cuda_args] if cuda_args else []
            op_files = glob.glob('./mmcv/ops/csrc/pytorch/*.cpp') + \
                       glob.glob('./mmcv/ops/csrc/pytorch/cpu/*.cpp') + \
                       glob.glob('./mmcv/ops/csrc/pytorch/cuda/*.cu') + \
                       glob.glob('./mmcv/ops/csrc/pytorch/cuda/*.cpp')
            extension = CUDAExtension
            include_dirs.append(os.path.abspath('./mmcv/ops/csrc/pytorch'))
            include_dirs.append(os.path.abspath('./mmcv/ops/csrc/common'))
            include_dirs.append(os.path.abspath('./mmcv/ops/csrc/common/cuda'))
        elif (hasattr(torch, 'is_mlu_available') and
              torch.is_mlu_available()) or \
                os.getenv('FORCE_MLU', '0') == '1':
            from torch_mlu.utils.cpp_extension import MLUExtension

            def get_mluops_version(file_path):
                with open(file_path) as f:
                    for line in f:
                        if re.search('MLUOP_MAJOR', line):
                            major = line.strip().split(' ')[2]
                        if re.search('MLUOP_MINOR', line):
                            minor = line.strip().split(' ')[2]
                        if re.search('MLUOP_PATCHLEVEL', line):
                            patchlevel = line.strip().split(' ')[2]
                mluops_version = f'v{major}.{minor}.{patchlevel}'
                return mluops_version

            mmcv_mluops_version = get_mluops_version(
                './mmcv/ops/csrc/pytorch/mlu/mlu_common_helper.h')
            mlu_ops_path = os.getenv('MMCV_MLU_OPS_PATH')
            if mlu_ops_path:
                exists_mluops_version = get_mluops_version(
                    mlu_ops_path + '/bangc-ops/mlu_op.h')
                if exists_mluops_version != mmcv_mluops_version:
                    print('the version of mlu-ops provided is %s,'
                          ' while %s is needed.' %
                          (exists_mluops_version, mmcv_mluops_version))
                    exit()
                try:
                    if os.path.exists('mlu-ops'):
                        if os.path.islink('mlu-ops'):
                            os.remove('mlu-ops')
                            os.symlink(mlu_ops_path, 'mlu-ops')
                        elif os.path.abspath('mlu-ops') != mlu_ops_path:
                            os.symlink(mlu_ops_path, 'mlu-ops')
                    else:
                        os.symlink(mlu_ops_path, 'mlu-ops')
                except Exception:
                    raise FileExistsError(
                        'mlu-ops already exists, please move it out,'
                        'or rename or remove it.')
            else:
                if not os.path.exists('mlu-ops'):
                    import requests
                    mluops_url = 'https://github.com/Cambricon/mlu-ops/' + \
                                 'archive/refs/tags/' + mmcv_mluops_version + '.zip'
                    req = requests.get(mluops_url)
                    with open('./mlu-ops.zip', 'wb') as f:
                        try:
                            f.write(req.content)
                        except Exception:
                            raise ImportError('failed to download mlu-ops')

                    from zipfile import BadZipFile, ZipFile
                    with ZipFile('./mlu-ops.zip', 'r') as archive:
                        try:
                            archive.extractall()
                            dir_name = archive.namelist()[0].split('/')[0]
                            os.rename(dir_name, 'mlu-ops')
                        except BadZipFile:
                            print('invalid mlu-ops.zip file')
                else:
                    exists_mluops_version = get_mluops_version(
                        './mlu-ops/bangc-ops/mlu_op.h')
                    if exists_mluops_version != mmcv_mluops_version:
                        print('the version of provided mlu-ops is %s,'
                              ' while %s is needed.' %
                              (exists_mluops_version, mmcv_mluops_version))
                        exit()

            define_macros += [('MMCV_WITH_MLU', None)]
            mlu_args = os.getenv('MMCV_MLU_ARGS', '-DNDEBUG ')
            mluops_includes = []
            mluops_includes.append('-I' +
                                   os.path.abspath('./mlu-ops/bangc-ops'))
            mluops_includes.append(
                '-I' + os.path.abspath('./mlu-ops/bangc-ops/kernels'))
            extra_compile_args['cncc'] = [mlu_args] + \
                                         mluops_includes if mlu_args else mluops_includes
            extra_compile_args['cxx'] += ['-fno-gnu-unique']
            op_files = glob.glob('./mmcv/ops/csrc/pytorch/*.cpp') + \
                       glob.glob('./mmcv/ops/csrc/pytorch/cpu/*.cpp') + \
                       glob.glob('./mmcv/ops/csrc/pytorch/mlu/*.cpp') + \
                       glob.glob('./mmcv/ops/csrc/common/mlu/*.mlu') + \
                       glob.glob(
                           './mlu-ops/bangc-ops/core/**/*.cpp', recursive=True) + \
                       glob.glob(
                           './mlu-ops/bangc-ops/kernels/**/*.cpp', recursive=True) + \
                       glob.glob(
                           './mlu-ops/bangc-ops/kernels/**/*.mlu', recursive=True)
            extra_link_args = [
                '-Wl,--whole-archive',
                './mlu-ops/bangc-ops/kernels/kernel_wrapper/lib/libextops.a',
                '-Wl,--no-whole-archive'
            ]
            extension = MLUExtension
            include_dirs.append(os.path.abspath('./mmcv/ops/csrc/common'))
            include_dirs.append(os.path.abspath('./mmcv/ops/csrc/common/mlu'))
            include_dirs.append(os.path.abspath('./mlu-ops/bangc-ops'))
        elif (hasattr(torch.backends, 'mps')
              and torch.backends.mps.is_available()) or os.getenv(
            'FORCE_MPS', '0') == '1':
            # objc compiler support
            from distutils.unixccompiler import UnixCCompiler
            if '.mm' not in UnixCCompiler.src_extensions:
                UnixCCompiler.src_extensions.append('.mm')
                UnixCCompiler.language_map['.mm'] = 'objc'

            define_macros += [('MMCV_WITH_MPS', None)]
            extra_compile_args = {}
            extra_compile_args['cxx'] = ['-Wall', '-std=c++17']
            extra_compile_args['cxx'] += [
                '-framework', 'Metal', '-framework', 'Foundation'
            ]
            extra_compile_args['cxx'] += ['-ObjC++']
            # src
            op_files = glob.glob('./mmcv/ops/csrc/pytorch/*.cpp') + \
                       glob.glob('./mmcv/ops/csrc/pytorch/cpu/*.cpp')
            # TODO: support mps ops on torch>=2.1.0
            if parse_version(torch.__version__) < parse_version('2.1.0'):
                op_files += glob.glob('./mmcv/ops/csrc/common/mps/*.mm') + \
                            glob.glob('./mmcv/ops/csrc/pytorch/mps/*.mm')
            extension = CppExtension
            include_dirs.append(os.path.abspath('./mmcv/ops/csrc/common'))
            include_dirs.append(os.path.abspath('./mmcv/ops/csrc/common/mps'))
        elif (os.getenv('FORCE_NPU', '0') == '1'):
            print(f'Compiling {ext_name} only with CPU and NPU')
            try:
                import importlib

                from torch_npu.utils.cpp_extension import NpuExtension
                extra_compile_args['cxx'] += [
                    '-D__FILENAME__=\"$$(notdir $$(abspath $$<))\"'
                ]
                extra_compile_args['cxx'] += [
                    '-I' + importlib.util.find_spec(
                        'torch_npu').submodule_search_locations[0] +
                    '/include/third_party/acl/inc'
                ]
                extra_compile_args['cxx'] += [
                    '-I' + importlib.util.find_spec(
                        'torch_npu').submodule_search_locations[0] +
                    '/include/third_party/hccl/inc'
                ]
                define_macros += [('MMCV_WITH_NPU', None)]
                extension = NpuExtension
                if parse_version(torch.__version__) < parse_version('2.1.0'):
                    define_macros += [('MMCV_WITH_XLA', None)]
                if parse_version(torch.__version__) >= parse_version('2.1.0'):
                    define_macros += [('MMCV_WITH_KPRIVATE', None)]
            except Exception:
                raise ImportError('can not find any torch_npu')
            # src
            op_files = glob.glob('./mmcv/ops/csrc/pytorch/*.cpp') + \
                       glob.glob('./mmcv/ops/csrc/pytorch/cpu/*.cpp') + \
                       glob.glob('./mmcv/ops/csrc/common/npu/*.cpp') + \
                       glob.glob('./mmcv/ops/csrc/pytorch/npu/*.cpp')
            include_dirs.append(os.path.abspath('./mmcv/ops/csrc/common'))
            include_dirs.append(os.path.abspath('./mmcv/ops/csrc/common/npu'))
        elif hasattr(torch, 'musa') or os.getenv('FORCE_MUSA', '0') == '1':
            from torch_musa.testing import get_musa_arch
            from torch_musa.utils.musa_extension import MUSAExtension
            define_macros += [('MMCV_WITH_MUSA', None),
                              ('MUSA_ARCH', str(get_musa_arch()))]
            os.environ['MUSA_ARCH'] = str(get_musa_arch())
            op_files = glob.glob('./mmcv/ops/csrc/pytorch/*.cpp') + \
                       glob.glob('./mmcv/ops/csrc/pytorch/cpu/*.cpp') + \
                       glob.glob('./mmcv/ops/csrc/pytorch/musa/*.mu') + \
                       glob.glob('./mmcv/ops/csrc/pytorch/musa/*.cpp')
            include_dirs.append(os.path.abspath('./mmcv/ops/csrc/pytorch'))
            include_dirs.append(os.path.abspath('./mmcv/ops/csrc/common'))
            include_dirs.append(os.path.abspath('./mmcv/ops/csrc/common/musa'))
            extension = MUSAExtension
        else:
            print(f'Compiling {ext_name} only with CPU')
            op_files = glob.glob('./mmcv/ops/csrc/pytorch/*.cpp') + \
                       glob.glob('./mmcv/ops/csrc/pytorch/cpu/*.cpp')
            extension = CppExtension
            include_dirs.append(os.path.abspath('./mmcv/ops/csrc/common'))

        # Since the PR (https://github.com/open-mmlab/mmcv/pull/1463) uses
        # c++14 features, the argument ['std=c++14'] must be added here.
        # However, in the windows environment, some standard libraries
        # will depend on c++17 or higher. In fact, for the windows
        # environment, the compiler will choose the appropriate compiler
        # to compile those cpp files, so there is no need to add the
        # argument
        if 'nvcc' in extra_compile_args and platform.system() != 'Windows':
            if parse_version(torch.__version__) <= parse_version('1.12.1'):
                extra_compile_args['nvcc'] += ['-std=c++14']
            else:
                extra_compile_args['nvcc'] += ['-std=c++17']

        ext_ops = extension(
            name=ext_name,
            sources=op_files,
            include_dirs=include_dirs,
            define_macros=define_macros,
            extra_objects=extra_objects,
            extra_compile_args=extra_compile_args,
            library_dirs=library_dirs,
            libraries=libraries,
            extra_link_args=extra_link_args)
        extensions.append(ext_ops)
    return extensions


setup(
    name='mmcv' if os.getenv('MMCV_WITH_OPS', '1') == '1' else 'mmcv-lite',
    version=get_version(),
    description='OpenMMLab Computer Vision Foundation',
    keywords='computer vision',
    packages=find_packages(),
    include_package_data=True,
    classifiers=[
        'Development Status :: 4 - Beta',
        'License :: OSI Approved :: Apache Software License',
        'Operating System :: OS Independent',
        'Programming Language :: Python :: 3',
        'Programming Language :: Python :: 3.7',
        'Programming Language :: Python :: 3.8',
        'Programming Language :: Python :: 3.9',
        'Programming Language :: Python :: 3.10',
        'Topic :: Utilities',
    ],
    url='https://github.com/open-mmlab/mmcv',
    author='MMCV Contributors',
    author_email='openmmlab@gmail.com',
    install_requires=install_requires,
    extras_require={
        'all': parse_requirements('requirements.txt'),
        'tests': parse_requirements('requirements/test.txt'),
        'build': parse_requirements('requirements/build.txt'),
        'optional': parse_requirements('requirements/optional.txt'),
    },
    python_requires='>=3.7',
    ext_modules=get_extensions(),
    cmdclass=cmd_class,
    zip_safe=False)

失败问题与解决记录

1. nvcc not found after subst

现象:

nvcc not found after subst: Z:\bin\nvcc.exe

原因:

Z: 盘符已被映射到其他 CUDA 版本,例如 CUDA 13.1,脚本想映射 CUDA 13.0 失败但错误被吞掉。

处理:

subst Z: /D
subst Z: "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.0"
subst

确认:

Z:\: => C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.0

2. CUDA 13.1 混入

现象:

where nvcc
Z:\bin\nvcc.exe
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.1\bin\nvcc.exe
...

只要第一项是 Z:\bin\nvcc.exeZ: 指向 CUDA 13.0,就可以接受。脚本把 Z:\bin 放到 PATH 最前面,确保实际使用 CUDA 13.0。

3. VS2022 MSVC 14.42 混入

现象:

编译命令里出现:

D:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.42.34433

处理:

  1. 不从 VS2022 Developer Prompt 启动。
  2. 脚本调用 vcvars64.bat 前清理 VS 旧变量。
  3. 打印 where clcl /Bv 做确认。

最终成功使用:

C:\Program Files\Microsoft Visual Studio\18\Insiders\VC\Tools\MSVC\14.50.35717

4. compiled_autograd.h(1134): error C2872: "std"

原因:

PyTorch 2.9.1 的 Windows CUDA 保护分支依赖 USE_CUDA,MMCV 原始构建没有定义该宏。

处理:

mmcv/setup.py 中为 Windows CUDA 编译定义:

define_macros += [('USE_CUDA', None)]

5. 路径过长风险

处理:

统一映射和缓存:

subst M: J:\PythonProjects4\LiveTalking\mmcv
subst Z: "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.0"
set TMP=M:\tmp
set TEMP=M:\tmp
set TORCH_EXTENSIONS_DIR=M:\torch_ext
set CUDA_CACHE_PATH=M:\cuda_cache
set PIP_CACHE_DIR=M:\pip_cache

编译日志中必须检查的内容

每次复现时,先看日志开头。

CUDA:

Using CUDA_HOME: Z:\
Z:\bin\nvcc.exe

MSVC:

C:\Program Files\Microsoft Visual Studio\18\Insiders\VC\Tools\MSVC\14.50.35717\bin\Hostx64\x64\cl.exe

短路径缓存:

Using tmp: M:\tmp
Using torch extensions cache: M:\torch_ext
Using CUDA cache: M:\cuda_cache

构建命令中应看到:

Z:\bin\nvcc
-IZ:\include
-IC:\Program Files\NVIDIA\CUDNN\v9.14\include
-DMMCV_WITH_CUDA
-DUSE_CUDA
-gencode=arch=compute_86,code=sm_86

注意事项

  1. 不要混装 mmcvmmcv-full。本项目使用本地源码 mmcv 2.2.0
  2. .venv\Lib\site-packages\mimictalk_mmcv_local.pth 应指向本地源码目录,确保 import mmcv 命中仓库内源码。
  3. 不要把 cl.exe 文件本身加入 PATH;PATH 应加入工具所在目录。
  4. CUDA_PATHPATH 第一项 nvcc、PyTorch 编译 CUDA 版本必须一致。本次是 cu130 / CUDA 13.0。
  5. 如果换 GPU,调整 TORCH_CUDA_ARCH_LIST。RTX 3090 使用 8.6
  6. 如果换 Python / torch / CUDA / MSVC 任一主版本,都应重新验证 setup.py 宏补丁是否仍然需要。
  7. wheelhouse 中不包含 torch 和 CUDA Toolkit,需要目标环境单独准备。
  8. 构建前清理 mmcv\build 可以避免 Ninja 复用旧参数。

最小复现命令清单

cd /d J:\PythonProjects4\LiveTalking
.venv\Scripts\activate.bat
subst Z: /D
subst Z: "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.0"
subst
rmdir /s /q mmcv\build
tools\build_mmcv.cmd

验证:

.\.venv\Scripts\python.exe -c "import mmcv; print(mmcv.__version__); print(mmcv.__file__)"
.\.venv\Scripts\python.exe -c "import mmcv._ext; print('MMCV ext: OK')"
.\.venv\Scripts\python.exe -c "from mmcv.ops import DeformConv2d; print('CUDA ops: OK')"
.\.venv\Scripts\python.exe -c "from mmcv import imread; print('Image I/O: OK')"
.\.venv\Scripts\python.exe -c "from mmengine.config import Config; print('MMEngine Config: OK')"

打包:

rmdir /s /q mmcv\build
tools\pack_mmcv_wheel.cmd
dir wheelhouse

结论

这次成功不是单一参数解决的,而是同时固定住了几个容易漂移的点:

  1. torch 2.9.1+cu130 对应 CUDA 13.0。
  2. nvcc 通过 Z:\bin\nvcc.exe 固定到 CUDA 13.0。
  3. MSVC 通过 VS 2026 Insiders vcvars64.bat 固定到 14.50.35717
  4. 源码、构建输出、临时目录、缓存目录都通过 M: 缩短。
  5. setup.py 为 Windows CUDA 编译补充 USE_CUDA,避开 PyTorch 2.9.1 头文件分支问题。
  6. 编译和打包都保存日志,后续能直接从日志回溯。

后续在同一机器上复现,优先使用 tools\build_mmcv.cmdtools\pack_mmcv_wheel.cmd,不要手工拼接长环境变量。

Logo

免费领 150 小时云算力,进群参与显卡、AI PC 幸运抽奖

更多推荐