Windows/MSVC: llama-server link fails with LNK2001 unresolved external “__” after #28091 (WINDOWS_EXPORT_ALL_SYMBOLS + PCH)

该报错发生在 Windows + MSVC 下编译 llama-server 时,链接阶段生成 llama-server-impl.dll 失败;核心原因是同一 target 上同时启用了 WINDOWS_EXPORT_ALL_SYMBOLS 和 target_precompile_headers

快速结论:该报错发生在 Windows + MSVC 下编译 llama-server 时,链接阶段生成 llama-server-impl.dll 失败;核心原因是同一 target 上同时启用了 WINDOWS_EXPORT_ALL_SYMBOLStarget_precompile_headers(PCH),导出符号时把 MSVC 内部的 PCH 记账符号当成普通符号导出。优先排查 PCH 与共享库导出配置的组合。

适用环境:Windows 11 原生(非 WSL)、MSVC toolset 14.44.35207(cl 19.44.35228)、CMake 4.3.2、Ninja、CUDA 13.1、RTX 3090,配置为 -DGGML_CUDA=ON -DCMAKE_CUDA_ARCHITECTURES=86-real;受影响模块为 llama-server。

最快修复方案:Issue 中已验证的临时规避方案是配置时关闭预编译头:cmake -B build -DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON。后续修复方向(Issue 评论中提出并由维护者确认可复现、已开 PR)是在 MSVC 共享库构建下对 server-context 与 llama-server-impl 两个 target 不启用 PCH。

注意事项:关闭 PCH 会放弃 #28091 带来的 Windows 构建时间收益,但对生成二进制的行为没有影响;Issue 作者已验证相同模型、相同参数下行为一致。评论区给出的 CMake 补丁在 Issue 中属于建议方案,作者表示未实测补丁,最终以官方合并的 PR 为准。

问题场景

在 Windows 原生环境下使用 MSVC 与 Ninja 构建 llama-server。编译阶段全部通过,链接阶段生成 llama-server-impl.dll 时报 LNK2001 / LNK1120。触发条件是在 #28091 合并之后,tools/server/CMakeLists.txt 中两个 target 同时具备以下配置:

  • target_precompile_headers(${TARGET} PRIVATE ${CMAKE_SOURCE_DIR}/common/common.h)(#28091 新增)
  • set_target_properties(${TARGET} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON)(原有配置)

报错原文

exports.def : warning LNK4022: no unique match for symbol "__"
exports.def : warning LNK4002: __@@_PchSym_@00@UooznzRnzhgviUyfrowUgllohUhvieviUxnzpvurovhUhvieviRxlmgvcgOwriUxnzpvPkxsOxccOlyq@4B2008FD98C1DD4
              is defined in "tools\server\CMakeFiles\server-context.dir\cmake_pch.cxx.obj"
exports.def : warning LNK4002: __@@_PchSym_@00@UooznzRnzhgviUyfrowUgllohUhvieviUxnzpvurovhUooznzRhvieviRrnkoOwriUxnzpvPkxsOxccOlyq@4B2008FD98C1DD4
              is defined in "tools\server\CMakeFiles\llama-server-impl.dir\cmake_pch.cxx.obj"
exports.def : error LNK2001: unresolved external symbol "__"
tools\server\llama-server-impl.lib : fatal error LNK1120: 1 unresolved externals

原因分析

最可能的原因是 CMake 两个特性在 MSVC 下互不兼容:WINDOWS_EXPORT_ALL_SYMBOLS 会让 CMake 把 target 中每个 object 文件的符号都写入自动生成的 exports.def,而启用 PCH 后该 target 会多出一个 cmake_pch.cxx.obj。MSVC 在该对象文件中带有形如 __@@_PchSym_@00@… 的内部记账符号,这些符号没有可链接的实际定义,被导出后即表现为 unresolved external symbol "__"。Issue 作者同时指出,这一组合在 #28091 之后才在此仓库中变得可达;该问题本身属于两个 CMake 特性之间的已知不兼容,而非仓库特有的逻辑错误。

环境排查

  • 操作系统:确认是否为 Windows 原生而非 WSL。
  • 编译器:确认是否为 MSVC,Issue 中为 MSVC toolset 14.44.35207(cl 19.44.35228)。
  • 构建工具:确认 CMake 版本(Issue 中为 4.3.2)与生成器(Ninja)。
  • CUDA:确认 CUDA 版本(Issue 中为 13.1)及 CMAKE_CUDA_ARCHITECTURES 设置(Issue 中为 86-real)。
  • 提交版本:确认是否位于 #28091 之后的提交(Issue 中为 5bda51b),该提交引入了 PCH 相关改动。
  • 构建配置:确认目标是否使用了 WINDOWS_EXPORT_ALL_SYMBOLStarget_precompile_headers 的组合。

解决步骤

  1. 先按 Issue 中已验证的规避方式重新配置构建:cmake -B build -DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON,然后重新执行 cmake --build build --target llama-server -j 10
  2. 若需要保留 PCH 的构建时间收益,可优先尝试在 MSVC 共享库构建下对 server-contextllama-server-impl 两个 target 关闭 PCH,仅在非 MSVC 或非共享库场景启用。评论区给出的补丁思路为:定义 LLAMA_SERVER_PCH 变量,若 BUILD_SHARED_LIBS 为真且 CMAKE_CXX_COMPILER_IDMSVC 则置为 OFF,并用 if (LLAMA_SERVER_PCH) 包裹两处 target_precompile_headers 调用。
  3. 若不希望修改本地 CMake,也可等待官方合并针对该问题的 PR 后同步上游更新。
  4. 修改后清理构建目录并重新配置、编译,避免旧的 exports.def 与 PCH 对象残留影响判断。

验证方法

重新编译后确认 llama-server 已完成链接并生成可执行文件,运行 .\build\bin\llama-server.exe --version 能正常输出版本信息,链接阶段不再出现 LNK4022LNK4002LNK2001LNK1120。Issue 作者同时验证了关闭 PCH 后二进制行为一致,可通过相同模型与相同参数对比解码速度来确认无异常。

参考来源

ggml-org/llama.cpp #28758

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 22955

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注