Previous: Argument Lists, Up: Program Structure [Contents][Index]
Normally, the byte-compiler does not actually execute the forms in
a file it compiles. For example, if a file contains (setq foo t)
,
the act of compiling it will not actually set foo
to t
.
This is true even if the setq
was a top-level form (i.e., not
enclosed in a defun
or other form). Sometimes, though, you
would like to have certain top-level forms evaluated at compile-time.
For example, the compiler effectively evaluates defmacro
forms
at compile-time so that later parts of the file can refer to the
macros that are defined.
This form controls when the body forms are evaluated.
The situations list may contain any set of the symbols
compile
, load
, and eval
(or their long-winded
ANSI equivalents, :compile-toplevel
, :load-toplevel
,
and :execute
).
The cl-eval-when
form is handled differently depending on
whether or not it is being compiled as a top-level form.
Specifically, it gets special treatment if it is being compiled
by a command such as byte-compile-file
which compiles files
or buffers of code, and it appears either literally at the
top level of the file or inside a top-level progn
.
For compiled top-level cl-eval-when
s, the body forms are
executed at compile-time if compile
is in the situations
list, and the forms are written out to the file (to be executed
at load-time) if load
is in the situations list.
For non-compiled-top-level forms, only the eval
situation is
relevant. (This includes forms executed by the interpreter, forms
compiled with byte-compile
rather than byte-compile-file
,
and non-top-level forms.) The cl-eval-when
acts like a
progn
if eval
is specified, and like nil
(ignoring the body forms) if not.
The rules become more subtle when cl-eval-when
s are nested;
consult Steele (second edition) for the gruesome details (and
some gruesome examples).
Some simple examples:
;; Top-level forms in foo.el: (cl-eval-when (compile) (setq foo1 'bar)) (cl-eval-when (load) (setq foo2 'bar)) (cl-eval-when (compile load) (setq foo3 'bar)) (cl-eval-when (eval) (setq foo4 'bar)) (cl-eval-when (eval compile) (setq foo5 'bar)) (cl-eval-when (eval load) (setq foo6 'bar)) (cl-eval-when (eval compile load) (setq foo7 'bar))
When foo.el is compiled, these variables will be set during the compilation itself:
foo1 foo3 foo5 foo7 ; 'compile'
When foo.elc is loaded, these variables will be set:
foo2 foo3 foo6 foo7 ; 'load'
And if foo.el is loaded uncompiled, these variables will be set:
foo4 foo5 foo6 foo7 ; 'eval'
If these seven cl-eval-when
s had been, say, inside a defun
,
then the first three would have been equivalent to nil
and the
last four would have been equivalent to the corresponding setq
s.
Note that (cl-eval-when (load eval) …)
is equivalent
to (progn …)
in all contexts. The compiler treats
certain top-level forms, like defmacro
(sort-of) and
require
, as if they were wrapped in (cl-eval-when
(compile load eval) …)
.
Emacs includes two special forms related to cl-eval-when
.
See Eval During Compile in GNU Emacs Lisp Reference Manual.
One of these, eval-when-compile
, is not quite equivalent to
any cl-eval-when
construct and is described below.
The other form, (eval-and-compile …)
, is exactly
equivalent to ‘(cl-eval-when (compile load eval) …)’.
The forms are evaluated at compile-time; at execution time,
this form acts like a quoted constant of the resulting value. Used
at top-level, eval-when-compile
is just like ‘eval-when
(compile eval)’. In other contexts, eval-when-compile
allows code to be evaluated once at compile-time for efficiency
or other reasons.
This form is similar to the ‘#.’ syntax of true Common Lisp.
The form is evaluated at load-time; at execution time, this form acts like a quoted constant of the resulting value.
Early Common Lisp had a ‘#,’ syntax that was similar to
this, but ANSI Common Lisp replaced it with load-time-value
and gave it more well-defined semantics.
In a compiled file, cl-load-time-value
arranges for form
to be evaluated when the .elc file is loaded and then used
as if it were a quoted constant. In code compiled by
byte-compile
rather than byte-compile-file
, the
effect is identical to eval-when-compile
. In uncompiled
code, both eval-when-compile
and cl-load-time-value
act exactly like progn
.
(defun report () (insert "This function was executed on: " (current-time-string) ", compiled on: " (eval-when-compile (current-time-string)) ;; or '#.(current-time-string) in real Common Lisp ", and loaded on: " (cl-load-time-value (current-time-string))))
Byte-compiled, the above defun will result in the following code (or its compiled equivalent, of course) in the .elc file:
(setq --temp-- (current-time-string)) (defun report () (insert "This function was executed on: " (current-time-string) ", compiled on: " '"Wed Oct 31 16:32:28 2012" ", and loaded on: " --temp--))
Previous: Argument Lists, Up: Program Structure [Contents][Index]