← 笔记

CMake 的 set(CACHE ... FORCE) 会覆盖命令行 -D:-DGGML_CUDA=ON 永远不生效

约 2 分钟#CMake#C++#Autarkia

带 FORCE 的 set(... CACHE ...) 每次 configure 都覆盖缓存,命令行 -D 传进来的值也一起覆盖。CMakeLists 里一行注释写着「默认关闭」的 FORCE,让 llama.cpp 在 Windows 上一直编成 CPU 版,没有报错,只是慢。

CMake 里 set(VAR value CACHE BOOL "" FORCE) 每次 configure 都会覆盖缓存里的值,命令行用 -D 传进来的也一起覆盖。想要「默认关、可以从命令行打开」,应该用不带 FORCE 的 set(... CACHE ...),或者 option()。

8 月 19 日,Autarkia 的 C++ 调度器做 GPU 推理时首 token 超时。我先怀疑的是虚拟环境,最后在 llama.cpp 的启动日志里看到两行:backend_ptrs.size()=1,KV cache 全部 dev=CPU。加载进来的扩展根本不带 CUDA。

cmake
# Windows 侧 CUDA 编译有兼容性问题,默认关闭
if(WIN32)
    set(LLAMA_CUDA OFF CACHE BOOL "" FORCE)
    set(GGML_CUDA OFF CACHE BOOL "" FORCE)
endif()

这段是 1 月留下的。当时 Windows 上 nvcc 碰到带空格的项目路径会报错,就先把 CUDA 关了。注释写的是「默认关闭」,但 FORCE 的意思是每次 configure 都覆盖缓存里的值,命令行 -D 传进来的也一起覆盖。所以它不是默认值,是强制值:在 Windows 上不管怎么传参数,编出来的都是 CPU 版。

三种写法在命令行传 -DGGML_CUDA=ON 时的结果:

cmake
set(GGML_CUDA OFF CACHE BOOL "" FORCE)   # -> OFF
set(GGML_CUDA OFF CACHE BOOL "")         # -> ON
option(GGML_CUDA "build with CUDA" OFF)  # -> ON(不传参数时是 OFF)

它藏得住,是因为编出来的东西能用:扩展能导入,日志写着找到了 scheduler_py,推理也有结果,只是慢。1 月之后「Windows 上 CUDA 有问题」已经是默认的认识,CPU 版看起来就是预期。能说明问题的只有那两行设备日志,它们不像异常,没人会多看一眼。

改法是把强制改成真正的默认:外面包一层 if(NOT DEFINED GGML_CUDA),命令行传了就听命令行的。更直白的写法是直接用 option()。另外加了一个脚本专门编 CUDA 版,放在单独的目录里,启动时可以用环境变量选后端。

还剩一处:现在挑后端是看目录名,build/cuda/ 存在就当它是 CUDA 版,加载之后没有核对。我打算在加载完扩展后打一行实际可用的后端,配置要求上 GPU 却只有 CPU 后端时直接报警告。