一些编译cuda的笔记

环境配置

Linux由于各个发行版包管理不同,且几乎99%的发行版一定会自带gcc,因此参见CUDAcuDNN安装即可,以及可能需要参见CUDA文档设置环境变量。
本节只介绍Windows.

CUDA支持离卡编译,因此CUDA Toolkit和其它各路编译套件完全可以装在没有N卡的机器上,然后完成所有编译工作。但是编译完的程序当然还是需要在有N卡的机器上才能运行

  1. Visual Studio: C/C++编译器
    如果电脑原先没有安装VS,那只安装VS Build Tools就足够了:从微软官网获取Visual Studio 2026生成工具(页面下拉,在所有下载里面选择“用于Visual Studio的工具”就能找到。或者,如果需要兼容性,可以选择VS2022或者VS2019

    截至当前的cuda版本(13.0),NVIDIA官方支持2019和2022

    然后在安装的时候,选择“使用C++的桌面开发”。组件可以适当精简,比如MSVC AddressSanitizervcpkg包管理器可以不需要。如下图所示:

    安装完成后,编译器默认并不会被添加到环境变量,也不建议直接把编译器添加到PATH。
    在开始菜单中可以看到专用的工具项,从这里启动就可以进入相应的cmd和powershell:

    为了简单快捷,可以自己在喜欢的位置创建一个空文件夹,里面编写一个setcl.bat内容如下(假设VS Build Tools安装到默认路径):
    1
    2
    @echo off
    "C:\Program Files (x86)\Microsoft Visual Studio\18\BuildTools\VC\Auxiliary\Build\vcvars64.bat"
    然后把这个文件夹添加进环境变量PATH,之后只要在任意位置运行setcl命令,就能等效于立即启动x64 Native Tools Command Prompt for VS

    一般都是在64位主机上编译目标为64位的程序,所以干脆直接启动这个,免得混淆。
    如果希望在命令行快捷启动其它的,可以按照开始菜单的启动项右键→打开文件位置→右键快捷方式→属性查看对应的启动项到底是在执行什么指令,然后用类似的方式搓成脚本。

    如果想要测试,可以编译一个示例,看看是否正常工作。示例代码来自Microsoft官方文档

    hello.c

    1
    2
    3
    4
    5
    6
    7
    #include <stdio.h>

    int main()
    {
    printf("Hello, World! This is a native C program compiled on the command line.\n");
    return 0;
    }
    1
    2
    cl hello.c
    hello.exe

    hello.cpp

    1
    2
    3
    4
    5
    6
    #include <iostream>
    using namespace std;
    int main()
    {
    cout << "Hello, world, from Microsoft C++!" << endl;
    }
    1
    2
    cl /EHsc hello.cpp
    hello.exe
  2. Cuda Toolkit: Cuda编译器
    前往NVIDIA Cuda Toolkit官网下载,安装的时候自定义组件仅选择RuntimeDevelopment两项即可:

    截至cuda 13.0 update 2版本,nvcc尚未官方支持vs2026。如果使用vs2026,会提示编译器不受支持,需要在编译时添加参数-allow-unsupported-compiler。可以使用环境变量把编译参数固定下来,NVCC_PREPEND_FLAGS将编译参数插入在其它参数的开头,NVCC_APPEND_FLAGS将编译参数追加在其它参数的末尾。

    安装完成后,同样可以编译一个示例测试一下。注意虽然nvcc直接添加进PATH了,但是仍然需要cl.exe提供C/C++编译器,所以仍然需要确保VS环境处于激活状态。

    hello.cu

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include <stdio.h>

    __global__ void hello_from_gpu ()
    {
    printf("Hello from GPU! \n");
    }

    int main (void)
    {
    hello_from_gpu<<<4,4>>>();
    cudaDeviceSynchronize();

    return 0;
    }

    编译后会输出16行”Hello from GPU!”

    1
    2
    nvcc hello.cu
    hello.exe
  3. cuDNN库:可能需要
    前往NVIDIA cuDNN官网,下载安装即可,可以在自定义里面选择是需要cuda13的版本还是cuda12的版本。

    虽然写的是12.9,但是对cuda12全兼容,如果cuda用了12.8也可以放心使用。

  4. 其它可选工具
    建议全局安装一个cmake和ninja,如果不安装也问题不大,pip里面也有这两个工具。
    1
    winget install Kitware.CMake Ninja-build.Ninja

编译记录

xformers

由于flash-attn2目前最后一个能在Windows上编译的版本是2.7.4,从2.8开始截止当前版本2.8.3在Windows上均会编译失败,因此xformers内置的flash-attn2在升级到2.8之后也无法在Windows上通过编译。
xformers最后一个绑定flash-attn2.7.4的版本是0.0.30,已知可以稳定配合pytorch2.7,因此如果官方包遇到兼容性问题(尤其是Blackwell GPU),自己编译一版0.0.30去配合torch2.7.1+cu128应该是个不错的选择。
从0.0.31开始,Windows上无法编译出含flash-attn2的xformers轮子。不是很建议尝试在旧xformers上强行为新版torch编译,适配大概率会比较差。
或者,编译一版不含flash attention的xformers,只使用mem eff优化也存在可行性,并且这样的话,编译所需时间会极大幅度缩短,内存压力也会极大幅度减小。即使没有fa2,单纯的xformers经测试也会比torch sdp更省显存。

  1. 获取源码:从github获取最新源码,或者从pypi获取指定版本的源码压缩包。

    这个commit开始,xformers主动提前适配了torch2.10nightly版本的API,弃用了对torch2.9版本的支持。
    因此,如果需要为torch2.9编译,那就不能直接连同submodules一起clone,而需要使用git checkout或者git reset --hard先切回旧版本:

    1
    2
    3
    git clone https://github.com/facebookresearch/xformers.git
    cd xformers
    git reset --hard 513e7a43aba20b22b6b52a32a5d17896ff0e2bd7

    然后再执行下文的git submodule update --init --recursive

    从github获取的时候要clone submodule:
    1
    git clone https://github.com/facebookresearch/xformers.git --recurse-submodules
    或者如果clone的时候忘记,那么进入xformers源码根目录下执行:
    1
    git submodule update --init --recursive
    对于pypi获取的压缩包,解压并且删除里面的xformers.egg-info文件夹。

    git在默认设置下使用Windows的旧版API,其不支持长路径,需要通过git config开启长路径支持:

    1
    git config --global core.longpaths true

    或者,如果有洁癖不想动全局配置,那就clone的时候不要--recursive-submodules,然后为仓库单独开启长路径之后再执行git submodule update
    如果没有开启长路径,然后clone期间出现Filename is too long报错,不要抱有任何侥幸心理,把源码文件夹整个删除,开启长路径支持之后再重新整个拉取,这是确保文件夹里的源码和预期一致的最稳妥的方法。

  2. 准备环境:建议使用venv虚拟环境,然后pip安装计划和xformers搭配的torch以及xformers的依赖numpy。如果前面没有安装全局的ninja,这里就一起安装一个,否则没有并行编译会纯纯龟速。
    与此同时,如果有用uv的习惯,那后面启动编译直接用uv就好(也可以pip install uv);或者用更官方一点的方式,pip install build setuptools wheel
  3. 微调setup.py(可选):
    • 首先咱不喜欢xformers在版本号里面记录编译日期;用git commit hash就足以指示编译的准确版本。因此删除开头的import datetime;然后定位到get_local_version_suffix()函数,修改:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
           def get_local_version_suffix() -> str:    
      if not (Path(__file__).parent / ".git").is_dir():
      # Most likely installing from a source distribution
      return ""
      - date_suffix = datetime.datetime.now().strftime("%Y%m%d")
      git_hash = subprocess.check_output(
      ["git", "rev-parse", "--short", "HEAD"], cwd=Path(__file__).parent
      ).decode("ascii")[:-1]
      - return f"+{git_hash}.d{date_suffix}"
      + return f"+{git_hash}"
    • 然后,由于flash attention v3仅支持A100,H100等计算卡,不支持Geforce游戏卡;计算卡要用也是在Linux上用,而Linux上既有满血的torch flash attn2也有xformers官方的满血fa3,因此Linux上自编译xformers的必要性也小些。所以修改源码直接屏蔽fa3编译:
      1
      2
      3
      4
           def get_flash_attention3_nvcc_archs_flags(cuda_version: int):
      + return []
      if os.getenv("XFORMERS_DISABLE_FLASH_ATTN", "0") != "0":
      return []
    • 下调nvcc threads:由于nvcc编译flash attn部分极其费内存,把nvcc threads调小降低内存压力:
      1
      2
      3
      4
      5
      6
      7
      8
               if cuda_version >= 1102:
      nvcc_flags += [
      "--threads",
      - "4",
      + "1",
      "--ptxas-options=-v",
      ]
      if sys.platform == "win32":
  4. 设置环境变量:
    • XFORMERS_DISABLE_FLASH_ATTN根据编译需求设置:
      设为0:开启xformers内置的flash-attn,包括fa2和fa3;此时这个选项仅是开启fa的必要条件,开启后上文屏蔽fa3的设置依旧有效;在高版本下编译fa2极大可能失败。
      设为1:直接禁用fa2和fa3,只编译最基础的xformers mem eff优化。
      对于旧版本xformers0.0.30,这个环境变量默认会取0;当前版本0.0.33已经改为默认取1
    • XFORMERS_PT_FLASH_ATTN设置为0
      Windows下pytorch根本没有编译flash attn组件,此选项让xformers编译自己打包的的flash attn,如果xformers版本高于0.0.30则不要开启,大概率会导致编译失败。
      如果上一个环境变量已经设为1禁用了flash attn,那么这个环境变量会被无视。
    • TORCH_CUDA_ARCH_LIST按以下规则设置:比较重要
      首先根据NVIDIA文档确定GPU与cuda arch版本号的关系。

      不在此表上的GPU已经不在cuda13的支持范围;如果需要在cuda12或者旧版本上为老显卡编译,参看NVIDIA文档

      然后确定编译目标:
      • 如果只想自用,那就只填自己的(例如RTX50系填12.0);
      • 如果想自己选择几代不同的架构,就用分号分隔(例如如果想同时支持RTX40和50系,填8.9;12.0);
      • 如果想搞成类似官方的泛用包,这里(在huggingface上)记录了一些xformers官方用过的环境变量可以照抄;
      • 如果不设置,xformers的默认行为会有所差异:flash attn2模块里面设定了一个默认列表,会根据cuda版本的不同启用不同的默认列表,然后将flash attn2的模块为列表中的所有架构编译;flash attn3模块则是检测本机是否是8.0(A100等)或者9.0(H100等),如果是,就针对本机架构编译,否就直接不编译。其它模块不确定,但是应该是针对本机架构编译。为了确保精准控制自己的需求,建议设置;
      • 如果手动设置的列表里面不含8.0和9.0,那么fa3模块会自动不启用,因此上文的手动屏蔽此时不再需要。
    • XFORMERS_PT_CUTLASS_ATTN可选设置,控制是否借用torch的cutlass的开关,设置为0禁用,默认启用。这个影响不大,不设保持默认行为也可,稍微节约一点点编译时间;设为0是模拟旧版本的行为
    • MAX_JOBS控制ninja的并行数:特别需要注意,因为xformers编译过程中,部分环节特别特别吃内存;而ninja的默认行为是把并行数直接开到CPU线程数+2,对于常规的消费级电脑,如果编译fa2,这个设置几乎一定会爆内存。
      作为参考,在fa2能通过编译的时候,咱自己的个人配置MAX_JOBS=2能不爆16GB内存,开到3就会开始触发大量虚拟内存交换,甚至会导致中断退出。根据自己的内存调整即可。咱测试的时候没动过nvcc threads,如果按照上文把nvcc threads降低,那有可能这个数值可以开高点,这样至少纯C++无CUDA的部分可以编译快点。
      如果选择不编译flash attention部分,在前面把nvcc threads减到1的前提下16G内存可以直接开8,编译很快就会完成。
    • NVCC_FLAGS:对于vs2026如果上文没有配置-allow-unsupported-compiler,xformers的编译程序接受这个环境变量作为追加编译参数,设置在这也是可以的。
  5. 启动编译:

    可以使用chcp 65001把输出切换到UTF-8编码,这样msvc编译器输出的中文不会乱码,可以更清晰地查看日志输出。

    导航到xformers源码的根路径,如果使用uv,就执行
    1
    uv build . --no-build-isolation
    如果使用build,在以下两种命令选一种;build的默认日志可能输出没那么多,如果缺少安全感就加个-v多看看日志刷屏
    1
    2
    python -m build . -n
    pyproject-build . -n
    注意上述命令的默认行为是,先把源码打包成源码包(sdist),就像pip的源码压缩包那样;然后对源码包执行编译。
    如果想直接只编译whl,那就额外添加--wheel参数。
    经过漫长的编译之后,产物会出现在dist文件夹,妥善保存。

    按照python现行规范,直接用python执行setup.py的行为都应当被替代:

    旧命令新命令
    python setup.py installpip install .
    python setup.py developpip install -e .
    python setup.py sdistpython setup.py build以及python setup.py bdist_wheelpython -m build

    其中后者会默认在TEMP目录下创建隔离的编译环境,视情况添加类似--no-build-isolation的参数改变这个行为。

上游flash-attn可能要注意的

额外提一下编译flash-attn可能需要注意的事项,和编译xformers无关,编译xformers不用看本节。

llama-cpp-python

onnxruntime-gpu


一些编译cuda的笔记
http://silvertuanzi.github.io/2025/12/03/nvcc-notes/
作者
silver-lasombra
发布于
2025年12月3日
许可协议