Skip to content

Latest commit

 

History

History
463 lines (351 loc) · 16.6 KB

installation.org

File metadata and controls

463 lines (351 loc) · 16.6 KB

Installing cclsh

See Shared SBCL daemon for opt-in multi-terminal sessions in one image, and Idle power and shell sessions for wakeup measurements.

cclsh has two supported host-Lisp paths:

  • CCL 1.13 on Linux x86-64 provides the Nix package, release archives, saved image builds, the prewarmed launcher and the shared login-shell procedure.
  • SBCL on macOS or Linux provides a portable source launcher for normal interactive use, scripts, pipelines and Lisp development.

The Nix flake is the recommended Linux installation. Source launchers are useful for development and for hosts where the CCL image is not available.

cclsh is not a POSIX shell. Use it as an ordinary shell before making it a login shell, and keep a working recovery shell available.

Nix package

Try it

Run cclsh without installing it:

nix run github:lambda-symbolics/cclsh

To check the package without starting an interactive session:

nix run github:lambda-symbolics/cclsh -- --version

Install for one user

nix profile install github:lambda-symbolics/cclsh
cclsh --version

From a checkout, use nix run . or nix profile install .#cclsh. Run nix flake check to build the complete package and test its command boundary and installed Quicklisp state.

The flake rebuilds CCL 1.13 from the exact downstream CCL commits and editor dependency revisions recorded in dependencies.lock. It installs an ordinary user command; it does not edit /etc/shells or change an account’s login shell.

Linux x86-64 release archive

Each GitHub release includes cclsh-VERSION-linux-x86_64.tar.xz and its .sha256 checksum. The archive is self-contained: it contains CCLSH’s matched kernel and image plus the runtime they need, so Nix is not required.

sha256sum -c cclsh-VERSION-linux-x86_64.tar.xz.sha256
tar -xJf cclsh-VERSION-linux-x86_64.tar.xz
mkdir -p ~/.local/opt
mv cclsh-VERSION-linux-x86_64 ~/.local/opt/cclsh
~/.local/opt/cclsh/bin/cclsh --version

Keep bin, lib and libexec together. To make it available as cclsh, add ~/.local/opt/cclsh/bin to PATH or create a symlink in a personal bin directory. The optional cclsh-fast launcher is included but remains experimental.

Quicklisp state

A saved image uses ~/quicklisp when it already exists. Otherwise cclsh copies its embedded, sanitized Quicklisp client and distribution index on first use to:

${XDG_DATA_HOME:-$HOME/.local/share}/cclsh/quicklisp

Set CCLSH_QUICKLISP_HOME to choose another writable location. An existing explicit target must contain setup.lisp; invalid or unwritable targets are reported and refused.

Interactive sessions and configured -lc=/-ic= commands load the selected Quicklisp home’s local-init files. Plain -c commands, scripts, piped input and safe mode do not execute them.

Run from source

SBCL on macOS or Linux

The scripts/cclsh-sbcl launcher runs the checkout with SBCL. It uses Quicklisp for the small host layer (cffi, bordeaux-threads and trivial-gray-streams), retains cclsh’s normal syntax and user startup file, and does not require a C compiler or a saved image.

On macOS, install SBCL with Homebrew; Linux distributions normally package it:

brew install sbcl                    # macOS
# or: sudo apt install sbcl          # Debian/Ubuntu

Install Quicklisp once if ~/quicklisp/setup.lisp does not already exist:

curl -O https://beta.quicklisp.org/quicklisp.lisp
sbcl --noinform --non-interactive \
  --load quicklisp.lisp \
  --eval '(quicklisp-quickstart:install)' \
  --eval '(uiop:quit)'

Clone cclsh and its locked sibling source dependencies. The same layout works for the CCL source path below:

