Emacs是怎么管理package依赖的?

假定以下是我的.emacs.d结构:

.emacs.d
├─elpa
│  ├─A-19990100.1111
│  ├─B-19990400.2222
├─site-lisp
│  ├─E
│  └─F

注意:这里A,B都是老版本,B依赖于A

现在我在init.el(package-install 'C),而这个C会依赖于新版的A

这个时候Emacs的package系统会怎么做?

  1. 更新A到新版,同时让B也更新到最新?(服务器处理版本依赖)

    .emacs.d
    ├─elpa
    │  ├─A-20200600.1111
    │  ├─B-20200400.2222
    │  ├─C-20200900.3333
    ├─site-lisp
    │  ├─E
    │  └─F
    
  2. 保持老版本们不变并企图让C依赖于老版本的A

    .emacs.d
    ├─elpa
    │  ├─A-19990100.1111
    │  ├─B-19990400.2222
    │  ├─C-20200900.3333
    ├─site-lisp
    │  ├─E
    │  └─F
    
  3. 保持老版本不变(B仍然依赖于老版的A),但是自动下载新版本的A,让C依赖于新版的A

    即:同时存在两个版本的A,但两个A不会相互影响,各自在隔离环境里运行。

    .emacs.d
    ├─elpa
    │  ├─A-19990100.1111
    │  ├─B-19990400.2222
    │  ├─A-20200600.1111
    │  ├─C-20200900.3333
    ├─site-lisp
    │  ├─E
    │  └─F
    

如果我因为某个需求要简单修改下A,于是我把A-19990100.1111elpa移动到site-lisp下:

.emacs.d
├─elpa
│  └─B-19990400.2222
├─site-lisp
│  ├─E
│  ├─F
│  └─A-19990100.1111

此时B还能正确访问A吗?

如果此时我再 (package-install 'C) 又会如何呢?

对Emacs的package系统不是很了解,望指点。

多谢。

两个地方决定包的版本:

  • 最低版本:每个包的 Package-Requires:
  • 最新版本:package-archive-contents

由于 elpa 仓库不保存历史版本,所以 package-archive-contents 必须经常更新,否则会出现 Package ‘xxxx-’ is unavailable” 错误。

当你安装 C 的时候,Emacs 会递归处理依赖关系:C -> A -> ...,如果 B 不再这条链上,就仍然保持旧版本。

Emacs 无法同时启用一个包的多个版本。

2 个赞

在安装新包的时候,确实有遇到过package ‘xxxx-’ is unavailable的错误。

之前的解决方法是用(package-refresh-contents)刷一下,并不知道原理。

原来它的意思是本地计算的包的版本(package-archive-contents)过老和服务器上的不匹配。

多谢了。


另外,昨天发现如果修改了包A(即:主题中的最后一个case)之后,再安装C的话,Emacs似乎还会在epla里下载A,从而出现两个A的状况:

.emacs.d
├─elpa
│  ├─A-20200600.1111
│  ├─B-20200400.2222
│  ├─C-20200900.3333
├─site-lisp
│  ├─E
│  ├─F
│  └─A-19990100.1111

其中BC都会依赖于A-20200600.1111 而不是 A-19990100.1111

然而,在实践中,A-19990100.1111的部分功能仍然有效,从而出现一些诡异的问题。

现在的解决方法只能是把 A B C 全放到 site-lisp里去做本地管理了。

因为 emacs 的包管理器无法识别手动安装的包。例子:
如果 A 包依赖 B 包但 B 包不依赖任何包, 你安装 A 包时,会使用 package-installed-p 判断依赖的 B 包的, B 包未安装则安装它,而自己手动安装的包无法被 package-installed-p 判断为已安装的,除非魔改 package-installed-p 的一些判断条件。