Warum wird "eval-when-compile" beim Laden der Datei ausgeführt und per Byte in .elc kompiliert?

9

Allgemeine Redewendung zur Umgehung der Makroerweiterung oder zum Auflösen von Warnungen vor undefinierten Variablen während der Bytekompilierung:

(eval-when-compile
  (require 'cl-lib))

Aber require ...das in .elcDatei kompiliert ! Ich fand, dass cl-eval-whendie richtige Semantik (nach Namen) haben.

Normalerweise brauchen wir nicht requireals Site-Datei undpackage.el

Zum Beispiel möchte ich meine Bytes kompilieren, .emacsdie einige externe Makros verwenden, aber stillschweigend durchlaufen, wenn es kein solches Paket gibt:

(cl-eval-when 'compile
  (condition-case err
      (require 'w3m-util)
    (error (byte-compile-warn "Failed by: %S" err))))
(w3m-util-DEPENDENT-CODE ...)

Ein anderer Weg, dies zu tun, ist:

(ignore-error
   (require 'w3m-util)
   (w3m-util-DEPENDENT-CODE ...))

Aber jetzt sind wir keine Top-Level-Form ...

Fülle ich diesen eval-when-compileNamen richtig aus und mache etwas, was von seinem Namen nicht erwartet wird?

Gavenkoa
quelle
FWIW, die beiden letztgenannten Snippets haben nicht das gleiche Verhalten. Ersteres schützt nicht vor w3m-DEPENDENT-CODEeinem Vermissten w3m-util.
Drew
(when (require 'w3m-util nil t) (w3m-util-DEPENDENT-CODE...))
Drew
(when (require 'w3m-util nil t) ...)ist eine nette Redewendung! Aber ich versuche, eine perfekte .emacsDatei zu erstellen, keine Bibliothek. Denken Sie also daran, das Laden von Code (auf Anfrage) mithilfe des automatischen Ladens zu verzögern. Aus diesem Grund verwende ich häufig die eval-after-loadFrage, ob requiredie Byte-Kompilierung nur mit der Makro-Erweiterung erfolgreich sein soll.
Gavenkoa

Antworten:

9

Hast du Emacs gefragt, was eval-when-compileer tun soll?

C-h f eval-when-compile sagt Ihnen, dass es das Argument auch beim Laden auswertet:

eval-when-compile is a Lisp macro in `byte-run.el'.

(eval-when-compile &rest BODY)

Like ‘progn’, but evaluates the body at compile time if you’re compiling.
Thus, the result of the body appears to the compiler as a quoted
constant.  In interpreted code, this is entirely equivalent to
‘progn’, except that the value of the expression may be (but is
not necessarily) computed at load time if eager macro expansion
is enabled.

Es heißt, wenn es interpretiert wird, ist es wie progn. Und es wiederholt dies ausdrücklich.

Ein Funktions- oder Makroname spiegelt das Verhalten selten perfekt wider. In diesem Fall klingt es jedoch so, als würden Sie nach einem anderen Verhalten suchen, das als "Verhalten" bezeichnet werden könnte eval-only-when-compile.

Drew
quelle
1
eval-only-when-compileName hilf mir zu verstehen, Punkt zu Name eval-when-compile, danke!
Gavenkoa
3

Um Code nur in der Kompilierungsphase auszuwerten, verwenden Sie eval-whenMakros, die von RMS am 30.07.1993 datiert wurden.

cl-eval-when erschien am 03.06.2012 von Stefan Monnier und ist für Emacs 22.x nicht verfügbar (wenn es dich interessiert, tue ich das).

Zum Beispiel möchten Sie in loswerden Warning: assignment to free variable:

(setq auto-revert-interval 2)

Fügen Sie einfach über dieser Zeile hinzu:

(eval-when 'compile (require 'autorevert))

Beachten Sie, dass dies nur für die Byte-Kompilierung von .emacsDateien nützlich ist . Wenn Sie eine Bibliothek entwickeln, sollten Sie requiredie Bibliotheksdatei in separate und nur die erforderlichen Funktionen laden.

Gavenkoa
quelle
Um variable Warnungen zu vermeiden, brauchen Sie nur(defvar auto-revert-interval)
npostavs
1
Ich benutze defvarin vielen Fällen eine Lösung, suche aber auch nach einer stärkeren Lösung. Ich kann den Namen falsch eingeben oder das Paket kann die Definition entfernen und die Kompilierungsprüfung ist in solchen Fällen stumm.
Gavenkoa