Как автоматически (пере) скомпилировать пакеты ELPA?
Сейчас я устанавливаю столько, сколько могу через MELPA и Marmalade, и управляю своим ~/.emacs.d с помощью git. Тем не менее, я должен игнорировать файлы *.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?
6 ответов
На самом деле 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)
Я рекомендую не держать пакеты в управлении версиями (вы бы не поставили файлы.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 и переустановил все (используя приведенный выше код).
Решение, которое мне нравится в более общем вопросе "Как автоматически перекомпилировать любой устаревший файл.elc", заключается в использовании https://github.com/tarsius/auto-compile
Раньше у меня было несколько пользовательских решений, которые охватывали большинство ситуаций, с которыми я столкнулся, но эта библиотека охватывает все, что я делал, и многое другое. Просто инициализируйте его перед загрузкой чего-либо еще, и вы отсортированы.
Что касается первоначального вопроса о некомпиляции файлов, которые не были изначально скомпилированы, это то, что 0
аргумент byte-recompile-directory
делает, так что вы явно просите об этом поведении. Поведение по умолчанию состоит в том, чтобы перекомпилировать только существующие устаревшие файлы.elc, так что вы должны просто удалить это 0
,
(byte-compile-file) работал для меня, когда мне нужно вручную перекомпилировать пакеты, которые я ранее установил, используя elpa.
В частности, для этой ситуации: https://github.com/yjwen/org-reveal/issues/76t
Я не знаю ответа на ваш конкретный вопрос о байт-компиляции пакетов точно так же package.el
было бы.
Тем не менее, для решения более общей проблемы с поддержанием вашего каталога конфигурации emacs в git при установке расширений через Melpa или marmalade, я предлагаю вам взглянуть на паллету, которая была разработана для решения этой самой проблемы.
Проблема в том, что вы просто компилируете файлы перед инициализацией пакетов. Если вы переключите две линии, ваша проблема должна исчезнуть. Вы получаете ошибку (Cannot open load file: eclim
) это потому что ~/.emacs.d/elpa/emacs-eclim-20130310.1237/
еще не в вашем load-path
, а также package-initialize
добавит его в ваш load-path
(наряду с несколькими другими вещами).