emacs-rime 在 windows 下无法加载模块,但从 msys2 环境启动可以

问题如标题所言,按照 emacs-rime/INSTALLATION.org基于 msys2 安装 Emacs-rime 中写的步骤安装了 emacs-rime,并且在 msys2 环境内编译 emacs-rime.dll 成功并且可以正常使用。不过这两篇教程中说,如此之后即使不从 msys2 环境中启动,也应该可以使用 emacs-rime。而我在使用不从 msys2 中启动的 Emacs 并调用 toggle-input-method 时,会提示:

rime--load-dynamic-module: Module could not be opened: "c:/Users/ASUS/.emacs.d/lib/rime/librime-emacs.dll", "找不到指定的程序。"

(题外话,这里的提示信息还是 GBK 编码的八进制字符串,用 decode-coding-string 解码才得到结果,看来编码在 Emacs 中也是复杂的问题)

经过我一番排查,发现即使用 emacs -Q 启动并且直接执行 (load-file rime--module-path) 甚至 (load rime--module-path nil nil t) 也会报错,而这就很奇怪,因为模块就在那里(rime--module-path 的值也是对的)。希望有了解的道友可以解惑。

参考这个:

直接从win启动时,emacs不会继承msys2的path,甚至找不到同目录下的dll。有两种方法可以解决:1. 把msys2的相关bin目录加入win的PATH 2. 把msys2的相关bin目录加入emacs的exec-path。 方法2可以避免PATH污染。

举个例子:

(let ((msys2root  "c:\\msys2\\"))
         (setenv "PATH" (concat
                         msys2root "mingw64\\libexec\\emacs\\28.0.50\\x86_64-w64-mingw32" ";"
                         msys2root "mingw64\\bin" ";"
                         msys2root "usr\\bin" ";"
                         (getenv "PATH")))
         ;;without this the new added $PATH value won't be inherite by exec-path
         (setq exec-path (split-string (getenv "PATH") path-separator)))

多谢两位!不过我的 Path 变量里似乎已经有 msys2 mingw64 的 bin 目录了:

$ echo $PATH | tr ':' '\n' # msys2
/mingw64/bin
...
$ $Env:Path -split ';' # PowerShell
C:\msys64\mingw64\bin
...

你的dll文件目前在"c:/Users/ASUS/.emacs.d/lib/rime/librime-emacs.dll",看下exec-pathload-path里面有没有这个文件的folder,或者干脆把这个dll复制到msys64/bin里面去。

可能有些依赖的动态库并不在 bin 目录 ? 还是用 ldd 看一下依赖吧

可以确定的是和这个应该无关,因为我setq这两个变量到和msys环境内的emacs一样也还是一样。

问题解决:只需要让 msys/bin 在 Path 变量中的顺位排得足够高。比如,调成顺序第一就不会出问题。经过二分排查,发现只需要排在 neovim 的前面就不会有问题。于是打开 neovim 所在的文件夹,发现原来里面有一些与 librime-emacs.dll 依赖的 dll 同名的 dll。也就是说,需要的 dll 被它们覆盖了,所以加载失败。

出现这个问题的根本原因其实应该是自己的 Path 清理不及时(因为装过许多软件和兼容环境,导致我的 Path 项目众多极其混乱)。