Gauche tries to provide low-level APIs close to what the underlying
system provides, but sometimes they vary among systems. For example,
POSIX does not require
symlink, so some systems may lack
sys-symlink (see Directory manipulation). Quite a few
unix-specific system functions are not available on Windows platform.
To allow writing a portable program across those platforms, Gauche
cond-expand (see Feature conditional) extensively.
A set of extended feature-identifiers is provided to check
availability of specific features. For example, on systems that
symlink, a feature identifier
is defined. So you can write a code that can switch based on
the availability of
sys-symlink as follows:
(cond-expand (gauche.sys.symlink ... code that uses sys-symlink ...) (else ... alternative code ...) )
If you’re familiar with system programming in C, you can think it equivalent to the following C idiom:
#if defined(HAVE_SYMLINK) ... code that uses symlink ... #else ... alternative code ... #endif
There are quite a few such feature identifiers; each identifier is explained in the manual entry of the procedures that depend on the feature. Here we list a few important ones:
This feature identifier is always defined. It is useful when you write Scheme code portable across multiple implementations.
Defined on Windows native platform. Note that cygwin does not define this feature identifier (but see below).
Defined on Cygwin.
Defined if Gauche is compiled with thread support. See Threads.
Defined to indicate the underlying thread implementation when Gauche has thread support. See Threads.
Defined if Gauche is compiled with IPv6 support.
Either one of these feature identifiers is defined, according to the compile-time option of Gauche’s internal character encoding. See Multibyte strings, for the details of the internal character encoding.
cond-expand is a macro, the body of clauses
are expanded into toplevel if
cond-expand itself is in
toplevel. That means you can switch toplevel definitions:
(cond-expand (gauche.os.windows (define (get-current-user) ... get current username ...)) (else (define (get-current-user) (sys-uid->user-name (sys-getuid)))))
Or even conditionally "use" the modules:
(cond-expand (gauche.os.windows (use "my-windows-compatibility-module")) (else))
The traditional technique of testing a toplevel binding
global-variable-bound?, see Module introspection)
doesn’t work well in this case, since
use form takes effect at compile time.
It is strongly recommended to use
cond-expand whenever possible.
Currently the set of feature identifiers are fixed at the build time of Gauche, so it’s less flexible than C preprocessor conditionals. We have a plan to extend this feature to enable adding new feature identifiers; but such feature can complicate semantics when compilation and execution is interleaved, so we’re carefully assessing the effects now.
A couple of notes:
Feature identifiers are not variables. They can only be used
within the feature-requirement part of
(see Feature conditional for the complete definition of
By the definition of
cond-expand raises an error
if no feature requirements are satisfied and there’s no
clause. A rule of thumb is to provide
else clause always,
even it does nothing (like the above example that has empty