REPL Extensions in Standalone EXE

Anton Kovalenko edited this page Aug 23, 2011 · 9 revisions
Clone this wiki locally

REPL extensions in standalone executables

Prebuilt standalone SBCL executables for Windows, available for download at the build status page, include a few modules from “SYS:CONTRIB;” collection. This list includes an extended REPL (SB-ACLREPL module).

When building standalone executable images, I add some features to SB-ACLREPL (this part of build process uses noticeable amount of code that is unpublished now).

New commands

SB-ACLREPL:ALIAS facility is used for their definition; the standard :aliases command prints a list of them, with a brief description of each one.

Current command set provides a convenient way of bootstrapping Quicklisp and loading systems provided by its repository.

Bootstrapping happens automatically when a Quicklisp-related command is entered for the first time, unless quicklisp is already loaded by other means at that moment: initial quicklisp.lisp (loaded from a socket stream) brings in another parts and the repository metadata.

Arguments for this kind of commands are never evaluated. They should be either symbols or string literals; non-qualified symbols that are used as string designators are not interned to the current *package* (internally, a special temporal package is used to achieve this).

Command :qload system...

Load one or more systems.

Command :qapropos some-text

Search system and release names in Quicklisp repository; list matching systems (the facility itself is provided by QL-DIST:SYSTEM-APROPOS).

Command :qupdate optional-dist-names-to-update...

Update Quicklisp metadata. With no arguments, update all subscribed dists and also Quicklisp client.

Command :qslime

Experimental: start SWANK server and SLIME client on local machine. This command is available since sbcl-

Multiple things happen here, even if we forget quicklisp bootstrapping. First, swank and quicklisp-slime-helper are quickloaded; then a registry is examined for Emacs installation (emacs_dir value under SOFTWARE/GNU/Emacs key, in HKCU and HKLM; the value at HKLM is written by EmacsW32 project’s install wizard). If Emacs installation root is found during this step, emacsclientw.exe, runemacs.exe or emacs.exe is started with command-line options that should make it load SLIME (from the quickloaded release) and connect to SBCL binary that received :qslime command.

If Emacs installation root is not found by reading the registry, an open file dialog is displayed (“Where is your emacs?”), and the answer is used to start SLIME. If emacsclientw.exe is available in the same directory as the selected executable (which is supposed to be runemacs.exe or emacs.exe), this command will prefer it.

I’m going to make some customization of this command’s behavior possible, if it proves to be useful; even now, it is a good tool to have SLIME running as soon as possible, if all you have is a modern GNU Emacs and one of my SBCL executables.

Command :lsloaded

Very Experimental: list Quicklisp systems that are known to be loaded by ASDF. Expect it to be broken or unreliable; for now, it’s the single command that works with ASDF directly; that would be bad enough, but it may also be affected by method definitions provided by particular systems.

Outer Parentheses May Be Omitted

I’ve reimplemented a facility from some older REPL (I don’t remember its name, only the idea): for ordinary S-expressions, a new postprocessing step was added. If a command line starts with a symbol that is FBOUND, but makes no sense as variable, the line is reinterpreted as if there were additional parentheses around (the precondition I use is probably stronger than expected; the purpose is to avoid any reinterpretation unless it’s obviously makes more sense than the original form).

Reinterpreted form is pretty-printed (with ;;; line prefix) before execution. Here is an example REPL session fragment:

CL-USER(9): list 1 2 3
;;;  => (LIST 1 2 3)
(1 2 3)

No attempt at reinterpretation is made if the last S-expression on the first line is incomplete, with the intent to avoid confusion caused by reinterpretation of non-trivial inputs (e.g. something received from redirected standard input).

REPL Override Warning

There are some other variants of extended REPL, like the one provided by a (quicklispable) GBBopen project. Some users may prefer SB-ACLREPL with the extensions, even if they need some of GBBopen modules.

If SB-INT:*REPL-READ-FORM-FUN* is modified but a prompt code is left intact, a simple warning will be signalled before the next REPL prompt:

   REPL behavior was overridden to use #<FUNCTION EXTENDED-REPL-READ-FORM-FUN>
   for reading forms. Among other things, it may mean that our Quicklisp
   goodies, like :qload and :qapropos, won't be available any more. Invoke
   (RESTORE-ACLREPL) to get back the form reader provided by SB-ACLREPL.

As it says, (COMMON-LISP-USER:RESTORE-ACLREPL) rolls back the changes; after it’s invoked, the original SB-ACLREPL with extensions will be used for all new listeners (including those created by default toplevel function of the dumped image).

Image Startup Sequence

When a new image is dumped and restarted later, both Quicklisp and ASDF can become confused upon restart: the first one keeps its repository location at ql:*quicklisp-home*, and the second keeps user cache directory specification in asdf::*user-cache*. Before dumping standalone binaries, I install the init-hook designed to do the right thing when possible.

  • ASDF User cache location is reinitialized according to the current user profile (side note: local application data directory is used for this purpose, instead of e.g. top-level %UserProfile% or %AppData%, to avoid cluttering roaming user profiles with cached FASLs).
  • If Quicklisp was loaded automatically during extended command execution, QL:*QUICKLISP-HOME* (which defaults to %UserProfile%/quicklisp/) is adjusted for current user profile as well. If some other way of loading quicklisp was used, no adjustment happens.

Image information (describing the unofficial build, its version, preloaded modules, and providing some relevant URLs) is printed by the original executables in the absence of command-line arguments. It’s never printed by non-original images (dumped with (SB-EXT:SAVE-LISP-AND-DIE) by the user).