Windows 上的 UCRT 的编译问题似乎解决了

成功倒是成功了,不过算是比较 hack,毕竟 Emacs 没有专门提供 Windows 上的 clang 编译支持:

和 ucrt64 和 mingw64 相比,基础步骤没区别:

pacman -Syu
pacman -S git
pacman -S texinfo
git config --global core.autocrlf false
git clone https://github.com/emacs-mirror/emacs --depth 1

安装软件时要装 clang 和 ncurses:

pacman -S "${MINGW_PACKAGE_PREFIX}-autotools"
pacman -S "${MINGW_PACKAGE_PREFIX}-clang"
pacman -S "${MINGW_PACKAGE_PREFIX}-gnutls"
pacman -S "${MINGW_PACKAGE_PREFIX}-make"
pacman -S "${MINGW_PACKAGE_PREFIX}-ncurses"

配置步骤也有些变化,需要指定编译器和 host:

./autogen.sh
./configure --with-native-compilation=no --host=x86_64-w64-mingw32 CC=clang
make -j20

到了这一步编译时,会出现如下错误(照理说 Mingw-w64 是实现了 nanosleep 的):

一种解决方法是注释掉 nt/gnulib-cfg.mk 里面的这两行:

然后编译就可以成功了:

但这个解决办法挺抽象的,应该有更好的方法,而且我也不知道实际用起来怎么样。(sys_select 在 w32proc.c 里面实现了,但不注释掉 sys_select 那一行会编译失败)


更新,在 ucrt64 环境下安装 pacman -S mingw-w64-ucrt-x86_64-clang 然后:

./configure --with-native-compilation=no CC=clang
make -j20

能够直接成功,没有 CLANG64 中出现的错误,这可能是因为只用了编译器,库环境还是 ucrt64:

* While there also exists a Clang package in the MINGW environments, that one still uses the GNU linker and the GNU C++ library. In some cases Clang is used to build packages as well there, in case upstream prefers Clang over GCC for example.

Environments - MSYS2

image


同样是 ucrt64 环境,gcc 和 clang 编译最后得到的 emacs.exe 体积差距似乎有点大…

GNU ELPA - elisp-benchmarks 试了一下,似乎是没什么区别:

测试方法是下载 elisp-benchmarks,解压然后添加路径到 load-path 里面,然后执行以下命令:

(setq gc-cons-threshold (* 1024 1024)) ;; 1MB
(elisp-benchmarks-run nil nil)
  • CPU: AMD Ryzen 5 7640HS, RAM: 32GB
  • OS: Windows 11 23H2 22631.4037
  • emacs-mirror/emacs@4f1987c
  • gcc.exe (Rev1, Built by MSYS2 project) 14.2.0
  • “GNU Emacs 31.0.50 (build 1, x86_64-w64-mingw32) of 2024-08-18”

UCRT 环境编译的 Emacs 得到如下结果:

* Results

  | test               | non-gc avg (s) | gc avg (s) | gcs avg | tot avg (s) | tot avg err (s) |
  |--------------------+----------------+------------+---------+-------------+-----------------|
  | bubble             |           3.13 |       6.00 |     426 |        9.13 |            0.08 |
  | bubble-no-cons     |           8.46 |       0.05 |       3 |        8.51 |            0.03 |
  | bytecomp           |           2.81 |       1.99 |     127 |        4.80 |            0.04 |
  | dhrystone          |           3.37 |       0.00 |       0 |        3.37 |            0.11 |
  | eieio              |           1.49 |       2.36 |     161 |        3.85 |            0.12 |
  | fibn               |           2.09 |       0.00 |       0 |        2.09 |            0.03 |
  | fibn-named-let     |           2.58 |       0.00 |       0 |        2.58 |            0.10 |
  | fibn-rec           |           2.78 |       0.00 |       0 |        2.78 |            0.12 |
  | fibn-tc            |           2.62 |       0.00 |       0 |        2.62 |            0.03 |
  | flet               |           6.78 |       0.00 |       0 |        6.78 |            0.02 |
  | font-lock          |           0.63 |       0.44 |      29 |        1.06 |            0.03 |
  | inclist            |          10.67 |       0.00 |       0 |       10.67 |            0.11 |
  | inclist-type-hints |          10.70 |       0.00 |       0 |       10.70 |            0.09 |
  | listlen-tc         |           2.61 |       0.00 |       0 |        2.61 |            0.03 |
  | map-closure        |           5.53 |       0.00 |       0 |        5.53 |            0.03 |
  | nbody              |           2.42 |      10.91 |     768 |       13.33 |            0.04 |
  | pack-unpack        |           0.34 |       0.61 |      42 |        0.95 |            0.01 |
  | pack-unpack-old    |           1.02 |       1.12 |      78 |        2.14 |            0.02 |
  | pcase              |           5.58 |       0.00 |       0 |        5.58 |            0.15 |
  | pidigits           |           4.65 |       7.67 |     390 |       12.32 |            0.55 |
  | scroll             |           0.00 |       0.00 |       0 |        0.00 |            0.00 |
  | smie               |           1.32 |       0.74 |      45 |        2.06 |            0.04 |
  |--------------------+----------------+------------+---------+-------------+-----------------|
  | total              |          81.57 |      31.88 |    2070 |      113.44 |            0.65 |

