logo raviqqe's logbook

Default library directories in Stak Scheme

Summary

What snow-chibi needs from an implementation

These facts come from the upstream source in lib/chibi/snow/.

Stak at 32410b5a4 (verified)

RequirementStatus
-A/-I flagsSupported by the interpreter and stak-compile
-A with a missing directoryWorks
.sld file with include relative to itWorks
Shebang scriptsWork
stak --versionPrints stak 0.12.28
Default library directoriesNone; the library-paths parameter starts empty
A way to print library directoriesNone from the command line; (library-paths) in (stak compile)
(exit 0)Exits with status 1 and prints Error: halt; fixed by #4143
cond-expand with (library (srfi 1))False, although (srfi 1) is built in; fixed by #4141
include-library-declarationsFails with procedure expected; fixed by #4144
-e flag to evaluate an expressionNone; the feature probe must go through a temporary file

The stak binary is defined by stak_sac::main! in sac/src/lib.rs, which parses arguments with clap before the Scheme program runs. -V and --version print the version and exit there. Every other argument, including -s and --heap-size, which clap also reads, reaches run.scm through the raw command line, so stak -s 2000000 foo.scm fails with unknown option "-s". A new flag therefore belongs in run.scm.

The mstak binary, a no_std build, runs the same run.scm, but its process context has no environment variables, so get-environment-variable always returns #f there.

Other implementations

The paths below are from Homebrew installations probed locally, except for Meevax, which comes from its source.

ImplementationDefault directoriesEnvironment variableHow to query
Chibi 0.12.0$PREFIX/share/chibi, $PREFIX/lib/chibi, /usr/local/{share,lib}/snow, ./lib, .CHIBI_MODULE_PATH(current-module-path)
Gauche 0.9.15$PREFIX/share/gauche-0.98/site/lib, then the versioned system libraryGAUCHE_LOAD_PATHgauche-config --sitelibdir, *load-path*, gosh -V
Guile 3.0.11$PREFIX/share/guile/3.0, .../site/3.0, .../site, $PREFIX/share/guileGUILE_LOAD_PATH%load-path, (%site-dir)
Sagittarius$PREFIX/share/sagittarius/sitelib, then versioned directoriesSAGITTARIUS_LOADPATH(load-path)
Chicken 6.0.0$PREFIX/lib/chicken/12CHICKEN_REPOSITORY_PATH(repository-path), chicken-install -repository
Chez. onlyCHEZSCHEMELIBDIRS(library-directories)
Racket 9.3Per-user collects, then the installation’s collectsPLTCOLLECTS(current-library-collection-paths)
Gambit 4.9.8~~userlib (~/.gambit_userlib), then ~~lib ($PREFIX/lib)GAMBOPT with search=DIR(path-expand "~~userlib")
Meevax$XDG_DATA_HOME/meevax (else ~/.local/share/meevax), $PREFIX/share/meevaxNonemeevax --library-directories

The last column lists ways to query each implementation, which are not always what snow-chibi uses. For example, snow-chibi installs Guile packages into (%site-ccache-dir). For other implementations snow-chibi supports, it queries (install-path #:libdir) on STklos, (scheme-library-paths) on Ypsilon, (scheme-paths) on TR7, (Cyc-installation-dir 'sld) on Cyclone, and (system-library-directory-pathname) on MIT Scheme.

Search order

Measured with an -I directory, an environment variable, and an -A directory all set:

Standards

Akku

Akku, the other Scheme package manager, installs into a project-local .akku/lib and generates an .akku/env script. That script exports each implementation’s own variable (CHIBI_MODULE_PATH, GAUCHE_LOAD_PATH, CHEZSCHEMELIBDIRS, GUILE_LOAD_PATH, SAGITTARIUS_LOADPATH, and others) and appends the shared R6RS_PATH and R7RS_PATH variables so that globally installed libraries remain reachable.

Conventions

Recommendation

  1. Search -I directories, then STAK_LIBRARY_PATH (colon-separated), then $XDG_DATA_HOME/stak (or ~/.local/share/stak), then a system directory such as /usr/local/share/stak, then -A directories. This matches Gauche and Guile.
  2. List the user directory before the system directory. Stak is installed with cargo install, so there is no installation prefix, and snow-chibi installs into the first directory it is given. A user directory first means installs without sudo, the same choice Meevax made.
  3. Add a command-line flag, handled in run.scm, that prints the directories one per line, in search order. The existing (library-paths) procedure in (stak compile) would return the same list. snow-chibi can reuse its Meevax code to find the install directory and to run tests, but its feature probe needs a temporary file, as Loko’s does, because Stak has no -e flag.
  4. Put the defaults in the interpreter and REPL drivers (run.scm and repl.scm), not in the compiler frontend. stak-compile and stak-build then keep producing the same bytecode regardless of what is installed on the machine, and embedded builds are unaffected. mstak shares run.scm but cannot read environment variables, so it can search only the system directory.
  5. Keep skipping directories that do not exist.

SRFI 176 is the standardized alternative to a custom flag, but it would replace clap’s -V handling in stak_sac::main!, which every binary built with that macro shares.

Decisions only the maintainer can make

Side findings

These are separate from what the issue asks but affect snow-chibi integration. The first three were found at 32410b5a4 and have been fixed on main since. The last two remain on main at 2b50ce988 and stop snow-fort’s (srfi 180), the issue’s example package, from loading, while Chibi 0.12.0 loads the same files.

  1. exit treats only #t or no argument as success. (exit 0) and (exit 3) both print Error: halt and exit with status 1. snow-chibi’s test runner fails any package test that exits with an integer, though tests ending with (test-exit) from (chibi test) pass because it exits with a boolean. The SRFI probe also ends with (exit 0), but snow-chibi ignores the probe’s exit status. Chibi and Gauche pass integer arguments through as exit codes, and R7RS asks implementations to translate the argument into an appropriate exit value. #4143 fixed it.
  2. cond-expand checks (library ...) requirements against a list fixed by define-features around line 334 of prelude.scm: (scheme base), (scheme read), (scheme write), (stak base), (stak continue), and (stak exception). (srfi 1), (scheme char), and every library on the load path test false, and (features) has no srfi-N entries. snow-chibi would conclude that Stak has no built-in SRFIs and install snow-fort’s (srfi 1), which Stak’s built-in library would then shadow because built-in libraries resolve before the load path. #4141 fixed it by checking built-in libraries and .sld files on the load path instead. snow-chibi’s probe now finds SRFI 1 and skips installing it as a natively implemented library, but the built-in (srfi 1) is partial and lacks procedures such as filter-map, take, and partition.
  3. include-library-declarations inside define-library fails with procedure expected. #4144 added it.
  4. The reader does not support the number prefixes #x, #b, #o, #d, #e, and #i, so #xd800 fails with invalid expression. (srfi 180) uses such literals, while its dependencies (srfi 60) and (srfi 145) load fine.
  5. cond-expand declarations inside define-library are ignored because register-library! in compile.scm collects only import, export, and begin declarations. snow-fort’s (srfi 64), which the (srfi 180) package needs for its test, selects its imports with cond-expand, so it loses them and fails with procedure expected.

Sources