Chapter 10. Libraries and Top-level Programs

The Revised6 Report describes two units of portable code: libraries and top-level programs. A library is a named collection of bindings with a declared set of explicitly exported bindings, a declared set of imported libraries, and a body that initializes its bindings. A top-level program is a stand-alone program with a declared set of imported libraries and a body that is run when the top-level program is run. The bindings in a library are created and its initialization code run only if the library is used, directly or indirectly, by a top-level program.

The import declarations appearing within libraries and top-level programs serve two purposes: first, they cause the imported libraries to be loaded, and second, they cause the bindings of the imported libraries to become visible in the importing library or top-level program. Libraries are typically stored in the file system, with one library per file, and the library name typically identifies the file-system path to the library, possibly relative to a default or programmer-specified set of library locations. The exact mechanism by which top-level programs are run and libraries are loaded is implementation-dependent.

This chapter describes the mechanisms by which libraries and programs are loaded in Chez Scheme along with various features for controlling and tracking this process. It also describes the set of built-in libraries and syntactic forms for defining new libraries and top-level programs outside of a library or top-level program file.

Section 10.1. Built-in Libraries

In addition to the RNRS libraries mandated by the Revised6 Report:

  (rnrs base (6))
  (rnrs arithmetic bitwise (6))
  (rnrs arithmetic fixnums (6))
  (rnrs arithmetic flonums (6))
  (rnrs bytevectors (6))
  (rnrs conditions (6))
  (rnrs control (6))
  (rnrs enums (6))
  (rnrs eval (6))
  (rnrs exceptions (6))
  (rnrs files (6))
  (rnrs hashtables (6))
  (rnrs io ports (6))
  (rnrs io simple (6))
  (rnrs lists (6))
  (rnrs mutable-pairs (6))
  (rnrs mutable-strings (6))
  (rnrs programs (6))
  (rnrs r5rs (6))
  (rnrs records procedural (6))
  (rnrs records syntactic (6))
  (rnrs records inspection (6))
  (rnrs sorting (6))
  (rnrs syntax-case (6))
  (rnrs unicode (6))

Chez Scheme also provides two additional libraries: (chezscheme) and (chezscheme csv7). The former can also be referenced as (scheme) and the latter can also be referenced as (scheme csv7).

The (chezscheme) library exports bindings for every identifier whose binding is described in this document, including those for keywords like lambda, auxiliary keywords like else, module names like scheme, and procedure names like cons. In most cases where an identifier exported from the (chezscheme) library corresponds to an identifier exported from one of the RNRS libraries, the bindings are identical. In some cases, however, the (chezscheme) bindings extend the rnrs bindings in some way. For example, the (chezscheme) syntax-rules form allows its clauses to have fenders (Section 11.2), while the (rnrs) syntax-rules form does not. Similarly, the (chezscheme) current-input-port procedure accepts an optional port argument that, when specified, sets the current input port to port (Section 9.8), while the (rnrs) current-input-port procedure does not. When the (chezscheme) library extends an RNRS binding in some way, the (chezscheme) library also exports the RNRS version, with the name prefixed by r6rs:, e.g., r6rs:syntax-rules or r6rs:current-input-port.

The (chezscheme csv7) Version 7 backward compatibility library contains bindings for a set of syntactic forms and procedures whose syntax or semantics directly conflicts with the RNRS bindings for the same identifiers. The following identifiers are exported from (chezscheme csv7).


The bindings of this library should be used only for old code; new code should use the RNRS variants. Each of these is also available in the (chezscheme) library with the prefix csv7:, e.g., csv7:record-type-name.

The interaction environment in which code outside of a library or RNRS top-level program is scoped contains all of the bindings of the (chezscheme) library, as described in Section 2.3.

Section 10.2. Running Top-level Programs

A top-level program must reside in its own file, which may have any name and may reside anywhere in the file system. A top-level program residing in a file is run by one of three mechanisms: the scheme-script command, the --program command-line argument, or the load-program procedure.

The scheme-script command is used as follows:

scheme-script program-filename arg ...

It may also be run implicitly on Unix-based systems by placing the line

#! /usr/bin/env scheme-script

at the front of the file containing the top-level program, making the top-level program file executable, and executing the file. This line may be replaced with

#! /usr/bin/scheme-script

with /usr/bin replaced by the absolute path to the directory containing scheme-script if it is not in /usr/bin. The first form is recommended in the nonnormative appendices to the Revised6 Report [29], and works wherever scheme-script appears in the path.

