Syntax and conditional compilation

Feature testing

Syntax: cond-expand cond-expand-clause* [(else command-or-definition*)]

cond-expand-clause ::= (feature-requirement command-or-definition*)
feature-requirement ::= feature-identifier
  | (and feature-requirement*)
  | (or feature-requirement*)
  | (not feature-requirement)
  | (library library-name)
feature-identifier ::= a symbol which is the name or alias of a SRFI

The cond-expand form tests for the existence of features at macro-expansion time. It either expands into the body of one of its clauses or signals an error during syntactic processing. cond-expand expands into the body of the first clause whose feature requirement is currently satisfied; the else clause, if present, is selected if none of the previous clauses is selected.

The implementation has a set of feature identifiers which are “present”, as well as a set of libraries which can be imported. The value of a feature-requirement is determined by replacing each feature-identifier by #t if it is present (and #f otherwise); replacing (library library-name) by #t if library-name is importable (and #f otherwise); and then evaluating the resulting expression as a Scheme boolean expression under the normal interpretation of and, or, and not.


    ((and srfi-1 srfi-10)
     (write 1))
    ((or srfi-1 srfi-10)
     (write 2))
   (define (program-name) (car (argv)))))

The second example assumes that command-line is an alias for some feature which gives access to command line arguments. Note that an error will be signaled at macro-expansion time if this feature is not present.

You can use java-6, java-7, java-8, or java-9 to check check if the underlying Java is a specific version or newer. For example the name java-7 matches for either Java 7, Java 8, or newer, as reported by System property "java.version".

You can use class-exists:ClassName to check if ClassName exists at compile-time. The identifier class-exists:org.example.MyClass is roughly equivalent to the test (library (org example MyClass)). (The latter has some special handling for (srfi ...) as well as builtin Kawa classes.)

Procedure: features

Returns a list of feature identifiers which cond-expand treats as true. This not a complete list - for example class-exists:ClassName feature identifiers are not included. It is an error to modify this list. Here is example of what features might return:

(features)  ⇒
(complex exact-complex full-unicode java-7 java-6 kawa
 ratios srfi-0 srfi-4 srfi-6 srfi-8 srfi-9 srfi-11
 srfi-16 srfi-17 srfi-23 srfi-25 srfi-26 srfi-28 srfi-30
 srfi-39 string-normalize-unicode threads)

File inclusion

Syntax: include path+

Syntax: include-relative path+

Syntax: include-ci path+

These take one or more path names expressed as string literals, find corresponding files, read the contents of the files in the specified order as if by repeated applications of read, and effectively replace the include with a begin form containing what was read from the files.

You can control the search path used for include by setting the kawa.include.path property. For example:

$ kawa -Dkawa.include.path="|:/opt/kawa-includes"

The special "|" path element means to search relative to the directory containing the including source file. The default search path is "|:." which means to first search the directory containing the including source file, and then search the directory specified by (current-path).

The search path for include-relative prepends "|" before the search path used by include, so it always searches first the directory containing the including source file. Note that if the default search path is used then include and include-relative are equivalent; there is only a difference if the kawa.include.path property changes the default.

Using include-ci is like include, except that it reads each file as if it began with the #!fold-case directive.