git clone https://github.com/lambda-symbolics/cclsh.git cclsh
cd cclsh
git clone https://github.com/lambda-symbolics/clinedi.git ../clinedi
git clone https://github.com/lambda-symbolics/structlisp.git ../structlisp
git clone https://github.com/lambda-symbolics/cl-colorist.git ../cl-colorist
git clone https://github.com/lambda-symbolics/colorlisp.git ../colorlisp
git clone https://github.com/lambda-symbolics/colordiff.git ../colordiff
for dependency in clinedi structlisp cl-colorist colorlisp colordiff; do
    commit=$(sed -n "s/^$dependency=//p" dependencies.lock)
    git -C "../$dependency" checkout --detach "$commit"
done
scripts/cclsh-sbcl --version
scripts/cclsh-sbcl
make sbcl-check

The launcher deliberately starts SBCL without its own user or system init files, then loads the selected Quicklisp setup and cclsh. This avoids accidental interference from unrelated Lisp projects. Use CCLSH_SBCL to select a specific SBCL executable and CCLSH_QUICKLISP_SETUP for a nonstandard Quicklisp location. The existing CCLSH_*_SOURCE dependency overrides also apply when a sibling checkout lives elsewhere.

To expose this checkout as cclsh while keeping its sibling dependencies in place, symlink the launcher into a personal bin directory:

mkdir -p ~/.local/bin
ln -sf "$PWD/scripts/cclsh-sbcl" ~/.local/bin/cclsh

The SBCL launcher is a source runner, not a saved application: it has no cclsh-fast mode and is not the supported target for /etc/shells or a login shell. Its edit command cannot yet use CCL’s source-note database. Use the CCL distribution below when those deployment modes or source-aware edit matter.

CCL on Linux x86-64

Requirements

Source development is tested with CCL 1.13 on Linux x86-64. It requires:

  • Git and Quicklisp
  • GNU make, coreutils, findutils, grep, awk, util-linux, m4 and binutils
  • a C toolchain
  • flock, runuser and getent for installation tooling

zoxide is optional. Install fzf as well to use zoxide’s interactive zi command.

Fetch source dependencies

Clone Clinedi, StructLisp, cl-colorist, ColorLisp and Colordiff beside the cclsh checkout, then select their locked revisions:

git clone https://github.com/lambda-symbolics/clinedi.git ../clinedi
git clone https://github.com/lambda-symbolics/structlisp.git ../structlisp
git clone https://github.com/lambda-symbolics/cl-colorist.git ../cl-colorist
git clone https://github.com/lambda-symbolics/colorlisp.git ../colorlisp
git clone https://github.com/lambda-symbolics/colordiff.git ../colordiff
for dependency in clinedi structlisp cl-colorist colorlisp colordiff; do
    commit=$(sed -n "s/^$dependency=//p" dependencies.lock)
    git -C "../$dependency" checkout --detach "$commit"
done

Set CCLSH_CLINEDI_SOURCE, CCLSH_STRUCTLISP_SOURCE, CCLSH_CL_COLORIST_SOURCE, CCLSH_COLORLISP_SOURCE or CCLSH_COLORDIFF_SOURCE when a checkout is not at its default sibling path. The build refuses a non-Git checkout, local modifications or a revision mismatch.

For interactive Quicklisp development, register the directory containing the checkouts in ~/quicklisp/local-init/common-lisp.lisp. Replace the example path with your checkout parent:

