【问题标题】:How do I automatically (re)compile ELPA packages?如何自动(重新)编译 ELPA 包?
【发布时间】:2013-03-11 15:49:05
【问题描述】:

我现在通过 MELPA 和 Marmalade 尽可能多地进行安装,并使用 git 管理我的 ~/.emacs.d。但是,我有 git ignore *.elc 文件。

这意味着当我在一个系统上安装一个软件包然后开始使用另一个系统时,git pull 只给我 *.el 文件。使用这些文件通常比使用 *.elc 慢。

我尝试将以下内容添加到 ~/.emacs.d/init.el:

;; load the packages we've installed. Note that package-install
;; byte-compiles the packages, but .elc is ignored by git so we force recompilation here
(byte-recompile-directory (expand-file-name "~/.emacs.d/elpa") 0)
(package-initialize)

不幸的是,这并不等同于 package.el 完成的编译。例如,如果我安装 emacs-eclim,package.el 不会编译 emacs-eclim/company-emacs-eclim.el,我会收到以下错误:

Leaving directory `/home/wilfred/.emacs.d/elpa'

Compiling file /home/wilfred/.emacs.d/elpa/emacs-eclim-20130310.1237/company-emacs-eclim.el at Mon Mar 11 15:40:01 2013
Entering directory `/home/wilfred/.emacs.d/elpa/emacs-eclim-20130310.1237/'
company-emacs-eclim.el:35:1:Error: Cannot open load file: eclim
Warning: reference to free variable `multiple-cursors-mode'
Warning: reference to free variable `mc--read-char'
Warning: assignment to free variable `mc--read-char'
Warning: reference to free variable `multiple-cursors-mode'
Warning: reference to free variable `mc--read-quoted-char'
Warning: assignment to free variable `mc--read-quoted-char'
Warning: reference to free variable `rectangular-region-mode'
Warning: reference to free variable `rectangular-region-mode'

如何让 Emacs 只对与 package.el 相同的文件进行字节编译?

【问题讨论】:

    标签: emacs compilation elisp elpa


    【解决方案1】:

    package.el 实际上使用完全相同的方法,只是在启动时重新编译使错误更加明显。

    使用的函数是package--make-autoloads-and-compile,它调用:

    (byte-recompile-directory pkg-dir 0 t)
    

    所以问题中的原始代码是正确的。但是,要重新编译尚未编译的目录,您可以执行以下操作:

    (require 'dash)
    (require 'f)
    
    (defun was-compiled-p (path)
      "Does the directory at PATH contain any .elc files?"
      (--any-p (f-ext? it "elc") (f-files path)))
    
    (defun ensure-packages-compiled ()
      "If any packages installed with package.el aren't compiled yet, compile them."
      (--each (f-directories package-user-dir)
        (unless (was-compiled-p it)
          (byte-recompile-directory it 0))))
    
    (ensure-packages-compiled)
    

    【讨论】:

      【解决方案2】:

      我建议不要将包保存在版本控制中(您不会将 .o 文件置于版本控制之下,对吗?)。这是我用来保持我的包同步的代码:

      (setq jpk-packages
            '(
              ac-dabbrev
              ...
              yasnippet
              ))
      
      (package-initialize)
      (add-to-list 'package-archives
                   '("melpa" . "http://melpa.milkbox.net/packages/"))
      (add-to-list 'package-archives
                   '("org" . "http://orgmode.org/elpa/"))
      
      (when (not package-archive-contents)
        (package-refresh-contents))
      
      (dolist (pkg jpk-packages)
        (when (and (not (package-installed-p pkg))
                 (assoc pkg package-archive-contents))
          (package-install pkg)))
      
      (defun package-list-unaccounted-packages ()
        "Like `package-list-packages', but shows only the packages that
        are installed and are not in `jpk-packages'.  Useful for
        cleaning out unwanted packages."
        (interactive)
        (package-show-package-list
         (remove-if-not (lambda (x) (and (not (memq x jpk-packages))
                                  (not (package-built-in-p x))
                                  (package-installed-p x)))
                        (mapcar 'car package-archive-contents))))
      

      我将上面的内容放在 init.el 中(当然是在版本控制之下),它会在 emacs 启动时安装任何尚不存在的包。更新是从 package-list-packages 创建的缓冲区完成的。 package-list-unaccounted-packages 显示所有已安装但不在我的jpk-packages 列表中的软件包,并且可以轻松删除我从列表中取出的软件包。

      要回答您的具体问题,我只需删除 elpa 目录并重新安装所有内容(使用上述代码)。

      【讨论】:

      • 您的 jpk-packages 似乎等同于 Carton 清单(正如 @francesco 在上面使用 Pallet 所描述的那样),但是您无法指定确切的包版本。
      • 我不使用 Carton 或 Pallet,但据我了解,我使用的是它们的一个非常简单的版本。我喜欢我的方式,因为我需要几乎所有的代码来引导纸箱/托盘,到目前为止,我还没有遇到不指定包版本的问题。
      • “你不会将 .o 文件置于版本控制之下,对吗?”我不觉得这是一个公平的比较。构建 .o 文件应该始终是可重现的。但是,似乎没有办法指定包的特定版本。我签入包文件,以便能够部署我知道可以一起工作的我的 emacs 配置的一致快照。
      【解决方案3】:

      对于“如何自动重新编译 any 过时的 .elc 文件”这个更一般的问题,我喜欢的解决方案是使用 https://github.com/tarsius/auto-compile

      我曾经有一些自定义解决方案涵盖了我遇到的大多数情况,但这个库涵盖了我正在做的所有事情以及更多。只需在加载其他任何内容之前对其进行初始化,您就可以排序了。

      至于不编译最初未编译的文件的原始问题,这就是 byte-recompile-directory0 参数所做的,因此您明确要求这种行为。默认行为是仅重新编译现有的过时 .elc 文件,因此您应该简单地删除该 0

      【讨论】:

        【解决方案4】:

        我不知道你关于字节编译包的具体问题的答案与package.el 的方式完全相同。

        但是,对于您在通过 Melpa 或 marmalade 安装扩展时在 git 中维护 emacs 配置目录的更普遍的问题,我建议您查看 pallet,它旨在解决这个问题。

        【讨论】:

        • 谢谢,我不知道 Pallet。但是,我真的很希望我的 .emacs.d 是独立的——我过去曾为很少更新的 elisp 文件在我最初下载它们的地方不再可用而感到悲痛。
        【解决方案5】:

        (byte-compile-file) 当我需要手动重新编译以前使用 elpa 安装的软件包时,它对我有用。

        特别针对这种情况:https://github.com/yjwen/org-reveal/issues/76t

        【讨论】:

          【解决方案6】:

          您遇到的问题只是在初始化包之前对文件进行了字节编译。如果您切换两条线,您的问题应该会消失。你得到的错误 (Cannot open load file: eclim) 是因为 ~/.emacs.d/elpa/emacs-eclim-20130310.1237/ 还没有在你的 load-path 中,package-initialize 会将它添加到你的 load-path 中(以及其他一些东西)。

          【讨论】:

            猜你喜欢
            • 2014-12-08
            • 1970-01-01
            • 2017-08-02
            • 1970-01-01
            • 1970-01-01
            • 2013-08-31
            • 2012-07-05
            • 1970-01-01
            • 2018-08-19
            相关资源
            最近更新 更多