17.2 Функции байт-компиляции

Вы можете байт-скомпилировать отдельное определение функции или макроса с помощью функции byte-compile. Вы можете скомпилировать весь файл с помощью byte-compile-file, или несколько файлов с помощью byte-recompile-directory или batch-byte-compile.

Иногда байт-компилятор выдает предупреждения и/или сообщения об ошибках (см. Ошибки компилятора для получения подробной информации). Эти сообщения обычно записываются в буфер под названием *Compile-Log*, который использует режим компиляции. См. Режим компиляции в Руководстве GNU Emacs. Однако, если переменная byte-compile-debug не равна nil, сообщения об ошибках будут сигнализироваться как ошибки Lisp (см. Ошибки).

Будьте осторожны при написании вызовов макросов в файлах, которые вы намереваетесь байт-скомпилировать. Поскольку вызовы макросов раскрываются при компиляции, макросы должны быть загружены в Emacs, иначе байт-компилятор не сделает нужного. Обычно для этого используются формы require, которые указывают файлы, содержащие необходимые определения макросов (см. Функции). Обычно байт-компилятор не вычисляет код, который он компилирует, но он обрабатывает формы require по-особому, загружая указанные библиотеки. Чтобы избежать загрузки файлов определений макросов, когда кто-то запускает скомпилированную программу, используйте eval-when-compile вокруг вызовов require (см. Вычисление во время компиляции). Для получения более подробной информации см. Макросы и байт-компиляция.

Встроенные (defsubst) функции менее проблематичны; если вы скомпилируете вызов такой функции до того, как будет известно ее определение, вызов все равно сработает корректно, просто он будет работать медленнее.

Функция: byte-compile symbol

Эта функция байт-компилирует определение функции symbol, заменяя предыдущее определение скомпилированным. Определение функции symbol должно быть фактическим кодом функции; byte-compile не обрабатывает перенаправление функций. Возвращаемое значение — объект байт-кода функции, который является скомпилированным определением symbol (см. Объекты замыканий).

(defun factorial (integer)
  "Вычислить факториал INTEGER."
  (if (= 1 integer) 1
    (* integer (factorial (1- integer)))))
⇒ factorial

(byte-compile 'factorial)
⇒
#[257
  "\211\300U\203^H^@\300\207\211\301^BS!_\207"
  [1 factorial] 4
  "Вычислить факториал INTEGER.\n\n(fn INTEGER)"]

Если определение symbol является объектом байт-кода функции, byte-compile ничего не делает и возвращает nil. Он не компилирует определение символа снова, поскольку исходный (нескомпилированный) код уже был заменен в ячейке функции символа скомпилированным кодом.

Аргументом для byte-compile также может быть выражение lambda. В этом случае функция возвращает соответствующий скомпилированный код, но не сохраняет его нигде.

Команда: compile-defun &optional arg

Эта команда считывает , содержащий точку, компилирует его и вычисляет результат. Если вы используете это для , который на самом деле является определением функции, эффект заключается в установке скомпилированной версии этой функции.

compile-defun обычно отображает результат вычисления в области вывода, но если arg не равен nil, он вставляет результат в текущий буфер после формы, которую он скомпилировал.

Команда: byte-compile-file filename

Эта функция компилирует файл кода Lisp с именем filename в файл байт-кода. Имя выходного файла формируется путем замены суффикса '.el' на '.elc'; если filename не заканчивается на '.el', к нему добавляется '.elc'.

Компиляция работает путем чтения входного файла по одной форме за раз. Если это определение функции или макроса, записывается скомпилированное определение функции или макроса. Другие формы группируются, затем каждая группа компилируется и записывается таким образом, чтобы ее скомпилированный код был выполнен при чтении файла. Все комментарии отбрасываются при чтении входного файла.

Эта команда возвращает t, если ошибок не было, и nil в противном случае. При интерактивном вызове она запрашивает имя файла.

$ ls -l push*
-rw-r--r-- 1 lewis lewis 791 Oct  5 20:31 push.el

(byte-compile-file "~/emacs/push.el")
     ⇒ t

$ ls -l push*
-rw-r--r-- 1 lewis lewis 791 Oct  5 20:31 push.el
-rw-rw-rw- 1 lewis lewis 638 Oct  8 20:25 push.elc
Команда: byte-recompile-directory directory &optional flag force follow-symlinks

Эта команда перекомпилирует каждый файл '.el' в directory (или его подкаталоги), который нуждается в перекомпиляции. Файл нуждается в перекомпиляции, если существует файл '.elc', но он старше файла '.el'.

Когда файл '.el' не имеет соответствующего файла '.elc', flag определяет, что делать. Если он равен nil, эта команда игнорирует такие файлы. Если flag равен 0, она компилирует их. Если он не равен ни nil, ни 0, она спрашивает пользователя, нужно ли компилировать каждый такой файл, и спрашивает о каждом подкаталоге.

В интерактивном режиме byte-recompile-directory запрашивает directory, а flag является аргументом префикса.

Если force не равен nil, эта команда перекомпилирует каждый файл '.el', у которого есть файл '.elc'.

Эта команда обычно не компилирует файлы '.el', которые являются символьными ссылками. Если необязательный параметр follow-symlink не равен nil, символически связанные '.el' также будут скомпилированы.

Возвращаемое значение непредсказуемо.

Функция: batch-byte-compile &optional noforce

Эта функция запускает byte-compile-file для файлов, указанных в командной строке. Эту функцию следует использовать только в пакетном выполнении Emacs, так как она завершает работу Emacs после завершения. Ошибка в одном файле не предотвращает обработку последующих файлов, но для него не будет сгенерирован выходной файл, и процесс Emacs завершится с ненулевым кодом состояния.

Если noforce не равен nil, эта функция не перекомпилирует файлы, у которых есть актуальный файл '.elc'.

$ emacs -batch -f batch-byte-compile *.el