For Gauche 0.9.5


Next: , Previous: , Up: Programming in Gauche   [Contents][Index]

3.5 Using platform-dependent features

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 maunal 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.threads

Defined if Gauche is compiled with thread support. See Threads.

gauche.sys.pthreads
gauche.sys.wthreads

Defined to indicate the underlying thread implementation when Gauche has thread support. See Threads.

gauche.net.ipv6

Defined if Gauche is compiled with IPv6 support.

gauche.ces.utf8
gauche.ces.eucjp
gauche.ces.sjis
gauche.ces.none

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.

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 global-variable-bound?, 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).


Next: , Previous: , Up: Programming in Gauche   [Contents][Index]