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
uses 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
has symlink
, a feature identifier gauche.sys.symlink
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:
gauche
This feature identifier is always defined. It is useful when you write Scheme code portable across multiple implementations.
gauche.os.windows
Defined on Windows native platform. Note that cygwin does not define this feature identifier (but see below).
gauche.os.cygwin
Defined on Cygwin.
gauche.sys.pthreads
gauche.sys.wthreads
Defined to indicate the underlying thread implementation.
See gauche.threads
- Threads.
gauche.net.ipv6
Defined if Gauche is compiled with IPv6 support.
Because 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
(using module-binds?
, see Module introspection)
doesn’t work well in this case, since
the 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 cond-expand
(see Feature conditional for the complete definition of
feature requirements).
By the definition of SRFI-0, cond-expand
raises an error
if no feature requirements are satisfied and there’s no else
clause. A rule of thumb is to provide else
clause always,
even it does nothing (like the above example that has empty else
clause).