(in-package #:quicklisp-client)
(pushnew #P"/path/to/checkouts/"
         *local-project-directories*
         :test #'equal)

Set CCLSH_QUICKLISP_SETUP when Quicklisp’s setup.lisp is elsewhere. Saved images include Quicklisp and the five locked source dependencies, but the build copies only an allowlist of Quicklisp metadata. Personal local init files, proxy settings, caches and downloaded systems do not enter the image.

Run from stock CCL

Stock CCL is sufficient for regression checks and unsaved REPL development:

scripts/check
(require :asdf)
(asdf:load-system "cclsh")
(cclsh:main)

Build a standalone image

A standalone image requires the Linux xstate and cclsh argument-boundary changes from the LuciusMagn CCL fork, based on Clozure CL 1.13. Clone the fork and select the exact supported revision:

git clone https://github.com/luciusmagn/ccl.git ../ccl
git -C ../ccl checkout --detach 579c87300ee632af99182276f2ad40e1c38c5d0a
make ccl-kernel CCL_SOURCE=../ccl
make build CCL=../ccl/lx86cl64 \
  CCL_IMAGE=/usr/lib/ccl/lx86cl64.image

The boot image path is distribution-specific and must match the CCL source generation. At the selected revision, make ccl-kernel recognizes both changes as already applied and builds the kernel.

make build validates and activates a matched cclsh kernel and cclsh.image pair in the repository. It rejects stock CCL with kernel consumed a cclsh command operand. The files under patches/ are byte-stable mirrors used by system-shell build attestation. See the patch ledger for hashes, provenance, validation and upstream status.

Install the validated pair for one user:

make install BINDIR="$HOME/.local/bin"

To rebuild and install in one command:

CCLSH_CCL=../ccl/lx86cl64 \
CCLSH_CCL_IMAGE=/usr/lib/ccl/lx86cl64.image \
  scripts/install

scripts/install creates an owner-only installation in ~/.local/bin by default. A root make install without DESTDIR is refused; use the shared system-shell procedure below instead.

Experimental prewarmed launcher

The optional cclsh-fast command keeps one CCLSH worker loaded ahead of time. It accelerates only a no-argument interactive launch whose standard input, output and error are the same foreground terminal. Options, scripts, piped input, redirected sessions, login-style invocations and incompatible process contexts execute the sibling cclsh directly.

The Nix package includes both commands. For a source installation, install cclsh first, then place the launcher beside its stable path:

make fast
make install-fast BINDIR="$HOME/.local/bin"

Start the per-user daemon explicitly, then invoke the alternate command:

cclsh-fast daemon start
cclsh-fast daemon status
cclsh-fast

The daemon requires XDG_RUNTIME_DIR to be an absolute directory owned by the current user with no group or other permissions. Most systemd login sessions already provide one. For a development session without one, create a private directory before starting the daemon:

export XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-$HOME/.local/run}"
install -d -m 700 "$XDG_RUNTIME_DIR"

status prints the ready and active worker counts. It succeeds only when a matching daemon has at least one ready worker, so scripts can use it as a readiness probe. restart replaces the daemon and stop shuts it down. Both operations terminate active accelerated sessions and their terminal jobs.

If no ready compatible daemon answers within the short lease deadline, cclsh-fast immediately executes ordinary cclsh. Once a lease is committed, it cannot fall back without risking two shells, so a later proxy failure returns an error instead.

The client uses the direct runtime for nonstandard inherited signal state or terminal descriptor flags, an inheritable descriptor above standard error, a duplicate environment name, a different CPU affinity or resource/security context, and a nonempty GPG_TTY or SSH_TTY. The last two variables name the caller’s real terminal and cannot safely bypass the proxy. Workers also require matching credentials, namespaces, filesystem root, cgroups, LSM label, limits, scheduling state and exec-sensitive environment variables.

This is deliberately opt-in and is not a login-shell target. It relays the session through a private pseudoterminal, so programs can observe a different terminal and process topology. Detached or session-escaping jobs are not supported: they may be terminated or lose their terminal when the proxy ends. A worker also begins CCL initialization before the caller’s environment and directory are applied. The compatibility checks cannot make every possible process attribute retroactive and are not a sandbox boundary. Use a daemon only inside the same trusted user security domain, and stop it before testing unusual sandbox, capability or terminal setups. Ctrl-Z job control inside CCLSH is relayed, but externally suspending the proxy or worker process itself is not a supported accelerated-session operation.

The ordinary cclsh executable and every noninteractive interface remain independent of the daemon.

Verify process and terminal changes

Run the normal checks first:

scripts/check

After process, pipeline or terminal changes, rebuild the saved image and run the PTY integration checks:

CCLSH_CCL=../ccl/lx86cl64 \
CCLSH_CCL_IMAGE=/usr/lib/ccl/lx86cl64.image \
  scripts/build
CCLSH_CCL=../ccl/lx86cl64 \
CCLSH_CCL_IMAGE=/usr/lib/ccl/lx86cl64.image \
  scripts/integration-check

The integration command also builds and exercises cclsh-fast, including direct fallback, worker replacement, caller context transfer, Ctrl-C and terminal restoration.

Install a shared login shell

The shared installer creates one root-owned, user-neutral image and registers a stable executable path in /etc/shells. It never changes an account’s shell. Startup, history and writable Quicklisp state remain private to each account.

Build and install an attested release

Run the steps in this order:

scripts/check
make system-shell-build CCL_SOURCE=../ccl CCL=../ccl/lx86cl64 \
  CCL_IMAGE=/usr/lib/ccl/lx86cl64.image
make integration-check CCL=../ccl/lx86cl64 \
  CCL_IMAGE=/usr/lib/ccl/lx86cl64.image
sudo make install-system-shell

system-shell-build verifies both downstream CCL changes, rebuilds the kernel, publishes the image and writes cclsh.attestation over the patch and artifact hashes. Do not run a plain scripts/build afterward; a plain build removes the attestation.

install-system-shell validates the candidate before activation, switches its content-addressed release atomically and registers /usr/local/bin/cclsh in /etc/shells. It rejects a missing or stale attestation. Registration failure restores the previous release.

Set PROBE_USER to add a clean-home launch as an existing account:

sudo make install-system-shell PROBE_USER=USER

The probe is additional validation only. It does not bind the installation to that account. PREFIX, BINDIR and SHELLS_FILE select custom system paths; their parent directories must be canonical, root-owned and not writable by non-root users.

Configure an account

Create a private startup file:

install -d -m 700 ~/.config/cclsh
touch ~/.config/cclsh/startup.lisp
chmod 600 ~/.config/cclsh/startup.lisp

Use the example startup file as a template. If you have a source checkout, copy it from its absolute path rather than assuming that examples/ exists in the current directory.

A cclsh login shell does not source /etc/profile or another shell’s configuration. Ensure that PATH retains required system directories such as /usr/local/bin, /usr/bin and /bin. Test optional startup tools such as zoxide separately.

Change the login shell

Probe the installed command and configured environment first:

/usr/local/bin/cclsh --version
env CCLSH_SAFE=1 /usr/local/bin/cclsh -c 'exit 0'
/usr/local/bin/cclsh -lc 'echo $PATH'
chsh -s /usr/local/bin/cclsh

An administrator can change another account with:

sudo chsh -s /usr/local/bin/cclsh USER

Plain -c commands run without user state, as expected by sshd. Executables must already be visible in sshd’s environment; user-profile-only programs need an absolute path or a system-visible wrapper. Use -lc when a command should load startup.lisp. Command strings always use cclsh syntax, not sh syntax.

Root and recovery

Keep an existing privileged session open while testing. The conservative choice is to leave root or another privileged recovery account on a stock shell. If every privileged account uses cclsh, keep a tested boot-loader or live-system recovery route.

Only after validating that recovery path should you change root:

sudo chsh -s /usr/local/bin/cclsh root

Never use a repository artifact as an account’s shell; it can disappear after a clean. If startup state fails, bypass it with:

env CCLSH_SAFE=1 /usr/local/bin/cclsh

From a recovery account, restore a stock shell with chsh and verify the result with getent passwd USER before ending the recovery session.

Upgrade the shared shell

Rebuild, rerun the integration checks and install another attested release. The atomic stable path updates every account that uses it. Repeat the clean --version and -c probes before relying on the new release.