The --program command is used similarly with the scheme or petite executables, either by running:

scheme --program program-filename arg ...
petite --program program-filename arg ...

or by including

#! /usr/bin/scheme --script


#! /usr/bin/petite --script

at the front of the top-level program file, making the file executable, and executing the file. Again, /usr/bin should be replaced with the absolute path to the actual directory in which scheme and/or petite resides, if not /usr/bin.

The load-program procedure, described in Section 12.4, is used like load:

(load-program string)

where string names the file in which the top-level program resides.

Regardless of the mechanism used, if the opening line is in one of the forms described above, or more generally, consists of #! followed by a space or a forward slash, the opening line is not considered part of the program and is ignored once the Scheme system starts up and begins to run the program. Thus, the line may be present even in a file loaded by load-program. In fact, load-program is ultimately used by the other two mechanisms described above, via the value of the scheme-program parameter described in Section 12.8, and it is load-program that scans past the #! line, if present, before evaluating the program.

A top-level program may be compiled with the compile-program procedure described in Section 12.4. compile-program copies the #! line from the source file to the object file, followed by a compiled version of the source code. Any libraries upon which the top-level program depends, other than built-in libraries, must be compiled first via compile-file or compile-library. This can be done manually or by setting the parameter compile-imported-libraries to #t before compiling the program. The program must be recompiled if any of the libraries upon which it depends are recompiled. A compiled top-level program can be run just like a source top-level program via each of the mechanisms described above.

In Chez Scheme, a library may also be defined in the REPL or placed in a file to be loaded via load or load-library. The syntax for a library is the same whether the library is placed in its own file and implicitly loaded via import, entered into the REPL, or placed in a file along with other top-level expressions to be evaluated by load. A top-level program may also be defined in the REPL or placed in a file to be loaded via load, but in this case, the syntax is slightly different. In the language of the Revised6 Report, a top-level program is merely an unwrapped sequence of subforms consisting of an import form and a body, delimited only by the boundaries of the file in which it resides. In order for a top-level program to be entered in the REPL or placed in a file to be evaluated by load, Chez Scheme allows top-level programs to be enclosed in a top-level-program form.

Section 10.3. Library and Top-level Program Forms

syntax: (library name exports imports library-body)
returns: unspecified
libraries: (chezscheme)

The library form defines a new library with the specified name, exports, imports, and body. Details on the syntax and semantics of the library form are given in Section 10.3 of The Scheme Programming Language, 4th Edition and in the Revised6 Report.

Only one version of a library can be loaded at any given time, and an exception is raised if a library is implicitly loaded via import when another version of the library has already been loaded. Chez Scheme permits a different version of the library, or a new instance of the same version, to be entered explicitly into the REPL or loaded explicitly from a file, to facilitate interactive testing and debugging. The programmer should take care to make sure that any code that uses the library is also reentered or reloaded, to make sure that code accesses the bindings of the new instance of the library.

(library (test (1)) (export x) (import (rnrs)) (define x 3))
(import (test))
(define f (lambda () x))
(f) <graphic> 3

(library (test (1)) (export x) (import (rnrs)) (define x 4))
(import (test))
(f) <graphic> 3    ; oops---forgot to redefine f
(define f (lambda () x))
(f) <graphic> 4

(library (test (2)) (export x) (import (rnrs)) (define x 5))
(import (test))
(define f (lambda () x))
(f) <graphic> 5

As with module imports (Section 11.5), a library import may appear anywhere a definition may appear, including at top level in the REPL, in a file to be loaded by load, or within a lambda, let, letrec, letrec*, etc., body. The same import form may be used to import from both libraries and modules.

