Emacs 29 升级指南

Emacs 29发布了,比较吸引我的新特性是treesitter、sqlite、svg的原生支持。虽然并没有特别迫切的需求,但还是忍不住想升级一下。以往都是直接下载 emacsformacosx 编译好的版本,这次发现没有native compile特性,非常慢。所以这次干脆自己编译了,还可以灵活选择需要的特性。

build-emacs-for-macos

首先尝试了build-emacs-for-macos这个辅助编译的脚本,它会帮你安装需要的依赖,编译过程还算顺利。但是发现它编译出来的emacs有点诡异。

打开Emacs后,会提示几个包的代码有些问题,这在我的预期之内。升级完Emacs,已经安装过的包最好都升级一下,或者删掉重装。因为老版本的emacs生成的elc文件,新版本不一定能兼容,就会出现各种奇奇怪怪的问题。

把有问题的包升级完,再重启emacs,问题依然存在。这就不符合预期了。索性把所有安装的包全部删掉,再重新安装。这样操作之后,再启动Emacs,看起来好像没问题了。

用了几天之后,诡异的问题又来了。有些包又有新版本,升级完重启后,发现依然使用老版本的,新版本被标记为obsolete。比如上面的doom-modeline,明明 20230819.1826 这个才是新版本,但生效的却是 20230815.230 。这个问题浪费了很多时间,我都开始看package.el代码,怀疑是不是Emacs 29本身带来了什么问题。

通过源码编译

package.el的代码实在太长了,很难找到问题原因。要不要尝试一下用源码直接编译呢?

拉一下代码:

$ git clone https://github.com/emacs-mirror/emacs.git

切换到29.1 tag:

$ git fetch --all --tags
$ git checkout tags/emacs-29.1 -b emacs-29.1

生成configure脚本:

$ ./autogen.sh

执行configure,选择需要编译的特性:

$ ./configure --with-native-compilation=aot --with-tree-sitter \
  --with-gif --with-png --with-jpeg --with-rsvg --with-tiff \
  --with-imagemagick --with-x-toolkit=gtk3 --with-xwidgets \
  --with-ns --with-sqlite3

编译并且生成mac app:

$ make
$ make install

生成的app在nextstep目录下面,直接打开就可以运行,可以移动到Applications文件夹下。

惊喜的发现,这么编译出来的Emacs没有上面的包版本问题。原本以为使用build-emacs-for-macos会节省很多时间,但结果恰恰相反,直接使用源码编译反而是最简单的。很多认为会带来便利的辅助环节,实际上会浪费更多时间和精力,所以最好是跳过它们。

一闪而过的eldoc

因为经常写emacs lisp,eldoc是必不可少的包。它可以在下面展示出光标所在函数的signature。

升级29之后,eldoc变成这样了:

eldoc一闪而过,我还没来得及看就没了,非常影响体验。难道是eldoc改动带来的问题?为了找到这个问题的原因,首先想用 --debug-init 启动emacs,看是不是自己的配置带来的问题,但是这个参数不管用。

那只能手动改配置重启了,当把配置去掉之后,就没这个问题了。因此可以确定问题出在配置的代码里面。但这个配置有3000多行,怎么才能找到是哪一段带来的问题呢?这时候二分查找就派上用场了。最后很快就定位到了原因,我配置了modalka的hook,在切换modalka状态时自动切换回之前的输入法。就是这段hook导致的问题。

为什么之前的版本没问题呢?这就要到eldoc的代码中找找答案了。发现在这个 commit 中,eldoc使用了 special-mode

这就很好理解了,special-mode是个major mode,在启动的时候就会调用modalka hook。解决的方案很简单,把special-mode排除在modalka之外就好了。

(add-to-list 'modalka-excluded-modes 'special-mode)