Pourquoi `eval-when-compile` s'exécute au chargement du fichier et est compilé en octets en .elc?

9

Idiome commun pour l'expansion de macro de contournement ou résoudre l'avertissement sur les variables non définies lors de la compilation d'octets:

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

Mais cela require ...compilé dans un .elcfichier! J'ai trouvé qui cl-eval-whenont une sémantique appropriée (selon le nom).

Normalement, nous n'avons pas besoin d'un requirefichier de site etpackage.el

Par exemple, je veux compiler mon octet .emacsqui utilise des macros externes, mais passer silencieusement s'il n'y a pas un tel paquet:

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

Une autre façon de procéder est:

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

Mais maintenant, nous ne sommes pas une forme de haut niveau ...

Dois-je remplir correctement ce eval-when-compilenom, faire quelque chose qui n'est pas attendu de son nom?

gavenkoa
la source
FWIW, les deux derniers extraits n'ont pas le même comportement. Le premier ne protège pas w3m-DEPENDENT-CODEd'un disparu w3m-util.
Drew
(when (require 'w3m-util nil t) (w3m-util-DEPENDENT-CODE...))
Drew
(when (require 'w3m-util nil t) ...)est un bel idiome! Mais j'essaye de faire un .emacsfichier parfait , pas une bibliothèque. Ayez donc à l'esprit le chargement de code retardé (sur demande) à l'aide du chargement automatique. Pour cette raison que j'utilise intensivement eval-after-load, il requiresuffit de faire en sorte que la compilation d'octets réussisse avec l'expansion des macros.
gavenkoa

Réponses:

9

Avez-vous demandé à Emacs ce qu'il eval-when-compileest censé faire?

C-h f eval-when-compile vous indique qu'il évalue également l'argument au moment du chargement:

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.

Il dit que s'il est interprété, c'est comme progn. Et il répète explicitement cela.

Un nom de fonction ou de macro reflète rarement parfaitement le comportement. Mais dans ce cas, il semble que vous recherchiez un comportement différent, qui pourrait être appelé eval-only-when-compile.

A dessiné
la source
1
eval-only-when-compilenom m'aide à comprendre point à nom eval-when-compile, merci!
gavenkoa
3

Pour évaluer le code uniquement à l'étape de la compilation, utilisez des eval-whenmacros datées par RMS en 1993-07-30.

cl-eval-when est apparu en 2012-06-03 de Stefan Monnier et il n'est pas disponible pour Emacs 22.x (si vous vous en souciez, je le fais).

Par exemple, vous aimez vous débarrasser de Warning: assignment to free variable:

(setq auto-revert-interval 2)

ajoutez juste au-dessus de cette ligne:

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

Notez que cela n'est utile que pour la compilation d'octets de .emacsfichier. Si vous développez une bibliothèque, vous devez faire requireou diviser le fichier de bibliothèque en séparer et charger uniquement les fonctionnalités requises.

gavenkoa
la source
Pour éviter les avertissements variables, il vous suffit de(defvar auto-revert-interval)
npostavs
1
J'utilise la defvarsolution dans de nombreux cas, mais je recherche également une solution plus solide . Je peux taper le nom ou le package peut supprimer la définition et le vérificateur de compilation serait silencieux dans de tels cas.
gavenkoa