(library (foo) (export a) (import (rnrs)) (define a 'a-from-foo))
(module bar (b) (define b 'b-from-bar))
(let () (import (foo) bar) (list a b)) <graphic> (a-from-foo b-from-bar)

The import keyword is not visible within a library body unless the library imports it from the (chezscheme) library.

syntax: (top-level-program imports body)
returns: unspecified
libraries: (chezscheme)

A top-level-program form may be entered into the REPL or placed in a file to be loaded via load, where it behaves as if its subforms were placed in a file and loaded via load-program. Details on the syntax and semantics of a top-level program are given in Section 10.3 of The Scheme Programming Language, 4th Edition and in the Revised6 Report.

The following transcript illustrates a top-level-program being tested in the REPL.

> (top-level-program (import (rnrs))
    (display "hello!\n"))

Section 10.4. Standalone import and export forms

Although not required by the Revised6 Report, Chez Scheme supports the use of standalone import and export forms. The import forms can appear anywhere other definitions can appear, including within a library body, module (Section 11.5) body, lambda or other local body, and at top level. The export forms can appear within the definitions of a library or module body to specify additional exports for the library or module.

Within a library or top-level program, the keywords for these forms must be imported from the (chezscheme) library to be available for use, since they are not defined in any of the Revised6 Report libraries.

syntax: (import import-spec ...)
syntax: (import-only import-spec ...)
returns: unspecified
libraries: (chezscheme)

An import or import-only form is a definition and can appear anywhere other definitions can appear, including at the top level of a program, nested within the bodies of lambda expressions, and nested within modules and libraries.

Each import-spec must take one of the following forms.

(for import-set import-level ...)

The for wrapper and import-level are described in Chapter 10 of The Scheme Programming Language, 4th Edition. They are ignored by Chez Scheme, which determines automatically the levels at which identifiers must be imported, as permitted by the Revised6 Report. This frees the programmer from the obligation to do so and results in more generality as well as more precision in the set of libraries actually imported at compile and run time [21,19].

An import-set must take one of the following forms:

(only import-set identifier ...)
(except import-set identifier ...)
(prefix import-set prefix)
(add-prefix import-set prefix)
(drop-prefix import-set prefix)
(rename import-set (import-name internal-name) ...)
(alias import-set (import-name internal-name) ...)

Several of these are specified by the Revised6 Report; the remainder are Chez Scheme extensions, including module-name and the add-prefix, drop-prefix, and alias forms.

An import or import-only form makes the specified bindings visible in the scope in which they appear. Except at top level, they differ in that import leaves all bindings except for those shadowed by the imported names visible, whereas import-only hides all existing bindings, i.e., makes only the imported names visible. At top level, import-only behaves like import.

Each import-set identifies a set of names to make visible as follows.

all exports of the library identified by the Revised6 Report library-spec (Chapter 10).

all exports of module named by the identifier module-name

(only import-set identifier ...):
of those specified by import-set, just identifier ...

(except import-set identifier ...):
all specified by import-set except identifier ...

(prefix import-set prefix):
all specified by import-set, each prefixed by prefix

(add-prefix import-set prefix):
all specified by import-set, each prefixed by prefix (just like prefix)

(drop-prefix import-set prefix):
all specified by import-set, with prefix prefix removed

(rename import-set (import-name internal-name) ...):
all specified by import-set, with each identifier import-name renamed to the corresponding identifier internal-name

(alias import-set (import-name internal-name) ...):
all specified by import-set, with each internal-name as an alias for import-name

The alias form differs from the rename form in that both import-name and internal-name are in the resulting set, rather than just internal-name.

It is a syntax violation if the given selection or transformation cannot be made because of a missing export or prefix.

An identifier made visible via an import of a module or library is scoped as if its definition appears where the import occurs. The following example illustrates these scoping rules, using a local module m.

(library (A) (export x) (import (rnrs)) (define x 0))
(let ([x 1])
  (module m (x setter)
    (define-syntax x (identifier-syntax z))
    (define setter (lambda (x) (set! z x)))
    (define z 2))
  (let ([y x] [z 3])
    (import m (prefix (A) a:))
    (setter 4)
    (list x a:x y z))) <graphic> (4 0 1 3)

The inner let expression binds y to the value of the x bound by the outer let. The import of m makes the definitions of x and setter visible within the inner let. The import of (A) makes the variable x exported from (A) visible as a:x within the body of the inner let. Thus, in the expression (list x a:x y z), x refers to the identifier macro exported from m while a:x refers to the variable x exported from (A) and y and z refer to the bindings established by the inner let. The identifier macro x expands into a reference to the variable z defined within the module.

With local import forms, it is rarely necessary to use the extended import specifiers. For example, an abstraction that encapsulates the import and reference can easily be defined and used as follows.

(define-syntax from
  (syntax-rules ()
    [(_ m id) (let () (import-only m) id)]))

(library (A) (export x) (import (rnrs)) (define x 1))
(let ([x 10])
  (module M (x) (define x 2))
  (cons (from (A) x) (from M x))) <graphic> (1 . 2)

The definition of from could use import rather than import-only, but by using import-only we get feedback if an attempt is made to import an identifier from a library or module that does not export the identifier. With import instead of import-only, the current binding, if any, would be visible if the library or module does not export the specified name.

(define-syntax lax-from
  (syntax-rules ()
    [(_ m id) (let () (import m) id)]))

(library (A) (export x) (import (rnrs)) (define x 1))

(let ([x 10])
  (module M (x) (define x 2))
  (+ (from (A) x) (from M y))) <graphic> exception: unbound identifier y
(let ([x 10] [y 20])
  (module M (x) (define x 2))
  (+ (lax-from (A) x) (lax-from M y))) <graphic> 21

Import visibility interacts with hygienic macro expansion in such a way that, as one might expect, an identifier x imported from a module M is treated in the importing context as if the corresponding export identifier had been present in the import form along with M.

The from abstraction above works because both M and id appear in the input to the abstraction, so the imported id captures the reference to id.

The following variant of from also works, because both names are introduced into the output by the transformer.

(module M (x) (define x 'x-of-M))
(define-syntax x-from-M
  (syntax-rules ()
    [(_) (let () (import M) x)]))

(let ([x 'local-x]) (x-from-M)) <graphic> x-of-M

On the other hand, imports of introduced module names do not capture free references.

(let ([x 'local-x])
  (define-syntax alpha
    (syntax-rules ()
      [(_ var) (let () (import M) (list x var))]))
  (alpha x)) <graphic> (x-of-M local-x)

Similarly, imports from free module names do not capture references to introduced variables.

(let ([x 'local-x])
  (define-syntax beta
    (syntax-rules ()
      [(_ m var) (let () (import m) (list x var))]))

  (beta M x)) <graphic> (local-x x-of-M)

This semantics extends to prefixed, renamed, and aliased bindings created by the extended import specifiers prefix, rename, and alias.

The from abstraction works for variables but not for exported keywords, record names, or module names, since the output is an expression and may thus appear only where expressions may appear. A generalization of this technique is used in the following definition of import*, which supports renaming of imported bindings and selective import of specific bindings---without the use of the built-in import subforms for selecting and renaming identifiers

(define-syntax import*
  (syntax-rules ()
    [(_ m) (begin)]
    [(_ m (new old))
     (module (new)
       (module (tmp)
         (import m)
         (alias tmp old))
       (alias new tmp))]
    [(_ m id) (module (id) (import m))]
    [(_ m spec0 spec1 ...)
     (begin (import* m spec0) (import* m spec1 ...))]))

To selectively import an identifier from module or library m, the import* form expands into an anonymous module that first imports all exports of m then re-exports only the selected identifier. To rename on import the macro expands into an anonymous module that instead exports an alias (Section 11.10) bound to the new name.

If the output placed the definition of new in the same scope as the import of m, a naming conflict would arise whenever new is also present in the interface of m. To prevent this, the output instead places the import within a nested anonymous module and links old and new by means of an alias for the introduced identifier tmp.

The macro expands recursively to handle multiple import specifications. Each of the following examples imports cons as + and + as cons, which is probably not a very good idea.

(let ()
  (import* scheme (+ cons) (cons +))
  (+ (cons 1 2) (cons 3 4))) <graphic> (3 . 7)

(let ()
  (import* (rnrs) (+ cons) (cons +))
  (+ (cons 1 2) (cons 3 4))) <graphic> (3 . 7)

syntax: (export export-spec ...)
returns: unspecified
libraries: (chezscheme)

An export form is a definition and can appear with other definitions at the front of a library or module. It is a syntax error for an export form to appear in other contexts, including at top level or among the definitions of a top-level program or lambda body.

Each export-spec must take one of the following forms.

(rename (internal-name export-name) ...)
(import import-spec ...)

where each internal-name and export-name is an identifier. The first two are syntactically identical to library export-specs, while the third is syntactically identical to a Chez Scheme import form, which is an extension of the R6RS library import subform. The first form names a single export, identifier, whose export name is the same as its internal name. The second names a set of exports, each of whose export name is given explicitly and may differ from its internal name.

For the third, the identifiers identified by the import form become exports, with aliasing, renaming, prefixing, etc., as specified by the import-specs. The module or library whose bindings are exported by an import form appearing within an export form can be defined within or outside the exporting module or library and need not be imported elsewhere within the exporting module or library.

The following library exports a two-armed-only variant of if along with all remaining bindings of the (rnrs) library.

(library (rnrs-no-one-armed-if) (export) (import (except (chezscheme) if))
  (export if (import (except (rnrs) if)))
  (define-syntax if
    (let ()
      (import (only (rnrs) if))
      (syntax-rules ()
        [(_ tst thn els) (if tst thn els)]))))

(import (rnrs-no-one-armed-if))
(if #t 3 4) <graphic> 3
(if #t 3) <graphic> exception: invalid syntax

Another way to define the same library would be to define the two-armed-only if with a different internal name and use rename to export it under the name if:

(library (rnrs-no-one-armed-if) (export) (import (chezscheme))
  (export (rename (two-armed-if if)) (import (except (rnrs) if)))
  (define-syntax two-armed-if
    (syntax-rules ()
      [(_ tst thn els) (if tst thn els)])))

(import (rnrs-no-one-armed-if))
(if #t 3 4) <graphic> 3
(if #t 3) <graphic> exception: invalid syntax

The placement of the export form in the library body is irrelevant, e.g., the export form can appear after the definition in the examples above.

syntax: (indirect-export id indirect-id ...)
returns: unspecified
libraries: (chezscheme)

This form is a definition and can appear wherever any other definition can appear.

An indirect-export form declares that the named indirect-ids are indirectly exported to top level if id is exported to top level.

In general, if an identifier is not directly exported by a library or module, it can be referenced outside of the library or module only in the expansion of a macro defined within and exported from the library or module. Even this cannot occur for libraries or modules defined at top level (or nested within other libraries or modules), unless either (1) the library or module has been set up to implicitly export all identifiers as indirect exports, or (2) each indirectly exported identifier is explicitly declared as an indirect export of some other identifier that is exported, either directly or indirectly, from the library or module, via an indirect-export or the built-in indirect export feature of a module export subform. By default, (1) is true for a library and false for a module, but the default can be overridden via the implicit-exports form, which is described below.

This form is meaningful only within a top-level library, top-level module, or module enclosed within a library or top-level module, although it has no effect if the library or module already implicitly exports all bindings. It is allowed anywhere else definitions can appear, however, so macros that expand into indirect export forms can be used in any definition context.

Indirect exports are listed so the compiler can determine the exact set of bindings (direct and indirect) that must be inserted into the top-level environment, and conversely, the set of bindings that may be treated more efficiently as local bindings (and perhaps discarded, if they are not used).

In the example below, indirect-export is used to indirectly export count to top level when current-count is exported to top level.

(module M (bump-count current-count)
  (define-syntax current-count (identifier-syntax count))
  (indirect-export current-count count)
  (define count 0)
  (define bump-count
    (lambda ()
      (set! count (+ count 1)))))

(import M)
current-count <graphic> 1
count <graphic> exception: unbound identifier count

An indirect-export form is not required to make count visible for bump-count, since it is a procedure whose code is contained within the module rather than a macro that might expand into a reference to count somewhere outside the module.

It is often useful to use indirect-export in the output of a macro that expands into another macro named a if a expands into references to identifiers that might not be directly exported, as illustrated by the alternative definition of module M above.

(define-syntax define-counter
  (syntax-rules ()
    [(_ getter bumper init incr)
       (define count init)
       (define-syntax getter (identifier-syntax count))
       (indirect-export getter count)
       (define bumper
         (lambda ()
           (set! count (incr count)))))]))

(module M (bump-count current-count)
  (define-counter current-count bump-count 0 add1))

syntax: (implicit-exports #t)
syntax: (implicit-exports #f)
returns: unspecified
libraries: (chezscheme)

An implicit-exports form is a definition and can appear with other definitions at the front of a library or module. It is a syntax error for an implicit-exports form to appear in other contexts, including at top level or among the definitions of a top-level program or lambda body.

The implicit-exports form determines whether identifiers not directly exported from a module or library are automatically indirectly exported to the top level if any meta-binding (keyword, meta definition, or property definition) is directly exported to top level from the library or module. The default for libraries is #t, to match the behavior required by the Revised6 Report, while the default for modules is #f. The implicit-exports form is meaningful only within a library, top-level module, or module enclosed within a library or top-level module. It is allowed in a module enclosed within a lambda, let, or similar body, but ignored there because none of that module's bindings can be exported to top level.

The advantage of (implicit-exports #t) is that indirect exports need not be listed explicitly, which is convenient. A disadvantage is that it often results in more bindings than necessary being elevated to top level where they cannot be discarded as useless by the optimizer. For modules, another disadvantage is such bindings cannot be proven immutable, which inhibits important optimizations such as procedure inlining. This can result in significantly lower run-time performance.

Section 10.5. Explicitly invoking libraries

procedure: (invoke-library libref)
returns: unspecified
libraries: (chezscheme)

libref must be an s-expression in the form of a library reference. The syntax for library references is given in Chapter 10 of The Scheme Programming Language, 4th Edition and in the Revised6 Report.

A library is implicitly invoked when or before some expression outside the library (e.g., in another library or in a top-level program) evaluates a reference to one of the library's exported variables. When the library is invoked, its body expressions (the right-hand-sides of the library's variable definitions and its initialization expressions) are evaluated. Once invoked, the library is not invoked again within the same process, unless it is first explicitly redefined or reloaded.

invoke-library explicitly invokes the library specified by libref if it has not already been invoked or has since been redefined or reloaded. If the library has not yet been loaded, invoke-library first loads the library via the process described in Section 2.4.

invoke-library is typically only useful for libraries whose body expressions have side effects. It is useful to control when the side effects occur and to force invocation of a library that has no exported variables. Invoking a library does not force the compile-time code (macro transformer expressions and meta definitions) to be loaded or evaluated, nor does it cause the library's bindings to become visible.

It is good practice to avoid externally visible side effects in library bodies so the library can be used equally well at compile time and run time. When feasible, consider moving the side effects of a library body to an initialization routine and adding a top-level program that imports the library and calls the initialization routine. With this structure, calls to invoke-library on the library can be replaced by calls to load-program on the top-level program.

Section 10.6. Library Parameters

The parameters described below control where import looks when attempting to load a library, whether it compiles the libraries it loads, and whether it displays tracking messages as it performs its search.

thread parameter: library-directories
thread parameter: library-extensions
libraries: (chezscheme)

The parameter library-directories determines where the files containing library source and object code are located in the file system, and the parameter library-extensions determines the filename extensions for the files holding the code, as described in section 2.4. The values of both parameters are lists of pairs of strings. The first string in each library-directories pair identifies a source-file root directory, and the second identifies the corresponding object-file root directory. Similarly, the first string in each library-extensions pair identifies a source-file extension, and the second identifies the corresponding object-file extension. The full path of a library source or object file consists of the source or object root followed by the components of the library name prefixed by slashes, with the library extension added on the end. For example, for root /usr/lib/scheme, library name (app lib1), and extension .sls, the full path is /usr/lib/scheme/app/lib1.sls. If the library name portion forms an absolute pathname, e.g., ~/.myappinit, the library-directories parameter is ignored and no prefix is added.

The initial values of these parameters are shown below.

(library-directories) <graphic> (("." . "."))

(library-extensions) <graphic> ((".chezscheme.sls" . "")
                       (".ss" . ".so")
                       (".sls" . ".so")
                       (".scm" . ".so")
                       (".sch" . ".so"))

As a convenience, when either of these parameters is set, any element of the list can be specified as a single source string, in which case the object string is determined automatically. For library-directories, the object string is the same as the source string, effectively naming the same directory as a source- and object-code root. For library-extensions, the object string is the result of removing the last (or only) extension from the string and appending ".so". The library-directories and library-extensions parameters also accept as input strings in the format described in Section 2.5 for the --libdirs and --libexts command-line options.

thread parameter: compile-imported-libraries
libraries: (chezscheme)

When the value of this parameter is #t, import automatically calls the value of the compile-library-handler parameter (which defaults to a procedure that simply calls compile-library) on any imported library if the object file is missing, older than the corresponding source file, older than any source files included (via include) when the object file was created, or itself requires a library that has been or must be recompiled, as described in Section 2.4. The default initial value of this parameter is #f. It can be set to #t via the command-line option --compile-imported-libraries.

When import compiles a library via this mechanism, it does not also load the compiled library, because this would cause portions of library to be reevaluated. Because of this, run-time expressions in the file outside of a library form will not be evaluated. If such expressions are present and should be evaluated, the library should be loaded explicitly.

thread parameter: import-notify
libraries: (chezscheme)

When the new parameter import-notify is set to a true value, import displays messages to the console-output port as it searches for the file containing each library it needs to load. The default value of this parameter is #f.

thread parameter: library-search-handler
libraries: (chezscheme)

The value of parameter must be a procedure that follows the protocol described below for default-library-search-handler, which is the default value of this parameter.

The value of this parameter is invoked to locate the source or object code for a library during import, compile-whole-program, or compile-whole-library.

procedure: (default-library-search-handler who library directories extensions)
returns: see below
libraries: (chezscheme)

This procedure is the default value of the library-search-handler, which is called to locate the source or object code for a library during import, compile-whole-program, or compile-whole-library. who is a symbol that provides context in import-notify messages. library is the name of the desired library. directories is a list of source and object directory pairs in the form returned by library-directories. extensions is a list of source and object extension pairs in the form returned by library-extensions.

This procedure searches the specified directories until it finds a library source or object file with one of the specified extensions. If it finds the source file first, it constructs the corresponding object file path and checks whether the file exists. If it finds the object file first, the procedure looks for a corresponding source file with one of the given source extensions in a source directory paired with that object directory. The procedure returns three values: the file-system path of the library source file or #f if not found, the file-system path of the corresponding object file, which may be #f, and a boolean that is true if the object file exists.

Section 10.7. Library Inspection

procedure: (library-list)
returns: a list of the libraries currently defined
libraries: (chezscheme)

The set of libraries initially defined includes those listed in Section 10.1 above.

procedure: (library-version libref)
returns: the version of the specified library
procedure: (library-exports libref)
returns: a list of the exports of the specified library
procedure: (library-requirements libref)
returns: a list of libraries required by the specified library
procedure: (library-requirements libref options)
returns: a list of libraries required by the specified library, filtered by options
procedure: (library-object-filename libref)
returns: the name of the object file holding the specified library, if any
libraries: (chezscheme)

Information can be obtained only for built-in libraries or libraries previously loaded into the system. libref must be an s-expression in the form of a library reference. The syntax for library references is given in Chapter 10 of The Scheme Programming Language, 4th Edition and in the Revised6 Report.

The library-version return value is a list of numbers (possibly empty) representing the library's version.

The list of exports returned by library-exports is a list of symbols, each identifying one of the library's exports. The order in which the elements appear is unspecified.

When the optional options argument is supplied, it must be an enumeration set over the symbols constituting valid library-requirements options, as described in the library-requirements-options entry below. It defaults to a set containing all of the options. Each element of the list of libraries returned by library-requirements is an s-expression form of a library reference. The library reference includes the actual version of the library that is present in the system (if nonempty), even if a version was not specified when it was imported. The order in which the libraries appear in the list returned by library-requirements is unspecified.

library-object-filename returns a string naming the object file if the specified library was loaded from or compiled to an object file. Otherwise, it returns #f.

(with-output-to-file ""
  (lambda ()
      '(library (A (1 2)) (export x z)
         (import (rnrs))
         (define x 'ex)
         (define y 23)
         (define-syntax z
           (syntax-rules ()
             [(_ e) (+ y e)])))))
(with-output-to-file ""
  (lambda ()
      '(library (B) (export x w)
         (import (rnrs) (A))
         (define w (cons (z 12) x)))))
(compile-imported-libraries #t)
(import (B))
(library-exports '(A)) <graphic> (x z) ; or (z x)
(library-exports '(A (1 2))) <graphic> (x z) ; or (z x)
(library-exports '(B)) <graphic> (x w) ; or (w x)
(library-version '(A)) <graphic> (1 2)
(library-version '(B)) <graphic> ()
(library-requirements '(A)) <graphic> ((rnrs (6)))
(library-requirements '(B)) <graphic> ((rnrs (6)) (A (1 2)))
(library-object-filename '(A)) <graphic> ""
(library-object-filename '(B)) <graphic> ""

syntax: (library-requirements-options symbol ...)
returns: a library-requirements-options enumeration set
libraries: (chezscheme)

Library-requirements-options enumeration sets are passed to library-requirements to determine the library requirements to be listed. The available options are described below.

Include the libraries that must be imported when the specified library is imported.

Includes the libraries that must be visited when the specified library is visited.

Include the libraries that must be invoked when the specified library is visited.

Includes the libraries that must be invoked when the specified library is invoked.

Chez Scheme Version 9 User's Guide
Copyright © 2023 Cisco Systems, Inc.
Licensed under the Apache License Version 2.0 (full copyright notice.).
Revised October 2023 for Chez Scheme Version 9.6.4
about this book