GaucheではOSが提供するAPIに近い低レベルAPIを提供するようにしています。
しかし、システムごとに扱いの違うものがあります。たとえば、POSIXでは
symlinkは必須ではありませんので、システムによっては
sys-symlink (ディレクトリ操作参照)がありません。
UNIX系のシステム関数は少なからずWindowsでは使えません。
プラットフォーム間でポータブルなプログラムを書くために、Gaucheでは
頻繁にcond-expand を使います(機能条件式参照)。
拡張された機能識別子(feature-identifier)が提供されており、これ
を使って特定の機能が利用可能かどうかチェックできます。たとえば、
symlinkがあるシステムでは機能識別子gauche.sys.symlinkが
定義されます。したがって、以下のようにsys-symlinkが利用できるか
どうかによって、コードをスイッチするようなプログラムを書けます。
(cond-expand (gauche.sys.symlink ... code that uses sys-symlink ...) (else ... alternative code ...) )
Cのシステムプログラミングに詳しいなら、上のコードは以下のCのイディオム と同じだとみなせます。
#if defined(HAVE_SYMLINK) ... code that uses symlink ... #else ... alternative code ... #endif
このような機能識別子はたくさんあり、それぞれの識別子についてはこのマニュ アル中のその機能に依存した手続きの項目で説明しています。特に重要なもの を以下にリストアップしておきます。
gaucheこの機能識別子は常に定義されています。Gauche以外のSchemeの実装とも互換 性のあるコードを書くときに使えます。
gauche.os.windowsWindowsネイティブプラットフォームで定義されます。cygwinでは この機能識別子は定義されません (下記も参照)。
gauche.os.cygwinCygwin上で定義されます。
gauche.sys.pthreadsgauche.sys.wthreadsスレッドの具体的な実装を示すために定義されます。
詳細はgauche.threads - スレッドを参照してください。
gauche.net.ipv6GaucheがIPv6をサポートするようにコンパイルされている場合に定義されます。
cond-expandはマクロなので、cond-expand自身がトップレベル
にあれば、節の本体はトップレベルで展開されます。これはトップレベルの定
義をスイッチできるということです。
(cond-expand
(gauche.os.windows
(define (get-current-user)
... get current username ...))
(else
(define (get-current-user)
(sys-uid->user-name (sys-getuid)))))
あるいは条件によってモジュールを使いわけられます。
(cond-expand (gauche.os.windows (use "my-windows-compatibility-module")) (else))
トップレベルの束縛をチェックするような旧いテクニック
(module-binds?を使う, モジュールイントロスペクション参照)
は実行時に効果を持つので、コンパイル時に解釈されるuse
を切り替えるのはうまくいきません。
可能なかぎり、cond-expandを使うことを推奨します。
現時点では機能識別子集合はGaucheのコンパイル時に固定されます。つまり、 Cのプリプロセッサを使った条件分岐よりも柔軟性に劣ります。この機能を拡 張してあとから機能識別子を追加できるようにする計画ですが、この機能拡張 はコンパイルと実行が細切れに入れ替わる場合のセマンティクスを複雑にしてしまう可 能性があり、現在その影響を慎重にみきわめている最中です。
いくつか注意事項があります。
機能識別子は変数ではありません。cond-expandの
feature-requirement部の内部でのみ利用可能です(機能要求の定義全般
については機能条件式を見てください)。
SRFI-0の定義により、機能要求が満されず、かつelse節がない
場合にはcond-expandはエラーをあげます。常にelseを書いて
おくのがよいでしょう。 上の例のように、else節でなにもしないとき
でも、空のelse節を書くのがよいでしょう。