MINGW64 环境编译的 Emacs 得到如下结果:

* Results 

  | test               | non-gc avg (s) | gc avg (s) | gcs avg | tot avg (s) | tot avg err (s) |
  |--------------------+----------------+------------+---------+-------------+-----------------|
  | bubble             |           3.08 |       5.41 |     368 |        8.49 |            0.17 |
  | bubble-no-cons     |           8.44 |       0.05 |       3 |        8.49 |            0.16 |
  | bytecomp           |           2.77 |       1.83 |     113 |        4.60 |            0.08 |
  | dhrystone          |           3.40 |       0.00 |       0 |        3.40 |            0.13 |
  | eieio              |           1.44 |       2.11 |     144 |        3.56 |            0.04 |
  | fibn               |           2.10 |       0.00 |       0 |        2.10 |            0.14 |
  | fibn-named-let     |           2.54 |       0.00 |       0 |        2.54 |            0.14 |
  | fibn-rec           |           2.83 |       0.00 |       0 |        2.83 |            0.03 |
  | fibn-tc            |           2.64 |       0.00 |       0 |        2.64 |            0.01 |
  | flet               |           6.92 |       0.00 |       0 |        6.92 |            0.02 |
  | font-lock          |           0.64 |       0.42 |      27 |        1.06 |            0.01 |
  | inclist            |          10.76 |       0.00 |       0 |       10.76 |            0.22 |
  | inclist-type-hints |          10.61 |       0.00 |       0 |       10.61 |            0.08 |
  | listlen-tc         |           2.61 |       0.00 |       0 |        2.61 |            0.03 |
  | map-closure        |           5.56 |       0.00 |       0 |        5.56 |            0.08 |
  | nbody              |           2.50 |      10.16 |     686 |       12.66 |            0.08 |
  | pack-unpack        |           0.34 |       0.56 |      37 |        0.90 |            0.01 |
  | pack-unpack-old    |           1.03 |       1.07 |      70 |        2.10 |            0.01 |
  | pcase              |           5.61 |       0.00 |       0 |        5.61 |            0.16 |
  | pidigits           |           5.02 |       7.29 |     348 |       12.31 |            1.11 |
  | scroll             |           0.00 |       0.00 |       0 |        0.00 |            0.00 |
  | smie               |           1.48 |       0.74 |      41 |        2.22 |            0.04 |
  |--------------------+----------------+------------+---------+-------------+-----------------|
  | total              |          82.32 |      29.64 |    1837 |      111.96 |            1.20 |

关键的统计数据就是最后的两行

;; UCRT
| total              |          81.57 |      31.88 |    2070 |      113.44 |            0.65 |
;; MSVCRT
| total              |          82.32 |      29.64 |    1837 |      111.96 |            1.20 |

可能就性能测试上来说,UCRT 和 MSVCRT 没什么太大的区别…

另外,我顺便测了下 29.2 和 31.0.50 的 fib,Emacs 30 的 GC 似乎提升不少,但是解释性能似乎不如 29(不过这个测试并没什么说服力,太简单了)

