Using the function subemacs-eval, a form can be synchronously
evaluated in a freshly started Emacs process, which inherits only
the load-path from the current process.
Other values must be passed explicitly by making them part of the form, e.g. by writing
(let ((my-int 10))
(subemacs-eval `(+ 5 ',my-int)))
=> 15
subemacs-eval also supports errors raised by Emacs' signal and
related functions, and displays messages emitted in the subprocess.
The original motivation for writing this package was Emacs Lisp
byte-compilation. When byte-compiling a file from within a running
Emacs process, missing require calls for dependencies and typos
may be hidden from the byte compiler due to the environment already
containing them.
Such issues may not become apparent until the code is executed by a
user, who does not load the same files during startup. While they
can be diagnosed by testing code with emacs -Q, this solution is
inconvenient.
Instead, compiling Emacs Lisp files in a clean process by default turns the byte-compiler into a powerful ad-hoc tool to identify issues from byte-compiler warnings.
Functions subemacs-byte-compile-file and
subemacs-byte-recompile-directory are therefore provided and also
serve as a demonstration of the use of subemacs-eval.
Originally I had planned to implement subemacs-funcall, as
passing functions to the subprocess would allow compile-time
checking of the passed expressions for issues.
Passing a lambda form to a hypothetical subemacs-funcall in an
environment where lexical-binding is enabled, will capture the
lexical environment into the resulting closure form and make it
available to the subprocess. This behaviour however is not
documented and may break in the future. As a consequence an
implementation of subemacs-funcall would either require enforcing
unexpected limitations (e.g. not allowing closures) or risk the
creation of code that depends on an undocumented feature of current
Emacs versions.
Passing a quoted lambda form would avoid these problems, but
would also sacrifice compile-time checks, and thus the only
advantage.
async.el implements a
superset of the functionality of subemacs.el, with
async-sandbox having essentially the functionality of
subemacs-eval. However, a few complementary properties allow
subemacs.el to remain useful.
-
subemacs-evalforwards the STDOUT and STDERR of the subprocess and allows access to the contents as a string.async-sandboxdoes not. -
With
subemacs-byte-compile-file, the module contains a useful development tool, that is optimized for quickly checking against compiler warnings. -
On Windows at least,
async-sandboxhas more overhead.(async-sandbox '(lambda ())) ; ≈ 0.75 seconds (subemacs-eval '(progn)) ; ≈ 0.35 seconds -
On Windows, I sometimes experience
async-sandboxhanging, while I never had such a problem withsubemacs-eval.
- Rewrote
subemacs-byte-compile-file. - Adjusted README text to describe usecases compared to
async.el.
Original release. Supports exclusively synchronous execution.