Windows 下 Neovim 的 nvim.treesitter 插件无法加载 yaml 模块

Windows 下使用 LazyVim 配置的 Neovim 打开 YAML 文件报错:

Error detected while processing BufReadPost Autocommands for "*":
Error executing lua callback: ...ocal/apps/neovim/current/share/nvim/runtime/filetype.lua:21: Error executing lua: ...ocal/apps/neovim/current/share/nvim/runtime/filetype.lua:22: BufReadPost Autocommands for "*"..FileType Autocommands for "*": Vim(append):Error executing lua callback: Failed to load parser for language 'yaml': uv_dlopen: The specified procedure could not be found.

stack traceback:
        [C]: in function '_ts_add_language'
        ...rrent/share/nvim/runtime/lua/vim/treesitter/language.lua:99: in function 'add'
        ...t/share/nvim/runtime/lua/vim/treesitter/languagetree.lua:98: in function 'new'
        ...neovim/current/share/nvim/runtime/lua/vim/treesitter.lua:61: in function '_create_parser'
        ...neovim/current/share/nvim/runtime/lua/vim/treesitter.lua:131: in function 'get_parser'
        ...neovim/current/share/nvim/runtime/lua/vim/treesitter.lua:459: in function 'start'
        ...a/lazy/nvim-treesitter/lua/nvim-treesitter/highlight.lua:20: in function 'attach'
        ...ata/lazy/nvim-treesitter/lua/nvim-treesitter/configs.lua:509: in function 'attach_module'
        ...ata/lazy/nvim-treesitter/lua/nvim-treesitter/configs.lua:532: in function 'reattach_module'
        ...ata/lazy/nvim-treesitter/lua/nvim-treesitter/configs.lua:133: in function <...ata/lazy/nvim-treesitter/lua/nvim-treesitter/configs.lua:132>
        [C]: in function 'nvim_cmd'
        ...ocal/apps/neovim/current/share/nvim/runtime/filetype.lua:22: in function <...ocal/apps/neovim/current/share/nvim/runtime/filetype.lua:21>
        [C]: in function 'nvim_buf_call'
        ...ocal/apps/neovim/current/share/nvim/runtime/filetype.lua:21: in function <...ocal/apps/neovim/current/share/nvim/runtime/filetype.lua:10>
stack traceback:
        [C]: in function 'nvim_cmd'
        ...ocal/apps/neovim/current/share/nvim/runtime/filetype.lua:22: in function <...ocal/apps/neovim/current/share/nvim/runtime/filetype.lua:21>
        [C]: in function 'nvim_buf_call'
        ...ocal/apps/neovim/current/share/nvim/runtime/filetype.lua:21: in function <...ocal/apps/neovim/current/share/nvim/runtime/filetype.lua:10>
stack traceback:
        [C]: in function 'nvim_buf_call'
        ...ocal/apps/neovim/current/share/nvim/runtime/filetype.lua:21: in function <...ocal/apps/neovim/current/share/nvim/runtime/filetype.lua:10>

此前已使用 :TSInstall yaml 命令安装了 nvim.treesitter 插件的 YAML 解析模块。运行 :checkhealth nvim-treesitter 命令检查,发现如下问题:

The following errors have been detected: ~
- ERROR yaml(highlights): Failed to load parser for language 'yaml': uv_dlopen: The specified procedure could not be found.
  
  yaml(highlights) is concatenated from the following files:
  | [ERROR]:"C:\Users\fournoas\AppData\Local\nvim-data\lazy\nvim-treesitter\queries\yaml\highlights.scm", failed to load: Failed to load parser for language 'yaml': uv_dlopen: The specified procedure could not be found.
- ERROR yaml(locals): Failed to load parser for language 'yaml': uv_dlopen: The specified procedure could not be found.
  
  yaml(locals) is concatenated from the following files:
  | [ERROR]:"C:\Users\fournoas\AppData\Local\nvim-data\lazy\nvim-treesitter\queries\yaml\locals.scm", failed to load: Failed to load parser for language 'yaml': uv_dlopen: The specified procedure could not be found.
- ERROR yaml(folds): Failed to load parser for language 'yaml': uv_dlopen: The specified procedure could not be found.
  
  yaml(folds) is concatenated from the following files:
  | [ERROR]:"C:\Users\fournoas\AppData\Local\nvim-data\lazy\nvim-treesitter\queries\yaml\folds.scm", failed to load: Failed to load parser for language 'yaml': uv_dlopen: The specified procedure could not be found.
- ERROR yaml(indents): Failed to load parser for language 'yaml': uv_dlopen: The specified procedure could not be found.
  
  yaml(indents) is concatenated from the following files:
  | [ERROR]:"C:\Users\fournoas\AppData\Local\nvim-data\lazy\nvim-treesitter\queries\yaml\indents.scm", failed to load: Failed to load parser for language 'yaml': uv_dlopen: The specified procedure could not be found.
- ERROR yaml(injections): Failed to load parser for language 'yaml': uv_dlopen: The specified procedure could not be found.
  
  yaml(injections) is concatenated from the following files:
  | [ERROR]:"C:\Users\fournoas\AppData\Local\nvim-data\lazy\nvim-treesitter\queries\yaml\injections.scm", failed to load: Failed to load parser for language 'yaml': uv_dlopen: The specified procedure could not be found.

按照插件官方文档的解决方法,只要将默认编译器改成 clang 就可以了。而目前使用的编译器是 gcc 。

退出 Neovim 进程,删除 %LOCALAPPDATA%\nvim-data\lazy\nvim-treesitter\parser\yaml.so 文件,安装 LLVM 并设置环境变量,将默认编译器设置为 clang :

POWERSHELLscoop install llvm
$env:CC="clang"

重新启动 Neovim 会自动安装 YAML 模块,也可以通过命令 :TSInstall yaml 手动安装。安装完毕后,用 :checkhealth 命令再次检查,发现 YAML 模块已经成功被加载。

观察了一下 gcc 和 clang 编译的 yaml.so 文件的区别发现, gcc 编译的文件小,并且动态链接了 libstdc++-6.dll 动态链接库;而 clang 编译的文件大,并没有链接 libstdc++-6.dll 动态链接库,应该是静态链接了标准库。猜测发生 The specified procedure could not be found. 错误的原因是因为 yaml.so 载入动态链接库 libstdc++-6.dll 失败导致的。而其他模块编译不出错的原因是,那些项目都是纯 C 语言编写的,而 yaml 模块是 C++ 编写的。