(progn
  (defun fib (n)
    (pcase n
      (0 0)
      (1 1)
      (_ (+ (fib (1- n)) (fib (- n 2))))))
  (setq gc-cons-threshold (* 1024 1024))
  (let ((res))
    (push (benchmark-run 100 (fib 25)) res)
    (byte-compile 'fib)
    (push (benchmark-run 1000 (fib 25)) res)
    (reverse res)))

在 29.2 和 31.0.50 下分别有如下结果:

;; 29.2
((15.779528 145 9.951868000000005) (6.902092000000001 0 0.0))
;; 31.0.50
((12.034346 741 6.412244000000001) (8.215974000000001 0 0.0))

(注:如果要用 elisp-benchmarks 测的话,最好每跑一次就重启一下 runemacs.exe -Q)

这个提升应该就是 30 的 GC 改进带来的,从上面的测试来看,同样的代码,GC 的次数变多但是总时间下降了,和运行时的改变没太大关系。

2 个赞

为啥要这个,不用终端版本可以不装么?

性能差不多我估计是因为跑字节码没有多少系统调用,比不出来很正常

在 clang64 环境下,没有装似乎没办法通过编译。

可以试试不装这个,然后根据 configure 的输出装其他的。

编译了一份 ucrt+native comp 出来,体感确实比 29.2 好不少

4 个赞

今天重新体验了一下,是要快一些。
用scoop安装,不要装emacs-k,emacs-k安装到C:\Program Files\WindowsApps目录。
建议装emacs-kl,emacs-kl安装在scoop目录下。速度比emacs-k更快,我也不知道为啥。

scoop install emacs-kl

对,但全面的测试有点难搞,我就借 native-comp 作者的 benchmark 随便跑跑了。

Windows app是运行在受控环境中,性能会差些,安全性更好。emacs-kl 就是原生exe,性能更好。

1 个赞

用 UCRT64 版本两天了,几个问题:

  • native-compile 离开了 MSYS2 环境用不了,以前也有人提过,这也是为什么 GNU 分发的不开这个
  • 同样原因,出了 MSYS2 Emacs 就找不到 gnutls,不影响启动,但比如 melpa 用不了,还好 gnu 和 nognu 都不用 https
  • 如果把自帯的包 native-compile 了,不关 Windows Defender 启动会更慢

这个我之前看日本有些博客折腾过,是可以的,只不过比较麻烦。让官方编译的 Windows 版 Emacs 29.2 的 native-comp 特性生效

这个得像官方提供的预编译版本一样,把 Emacs.exe 要用到的 dll 库全都放到 Emacs 安装(也就是 make install 的那个目录)目录的 bin 下,也得一个一个弄很麻烦。

Windows Defender 算是 Emacs 在 Windows 上慢的一个很大原因,不管是编译还是运行。

看来得写一个辅助工具,递归检查 exe 和 dll 依赖的 dll 了。:fearful:

没办法,Windows 不装杀毒软件就等于给黑客当筛子。

那 Linux 为啥不需要装?

kiennq最近编译出来emacs.exe真是小呀

1 个赞

这个问题讨论得很多嘛。随便说几个,一,大部分 linux 软件是从可信任的包管理器安装的,而 Windows 软件不是。二,linux 软件大多都是开源的,开源多少能增加软件代码被人审查的机会。三,不像 Windows 软件大多拥有全盘的访问权限,linux 有手段可以严格限制一个软件访问哪些目录。还有很多原因,也有一些是劣势。其中最关键的大概是很少有不安全源下载的软件这一点了。

2 个赞

linug入手门槛比windows高,并且linux大多数情况下都是使用包管理器安装,windows用户更倾向于去网站下载exe,另外就是系统文件权限的问题,windows下的管理员权限被滥用也不是一天两天的了

好奇怪啊,上面的那个构建我使用就莫名其妙的高CPU,用你说的这个就正常,而且速度确实提升不少

主要原因还是因为 linux 的用户水平大部分都比较高,不会像小白那样随便找个 exe 不管三七二十一直接双击运行。要是 linux 成了主流的桌面系统,然后到处都是闭源野包不知道哪里来的 deb 满天飞,那一样安全性是个问题。

没那么麻烦,用 Process Explorer - Sysinternals 很容易就能找到 EXE 加载了什么 dll:

打开 Process Explorer 之后可以打开 Lower Pane(菜单 View → Show Lower Pane 或者 Ctrl + L),然后在上面选中 Emacs.exe 即可。或者使用菜单里面的 Find 然后搜索 emacs。

3 个赞

这个是检查正在运行的 Process,看起来应该比 ldd 效果更好。

我找找它有没有 CLI 接口,如果有的话就可以方便地集成进打包脚本和 CI/CD 里了。


找到了:


P.S. 这个工具的作者好像现在是 Azure 的 CTO 吧?

1 个赞

对对,这是一个重要原因。我只是举些例子~ 覆盖不全还望海纳。