用 GitHub Actions 每日于 macOS 构建的静态链接外部依赖的 Emacs

跟 jimeh/build-emacs-for-macos 和 caldwell/build-emacs 最大的区别就是它静态链接所有外部依赖:

至于怎么在 macOS 上静态链接,最好的方法就是不装 .dylib,那就不能用包管理器,自己从上游 fetch source 然后再自己编译(Gentoo 正统在 macOS),大概就这样

几个踩的坑:

很坑的一点就是 GitHub Actions 自带了愚蠢的 Homebrew,然后 Homebrew 应该是自带了 gettext 和 GnuTLS。前天晚上当编译仙人的时候看到产物里链接了一个 Homebrew 的 GnuTLS 动态库差点没给我气死(

提供一个请 Homebrew 离开的脚本:

curl -O https://raw.githubusercontent.com/Homebrew/install/HEAD/uninstall.sh
sudo chmod +x uninstall.sh
sudo env NONINTERACTIVE=1 ./uninstall.sh
sudo rm -rf /opt/homebrew
export PATH=''
eval $(/usr/libexec/path_helper -s)

然后就是因为 Emacs 是不支持静态编译的,但是它使用 pkg-config,所以如果需要的库只存在 .a 的静态库,只需要把 pkg-config 加上 --static 的旗标就可以静态编译了

./configure PKG_CONFIG='pkg-config --static'

然后就是 libncurses,应该是在 macOS 上提供 tput 函数的。但是因为 macOS 自带了 libncurses(好像是 5.4 版本)的动态库,所以 clang 会优先链接动态库,然后因为 SIP 我们还拿它没办法,就比较无解。我是通过 libncursesw 解决的(wide-char 版本):

curl -O https://ftp.gnu.org/gnu/ncurses/ncurses-6.5.tar.gz
tar -zxf ncurses-6.5.tar.gz && cd ncurses-6.5
./configure --disable-shared && make -j4
sudo make install
sudo ln -s /usr/local/include/ncursesw/curses.h /usr/local/include/ncurses.h # so Emacs can #include <ncurses.h>

# ...

sed -i '' '/darwin/ s/lncurses/lncursesw/g' configure.ac # before ./autogen.sh

出此下策(用 sed 替换 configure.ac)是因为它被写死了

# line 6155-6160
case "$opsys$REALLY_ANDROID" in
  ## darwin: Prevents crashes when running Emacs in Terminal.app under 10.2.
  ##  The ncurses library has been moved out of the System framework in
  ##  Mac OS X 10.2.  So if configure detects it, set the command-line
  ##  option to use it.
  darwin) LIBS_TERMCAP="-lncurses" ;;

然后它是不支持 native-comp 的(之后可能会支持吧,看我有没有兴趣再试试 native-comp)。现在的理由是:

  • 我不用
  • 我感觉在 GitHub Actions 上面编译 libgccjit 还是太变态了(现在已经需要 30 分钟了
  • 在 GitHub Actions 上面肯定是不能编译 Emacs 内置包的,那在本机上还要编译半天算什么话

有需要的点 README 最上面那个 build status 的 badge,然后选一个 run(一般肯定是选最新的吧)点进去,在 Artifacts 里下载当天早上 8 点编译的产物

调 GitHub Actions 真的是欲仙欲死

眼看着转了半个小时然后失败(或者被 Homebrew NTR)了的我就像无能的丈夫

9 个赞

都静态编译了,有没有试试 lto

我刚还在想要不要试试

应该是 ./configure 的时候 CFLAGS='-flto=thin' 就可以了对吧,macOS 上用的 ld64 不需要别的什么参数吧

明天早上就能看到结果了(

ThinLTO 最大的变化就是 binary size 显著的更小了(尺寸应该跟动态链接的差不多了

性能提升相对来说可能不大,差距应该是不如静态链接对动态链接的

2 个赞

试了下,贼几把快,不要 native comp 后启动比 jimeh/emacs-builds 快多了

最牛的地方是只要下载不到 40MB。

2 个赞

可能是没装 gnuzip,Emacs.app/Contents/Resources/lisp.el 都没压缩,不然安装尺寸可以更小

macOS 上一直没感觉到 nativecomp 有任何性能提升。如果能用放弃掉 nativecomp 换来启动速度的提升,那这个好啊。

和自编译的emacs-plus比又如何呢

比用普通参数自己编译的也要快

我看看,这还真没注意到

有点意思,不过我想请教下一些明显是动态加载的库是如何做到静态链接的,能做的话我在 Windows 上也试试。算了,好像就 Windows 上需要动态链接?

其实是因为我 configure 的时候因为希望干净可控一点,先用了 --without-all

导致 --with_compress_install 也一起被关掉了(

我就想明明有 checking for gzip... /usr/bin/gzip 为什么没被压缩

AC_PATH_PROG([INSTALL_INFO], [install-info], [:],
  [$PATH$PATH_SEPARATOR/usr/sbin$PATH_SEPARATOR/sbin])
dnl Don't use GZIP, which is used by gzip for additional parameters.
AC_PATH_PROG([GZIP_PROG], [gzip])

test $with_compress_install != yes && test -n "$GZIP_PROG" && \
   GZIP_PROG=" # $GZIP_PROG # (disabled by configure --without-compress-install)"

艹(

在 macOS 上 treesitter 的 make target 里面有 static 和 shared,但是如果需要 pkg-config 用的 .pc 那最方便的就是 make install, 会 build both,所以只需要把 dylib 删掉就好了(

1 个赞

请教如何解决这个提示?

xattr -c path/to/your/Emacs.app

1 个赞

我一般用这个 sudo xattr -r -d com.apple.quarantine Emacs.app

其实差不多,但万一有的 extended attribute 有用呢(

感觉是 Windows 上的动态链接和其他平台差别太大,搞得动态/静态没法简单切换就一刀切了 :rofl:

现在启用了 Resource/lisp 的 gz 压缩。换来了更小的安装尺寸(190mb->140mb)

代价是稍微更大的下载尺寸(35mb->45mb),因为 gz 压缩率不如 xz,binary 压缩率不良

(启动)性能没有影响,因为是 pdump 过的,不会影响静态链接+LTO 的性能优势

最简单的方法是解压的时候把 tar 包从 stdin 传入给 tar xvf -,而不是直接提供文件名

没有有用的,全删了就行,当然下载最好不用浏览器就没这烦恼