Converting an Emacs Lisp program to lexical binding is easy. First,
add a file-local variable setting of lexical-binding
to
t
in the header line of the Emacs Lisp source file (see File Local Variables). Second, check that every variable in the program
which needs to be dynamically bound has a variable definition, so that
it is not inadvertently bound lexically.
A simple way to find out which variables need a variable definition
is to byte-compile the source file. See Byte Compilation. If a
non-special variable is used outside of a let
form, the
byte-compiler will warn about reference or assignment to a free
variable. If a non-special variable is bound but not used within a
let
form, the byte-compiler will warn about an unused lexical
variable. The byte-compiler will also issue a warning if you use a
special variable as a function argument.
A warning about a reference or an assignment to a free variable is
usually a clear sign that that variable should be marked as
dynamically scoped, so you need to add an appropriate defvar
before the first use of that variable.
A warning about an unused variable may be a good hint that the
variable was intended to be dynamically scoped (because it is actually
used, but in another function), but it may also be an indication that
the variable is simply really not used and could simply be removed.
So you need to find out which case it is, and based on that, either
add a defvar
or remove the variable altogether. If removal is
not possible or not desirable (typically because it is a formal
argument and that we cannot or don’t want to change all the callers),
you can also add a leading underscore to the variable’s name to
indicate to the compiler that this is a variable known not to
be used.)
Caution: This is an experimental feature that may change or disappear without prior notice.
The byte-compiler can also warn about lexical variables that are
special in other Emacs Lisp files, often indicating a missing
defvar
declaration. This useful but somewhat specialized check
requires three steps:
EMACS_GENERATE_DYNVARS
set to a nonempty string. These are typically all the files in the
same package or related packages or Emacs subsystems. The process
will generate a file whose name ends in .dynvars for each
compiled Emacs Lisp file.
EMACS_DYNVARS_FILE
set to the name
of the aggregated file created in step 2.
Here is an example illustrating how this could be done, assuming that
a Unix shell and make
are used for byte-compilation:
$ rm *.elc # force recompilation $ EMACS_GENERATE_DYNVARS=1 make # generate .dynvars $ cat *.dynvars > ~/my-dynvars # combine .dynvars $ rm *.elc # force recompilation $ EMACS_DYNVARS_FILE=~/my-dynvars make # perform checks