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.windows
Windowsネイティブプラットフォームで定義されます。cygwinでは この機能識別子は定義されません (下記も参照)。
gauche.os.cygwin
Cygwin上で定義されます。
gauche.sys.pthreads
gauche.sys.wthreads
スレッドの具体的な実装を示すために定義されます。
詳細はgauche.threads
- スレッドを参照してください。
gauche.net.ipv6
Gaucheが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
節を書くのがよいでしょう。