For Development HEAD DRAFTSearch (procedure/syntax/module):

9.8 gauche.configure - ビルド用ファイルの生成

Module: gauche.configure

このモジュールはconfigureスクリプトを書くためのユーティリティライブラリです。 configureスクリプトはシステムの属性をチェックして、 ビルド用のファイル(通常はmakefile)をテンプレートから生成します。

主な目的は、Gauche拡張パッケージにおいて、autoconfが生成する configureシェルスクリプトを置き換えることです。

autoconfを使う利点は、生成されるスクリプトが最小限のシェル機能と基本的なunixコマンドにしか 依存しないため、ほとんど何も入れないunix上でも実行できることです。 けれども、Gauche拡張パッケージをビルドする時には、 既にGaucheはインストールされているわけですから、これを使わない手はありません。

configureスクリプトがGaucheで直接書ければ、配布前に configureスクリプトを生成するという余分な手間が省けます。 configureスクリプト自体をリポジトリにチェックインしておけますし、 誰でもソースツリーをチェックアウトしたら(autoconfを使わずに)すぐに configureを実行できます。

ただ、今のところgauche.configureはautoconfの機能の小さなサブセット しかカバーしないので、複雑な機能テストが必要ならautoconfに戻らなければ ならない場合もあります。必要に応じて機能テストを足して行く予定です。

gauche.configureのコアとなる機能は、テンプレート(例: Makefile.in) から、@VAR@のように書かれたパラメータを置換して ファイル(例: Makefile)を生成することです。 autoconf用に書いたMakefile.inはそのまま流用できるはずです。

autoconfのAC_*マクロに対応する機能は、プレフィクスをcf-に置き換えた 名前で提供されています。


9.8.1 configureスクリプトの構成とビルドファイル

configureスクリプトは、それを実行しているシステムの特性を調べて 置換パラメータの値を決定し、ビルドファイルのテンプレート中の置換パラメータを 値に書き換えてビルドファイルを生成します。

通常、テンプレートファイルにはサフィックス.inがつけられ、 対応する出力ファイルはそのサフィックスが除かれたものになります。 例えばMakefile.inMakefileを生成するテンプレートです。

テンプレートファイル中には@PARAMETER_NAME@という形式の 置換パラメータを含めることができます。以下は典型的なMakefileのテンプレートです。

GAUCHE_PACKAGE = "@GAUCHE_PACKAGE@"
SOEXT          = @SOEXT@
LOCAL_PATHS    = "@LOCAL_PATHS@"

foo.$(SOEXT): $(foo_SRCS)
        $(GAUCHE_PACKAGE) compile \
          --local=$(LOCAL_PATHS) --verbose foo $(foo_SRCS)

configureがこのテンプレートを処理する際に、@GAUCHE_PACKAGE@@SOEXT@@LOCAL_PATHS@はそれぞれ適切な値に 置換されます。autoconfを知っている読者には馴染み深い動作でしょう。

Gaucheのconfigureスクリプトはautoconfのconfigure.inと 似たような構造をとりますが、フルセットのSchemeの力を使うことができます。 次は最小のconfigureスクリプトです:

#!/usr/bin/env gosh
(use gauche.configure)
(cf-init-gauche-extension)
(cf-output-default)

このスクリプトはいくつかの共通タスクを行います。 cf-init-gauche-extensionの仕事は以下のとおりです。

cf-output-defaultは次の処理を行います。

一般的に、configureスクリプトは以下のようなパーツから構成されます:

  1. 追加の引数の宣言(省略可): --with-PACKAGE--enable-FEATUREで 処理すべきオプションを、それぞれcf-with-argcf-enable-argで 宣言します。
  2. 初期化。cf-initcf-init-gauche-extensionを呼ぶと、 グローバルなコンテキストが設定され、 configureに与えられた引数がパーズされます。また、 package.scmが存在していれば、そこからパッケージメタ情報が読み込まれます。
  3. テストと置換パラメータの設定 (省略可): システムの特性を調べ、 置換すべきパラメータやCプリプロセッサ定義の値を設定します。
  4. 出力の生成。cf-outputcf-output-defaultを呼び出し、 テンプレートファイルを処理します。

多くのcf-* APIは、autoconfのAC_*もしくはAS_*マクロに 対応しています。引数の宣言がcf-initより前になされなければならないのは、 1パスでcf-initがカスタム引数の説明を含んだヘルプメッセージを 生成する必要があるからです。


9.8.2 Configure API

初期化

Function: cf-init-gauche-extension

{gauche.configure} これはいくつかの定形のcf-*呼び出しをひとつにまとめた便利関数です。 configureスクリプト中で1回だけ呼び出される必要があります。

この関数はまずcf-arg-with関数で--with-localコマンドライン引数の 処理を登録し、次にcf-initを引数なしで呼んで初期化し、 さらに以下の置換パラメータをセットします:

GOSH

goshへのパス

GAUCHE_CONFIG

gauche-configへのパス

GAUCHE_PACKAGE

gauche-packageへのパス

GAUCHE_INSTALL

gauche-installへのパス

GAUCHE_CESCONV

gauche-cesconvへのパス

GAUCHE_PKGINCDIR

gauche-config --pkgincdirの結果

GAUCHE_PKGLIBDIR

gauche-config --pkglibdirの結果

GAUCHE_PKGARCHDIR

gauche-config --pkgarchdirの結果

--with-localコマンドライン引数はコロン区切りのパス名をパラメータとして 取ります。その値は置換パラメータLOCAL_PATHSにセットされます。 デフォルトのMakefile.inテンプレートを使っていれば、その値は gauche-package--local引数に渡され、 C拡張コードがコンパイル・リンクされる際のヘッダファイル、ライブラリオブジェクトが それぞれ指定されたパス以下のincludelibサブディレクトリから探されます。 例えば拡張モジュールがfooライブラリに依存していて、あなたがそれを /opt/foo以下にインストールしていたとしましょう(つまり、 ヘッダファイルが/opt/foo/includeに、ライブラリオブジェクトが /opt/foo/libにあります)。その場合、 拡張モジュールをconfigureする際に--with-local=/opt/fooを渡せばうまくいきます。

デフォルトで行われるこれら余分な動作が邪魔な場合は、 この関数を使わずに個々のcf-*関数を呼び出すこともできます。 下のcf-initも参照してください。

Function: cf-init :optional package-name package-version maintainer-email homepage-url

{gauche.configure} configureシステムを初期化します。autoconfのAC_INITに対応します。 これはconfigureスクリプト中で、 全ての機能テスト手続きに先立って必ず1回呼ばれなければなりません。 (cf-init-gauche-extensionを呼んだ場合、その中からcf-initが 呼ばれています。)

まずこの手続きは、configureスクリプトと同じディレクトリにpackage.scmという ファイルがあるかどうか調べ、あればGaucheパッケージ記述をそこから読み込みます。 パッケージ記述には、パッケージ名、バージョン、依存関係などがかかれています。 詳しくはgauche.package - パッケージメタ情報を参照してください。

次にこの手続きはコマンドライン引数をパーズし、configureの環境を設定し、 (もしpackage.scmが依存関係を定義していれば)必要なパッケージが 既にあるかどうかもチェックします。

省略可能引数は以前のバージョンとの互換性のためのものです。package.scmが 無い場合、少なくともpackage-namepackage-versionを与える 必要があります。これらは置換パラメータのPACKAGE_NAMEPACKAGE_VERSION を置換するのに使われます。他の引数maintainer-emailhomepage-urlPACKAGE_BUGREPORTPACKAGE_URLに 使われます。これらの引数はautoconfのAC_INITマクロと互換です。

推奨される呼び出し方法は、package.scmを用意し、cf-initには 引数を渡さないことです。そうすれば、パッケージのメタ情報を一ヶ所(package.scm)で 管理できます。package.scmが読まれた場合、PACKAGE_BUGREPORTは パッケージ記述のmaintainersの最初のエントリで、また PACKAGE_URLはパッケージ記述のhomepageで初期化されます。 パッケージ記述についての詳細はgauche.package - パッケージメタ情報を見てください。

もしpackage.scmが存在し、かつcf-initに引数が与えられた場合、 それぞれ対応する情報は一致していなければなりません。一致していなかった場合、 cf-initはエラーを投げます。これは、package.scmへの移行の途中で、 どちらかの情報をアップデートし忘れたケースを捕まえるためです。

この手続きはまた、prefixbindirあるいはsrcdirといった 標準の置換パラメータをたくさん設定します。 どの置換パラメータが設定されるか見たければ、cf-initの後に cf-show-substsを呼んでみてください。

コマンドライン引数

Function: cf-arg-enable feature help-string :optional proc-if-given proc-if-not-given
Function: cf-arg-with package help-string :optional proc-if-given proc-if-not-given

{gauche.configure} それぞれ、configureスクリプトが、機能選択引数およびパッケージ選択引数を認識するようにします。 autoconfでの対応するマクロはAC_ARG_ENABLEAC_ARG_WITHです。

これらの手続きはcf-initもしくはcf-init-gauhce-extensionの前に 呼ばれなければなりません。

featurepackage引数はシンボルでなければなりません。

機能選択引数は、--enable-feature=val--enable-feature、もしくは--disable-featureという 引数です。後のふたつはそれぞれ --enable-feature=yesおよび --enable-feature=noと同じです。 このconfigure引数は、パッケージ自体が提供しているオプショナルな機能を選択するのに使います。

パッケージ選択引数は、--with-package=val--with-package、もしくは--without--packageという 引数です。後のふたつはそれぞれ --with-package=yesおよび --with-package=noと同じです。 このconfigure引数は、このパッケージが使う外部のパッケージを選択するのに使います。

cf-initがコマンドライン引数処理中にこれらの形の引数を見つけた場合、 featureまたはpackageと、与えられたvalをグローバルなテーブルに 保存します。このグローバルテーブルは下のcf-feature-refおよび cf-package-refでアクセスできます。

help-stringは文字列で、configure --helpで表示される ヘルプメッセージに使われます。 下のcf-help-stringを使ってヘルプ文字列を整形することができます。

省略可能引数proc-if-givenは、与えられたら引数をひとつ取る手続きでなければなりません。 cf-initが対応するコマンドライン引数を見つけた時に、コマンドラインで与えられた valを引数としてこの手続きが呼ばれます。

省略可能引数proc-if-not-givenは、与えられたら引数を取らない手続きでなければなりません。 cf-initが対応するコマンドライン引数を見つけられなかった時に、 この手続きが呼ばれます。

下は、--with-local=PATH:PATH:…という形式の コマンドライン引数を受け取る例です (このcf-arg-with呼び出しはcf-init-gauche-extensionに含まれています)。 ヘルプ文字列を生成するのにcf-help-stringを使っているのに注目してください。 また、コマンドライン引数で与えられたオプションの値は、 3番めの引数の手続きへと渡されます。

(cf-arg-with 'local
             (cf-help-string
              "--with-local=PATH:PATH..."
              "For each PATH, add PATH/include to the include search
  paths and PATH/lib to the library search paths.  Useful if you have some
  libraries installed in non-standard places. ")
             (^[with-local]
               (unless (member with-local '("yes" "no" ""))
                 (cf-subst 'LOCAL_PATHS with-local)))
             (^[] (cf-subst 'LOCAL_PATHS "")))
Function: cf-help-string item description

{gauche.configure} コマンドライン引数のヘルプメッセージにふさわしい形式にフォーマットした文字列を 返します。戻り値をcf-arg-enablecf-arg-withhelp-string引数に渡すことで、 configure --helpが統一的な出力を生成できます。 autoconfのAS_HELP_STRINGに相当します。

(cf-help-string "--option=ARG" "Give ARG as the value of option")
Function: cf-feature-ref name
Function: cf-package-ref name

{gauche.configure} グローバルな機能テーブルおよびパッケージテーブルにnameで登録された値を 返します。これらはcf-initの後で呼べます。

例えば、cf-arg-enablefoofeatureという機能に関するコマンドライン 引数を登録したとしましょう。ユーザがconfigureスクリプトに --with-foofeature=fullオプションを与えて起動した場合、 (cf-feature-ref 'foofeature)"full"を返します。 コマンドライン引数が与えられなかった場合は#fが返ります。

機能テーブルやパッケージテーブルに値を足したり変更したい場合は一般化set!を使って (set! (cf-feature-ref 'NAME) VALUE)と書くことができます。

メッセージ

cf-init手続きはconfig.logにロギングするデフォルトログドレインを オープンするので、log-formatを使ってconfig.logにログを 残すことができます (ロギングの詳細についてはgauche.logger - ユーザレベルのロギング参照)。

しかし、一貫した形式でメッセージを扱うために、以下の手続きが提供されています。 これらの手続きはログファイルと現在の出力ポートに(見やすいようにそれぞれ若干異なる 形式で)メッセージを出力します。

Function: cf-msg-checking fmt arg …

{gauche.configure} “checking XXX...” というメッセージを出力します。fmtarg … 引数はformatに渡されて、“XXX”の部分を生成します (フォーマット出力参照)。

現在の出力ポートに向けては、改行文字は出力されません。 この後でcf-msg-resultが呼ばれることを期待しているからです。

以下は、cf-msg-checkingcf-msg-resultを使っているソースからの 抜粋です。

(define (compiler-can-produce-executable?)
  (cf-msg-checking "whether the ~a compiler works" (~ (cf-lang)'name))
  (rlet1 result ($ run-compiler-with-content
                   (cf-lang-link-m (cf-lang))
                   (cf-lang-null-program-m (cf-lang)))
    (cf-msg-result (if result "yes" "no"))))

この例は、次のような出力を生成します:

checking whether the C compiler works... yes

また、ログファイルに対しては次の情報が記録されます:

checking: whether the C compiler works
... run-compiler-with-contentのログ出力 ...
result: yes

これはautoconfのAC_MSG_CHECKINGに対応します。

Function: cf-msg-result fmt arg …

{gauche.configure} fmtarg …がformatに渡され、フォーマット結果が出力されます。 通常、メッセージは単なる “yes” / “no” か、見つかった(ライブラリやヘッダの)名前です。 ログファイルに対しては、XXXをフォーマットされたメッセージとして、 “result: XXX”という文字列が記録されます。 cf-msg-checkingと一緒に使うことを想定しています。 上のcf-msg-checkingの例を見てください。 これはautoconfのAC_MSG_RESULTに対応します。

Function: cf-msg-notice fmt arg …

{gauche.configure} フォーマットされたメッセージをコンソールとログファイルの両方に出力します。 最後に改行文字が追加されます。これはautoconfのAC_MSG_NOTICEに対応します。

Function: cf-msg-warn fmt arg …
Function: cf-msg-error fmt arg …

{gauche.configure} それぞれ、“Warning: XXX” および “Error: XXX” というメッセージを出力します。 fmtarg …はformatに渡されて、 XXXの部分の文字列を生成します (フォーマット出力参照)。

さらに、cf-msg-errorは終了コード1でプロセスを終了します。

これらは、autoconfのAC_MSG_WARNAC_MSG_ERRORに相当します。 註: AC_MSG_ERRORは終了コードが指定できますが、 cf-msg-errorは今の所1に固定です。

Function: cf-echo arg … [> file][>> file]

{gauche.configure} シェルのechoコマンドを置き換える便利手続きです。

引数リストが> fileもしくは>> fileで終わっている場合 (fileはファイル名の文字列)、これはシェルのechoのように動作します。 すなわち、その部分を除くarg …が空白文字を間に挟んで fileに書き出されます。また最後に改行文字も書き出されます。 >を使った場合はfileは上書きされ、>>の場合は追記されます。

引数リストが上記リダイレクト指示で終わっていない場合は、 現在の出力ポートとログファイル両方に、arg …を空白文字を間に挟んで出力します。 また最後に改行文字も書き出されます。ログファイルに向けては、メッセージの前に “Message:”が出力されます。

パラメータと定義

configureスクリプトは、定義テーブルと置換パラメータテーブルという 二つのグローバルなテーブルを持っています。 定義テーブルはCプリプロセッサの定義に使われ、置換パラメータテーブルは @PARAMETER@の置換に使われます。 (置換パラメータをSchemeのパラメータオブジェクト(パラメータ参照)と 混同しないように!)。

Function: cf-define symbol :optional value

{gauche.configure} symbolvalueとするCプリプロセッサ定義を登録します。 valueには任意のSchemeオブジェクトを渡せますが、 そのdisplay表記がそのままコンパイラのコマンドライン (-DSYMBOL=VALUEという形式)あるいはconfig.h内の定義 (#define SYMBOL VALUEという形式)に使われるので、 妙な文字を入れない方が無難でしょう。valueが省略された場合は 1が使われます。

註: 文字列を値とする定義、例えば #define FOO "foo" を生成するには、 (cf-define 'FOO "\"foo\"") とする必要があります。

これはautoconfのAC_DEFINEに相当します。

Function: cf-defined? symbol

{gauche.configure} symbolcf-defineされていれば#tを、 そうでなければ#fを返します。

Function: cf-subst symbol :optional value

{gauche.configure} 置換パラメータsymbolを値valueで定義します。 出力ファイルを生成する時に、テンプレートの@symbol@valueに置換されます。

valueは通常文字列ですが、任意のSchemeオブジェクトで構いません。 displayでの印字表現が使われます。

valueが省略されるか#fの場合はちょっと違った動作になります。 symbolがまだ置換パラメータとして登録されていない場合は、 空文字列を値として置換パラメータを登録します。既に登録されていた場合は値をそのまま残します。

これはautoconfのAC_SUBSTに相当します。ただ、autoconfeでは値を明示しなくても 同名のシェル変数の値が使われますが、Gaucheでは値を陽に与えなければなりません。

Function: cf-subst-prepend symbol value :optional delim default
Function: cf-subst-append symbol value :optional delim default

{gauche.configure} 置換パラメータsymbolの値の前もしくは後に、 delimを挟んでvalueを付け足します。 symbolがまだ定義されていなかった場合な、 defaultが与えられ空文字列でなければあたかもそれが既に設定されていた値であるかのように 動作し、そうでなければvalueが最初の値となります(この場合、delimは使われません)。 delimが省略された場合は空白1文字の文字列が使われます。

置換パラメータにはよくコマンドライン引数をつけ足してゆくので (例:コンパイラの-I include-dir)、これらの手続きが便利に使えるでしょう。 フラグ

Special Form: with-cf-subst (binding …) body …

{gauche.configure} 一時的に置換パラメータを新たな値に置き換えてbody …を実行します。 コンパイルチェックを違うパラメータで実行してみたい時に便利です。

bindingは以下のいずれかの形式です。

(var value)

一時的に置換パラメータvarの値をvalueで置き換えます。

(var + value)

一時的に置換パラメータvarの値の後に空白を挟んでvalueを追加します。 追加には上記のcf-subst-appendが使われます。

(var value +)

一時的に置換パラメータvarの値の前に空白を挟んでvalueを前置します。 追加には上記のcf-subst-prependが使われます。

(with-cf-subst ((LIBS "-L<path> -l<lib>"))
  (cf-try-compile-and-link ...))

autoconfではこのパターンは、現在の置換パラメータを保存し、 新たなパラメータに変更してチェックを走らせた後で置換パラメータを元に戻しますが、 とても面倒です。

Function: cf-have-subst? symbol

{gauche.configure} symbolcf-substで置換パラメータとして登録されていれば#tを、 そうでなければ#fを返します。

Function: cf-arg-var symbol

{gauche.configure} 名前symbolを持つ環境変数を探し、見つかればそれを置換パラメータsymbolの 値とします。環境変数が見つからない場合、まだsymbolが置換パラメータとして登録されて いなければ、空文字列を値として登録します。そうでなければ何もしません。

例えば、(cf-arg-var 'MYCFLAGS)を呼び出しておくと、 ユーザは@MYCFLAGS@の置換をMYCFLAGS=-g ./configureのようにして 与えることができます。

これはautoconfのAC_ARG_VARに相当します。 ただし、autoconfと違ってヘルプ文字列を与えることはできません。 cf-arg-varcf-initより後に呼ばれねばならず、 しかしヘルプ文字列はcf-init内で構築される必要があるからです。

Function: cf-ref symbol :optional default

{gauche.configure} 置換パラメータsymbolの値を返します。該当する置換パラメータが登録されていない場合、 defaultが与えられていればそれを返し、そうでなければエラーを投げます。

Function: cf$ symbol

{gauche.configure} cf-refと同じように置換パラメータsymbolの値を返しますが、 該当する置換パラメータが登録されていない場合は空文字列を返します。 文字列補間の中で#"gosh ~(cf$'GOSHFLAGS)"のように使えるので便利です。

定義済みテスト

Function: cf-check-prog sym prog-or-progs :key value default paths filter
Function: cf-path-prog sym prog-or-progs :key value default paths filter

{gauche.configure} Check if a named executable program exists in search paths, and if it exists, sets the substitution parameter sym to the name of the found program. The name to search is specified by prog-or-progs, which is either a string or a list of strings.

The difference of cf-check-prog and cf-path-prog is that cf-check-prog uses the basename of the found program, while cf-path-prog uses its full path. These corresponds to autoconf’s AC_CHECK_PROG, AC_CHECK_PROGS, AC_PATH_PROG and AC_PATH_PROGS.

For example, the following feature test searches either one of cc, gcc, tcc or pcc in PATH and sets the substitution parameter MY_CC to the name of the found one.

(cf-check-prog 'MY_CC '("cc" "gcc" "tcc" "pcc"))

If multiple program names is given, the search is done in the following order: First, we search for the first item (cc, in the above example) for each of paths, then the second, etc. For example, if we have /usr/local/bin:/usr/bin:/bin in PATH and we have /usr/local/bin/tcc and /usr/bin/gcc, the above feature test sets MY_CC to "gcc". If you use cf-path-prog instead, MY_CC gets "/usr/bin/gcc".

If no program is found, sym is set to the keyword argument default if it is given, otherwise sym is left unset.

If the value keyword argument is given, its value is used instead of the found program name to be set to sym.

The list of search paths is taken from PATH environment variable. You can override the list by the paths keyword argument, which must be a list of directory names. It may contain nonexistent directory names, which are silently skipped.

The filter keyword argument, if given, must be a predicate that takes full pathname of the executable program. It is called when the procedure finds matching executable; the filter procedure may reject it by returning #f, in which case the procedure keeps searching.

Note: If the substitution parameter sym is already set at the time these procedure is called, these procedures do nothing. Combined with cf-arg-var, it allows the configure script caller to override the feature test. For example, suppose you have the following in the configure script:

(cf-arg-var 'GREP)
(cf-path-prog 'GREP '("egrep" "fgrep" "grep"))

A user can override the test by calling configure like this:

$ ./configure GREP=mygrep
Function: cf-prog-cxx

{gauche.configure} A convenience feature test to find C++ compiler. This searches popular names of C++ compilers from the search paths, sets the substitution parameter CXX to the compiler’s name, then tries to compile a small program with it to see it can generate an executable.

This corresponds to autoconf’s AC_PROG_CXX.

CXX is cf-arg-var’ed in this procedure. If a user provide the value when he calls configure, the searching is skipped, but the check of generating an executable is still performed.

If the substitution parameter CXXFLAGS is set, its value is used to check if the compiler can generate an executable. CXXFLAGS is cf-arg-var’ed in this procedure.

This procedure also emulates autoconf’s AC_PROG_CXX behavior— if CXX is not set, but CCC is set, then we set CXX by the value of CCC and skip searching.

Function: cf-header-available? header :key includes
Function: cf-check-header header :key includes

{gauche.configure} Check if a header file header exists and usable, by compiling a source program of the current language that includes the named header file. Return #t if the header is usable, #f if not.

Both procedure does the same thing. The name cf-check-header corresponds to autoconf’s AC_CHECK_HEADER.

If header requires other headers being included or preprocessor symbols defined before it, you can pass a list of strings to be emitted before the check in the includes keyword arguments. The given strings are just concatenated and used as a C program fragment. The default value is provided by cf-includes-default.

The following example sets C preprocessor symbol HAVE_CRYPT_H to 1 if crypt.h is available. (Note: For this kind of common task, you can use cf-check-headers below. The advantage of using cf-check-header is that you can write other actions in Scheme depending on the result.)

(when (cf-check-header "crypt.h")
  (cf-define "HAVE_CRYPT_H" 1))
Function: cf-check-headers headers :key includes if-found if-not-found

{gauche.configure} Codify a common pattern of checking the availability of headers and sets C preprocessor definitions. This corresponds to autoconf’s AC_CHECK_HEADERS. This procedure is invoked for the side effects, and returns an undefined vlaue.

See this example:

(cf-check-headers '("unistd.h" "stdint.h" "inttypes.h" "rpc/types.h"))

This checks availability of each of listed headers, and sets C preprocessor definition HAVE_UNISTD_H, HAVE_STDINT_H, HAVE_INTTYPES_H and HAVE_RPC_TYPES_H to 1 if the corresponding header file is available.

A list of strings given to includes are emitted to the C source file before the inclusion of the testing header. You can give necessary headers and/or C preprocessor definitions there; if omitted, cf-includes-default provides the default list of such headers.

The keyword argument if-found and if-not-found are procedures to be called when a header is found to be available or to be unavailable, respectively. The procedure receives the name of the header.

The name of the C preprocessor definition is derived from the header name by upcasing it and replacing non-alphanumeric characters for _. Note that this substitution is not injective: Both gdbm/ndbm.h and gdbm-ndbm.h yield GDBM_NDBM_H. If you need to distinguish such files you have to use cf-check-header.

Function: cf-includes-default

{gauche.configure} Returns a list of strings that are included in the check program by default. It is actually a combination of C preprocessor #ifdefs and #includes, and would probably be better to be called cf-prologue-default or something, but the corresponding autoconf macro is AC_INCLUDES_DEFAULT so we stick to this name.

Usually you don’t need to call this explicitly. Not giving the includes argument to cf-check-header and cf-check-headers will make cf-includes-default called implicitly.

Function: cf-type-available? type :key includes
Function: cf-check-type type :key includes

{gauche.configure} Test if type is defined as a type name. Return #t if type is defined, #f otherwise.

Two procedures are the same. The name cf-check-type corresponds to AC_CHECK_TYPE.

A list of strings given to includes are emitted to the C source file before the inclusion of the testing header. You can give necessary headers and/or C preprocessor definitions there; if omitted, cf-includes-default provides the default list of such headers.

Function: cf-check-types types :key includes if-found if-not-found

{gauche.configure} For each type in the list types, call cf-check-type to see it is defined as a type. If it is, defines HAVE_type, and calls if-found with the type as an argument if provide. If the type is not defined and if-not-found is provided, calls it with the type as an argument.

The argument includes is passed to cf-check-type.

This corresponds to autoconf’s AC_CHECK_TYPES.

Returns an undefiend value. This procedure is for side effects.

;; May define HAVE_PTRDIFF_T and/or HAVE_UNSIGNED_LONG_LONG_INT
;; depending on its availability:
(cf-check-types '("ptrdiff_t" "unsigned long long int"))

;; Example of using includes to add an extra header.
(cf-check-types '("float_t")
                :includes `(,@(cf-includes-default)
                            "#include <math.h>\n"))
Function: cf-decl-available? symbol :key includes
Function: cf-check-decl symbol :key includes

{gauche.configure} Test if symbol is declared as a cpp macro, a variable, a constant, or a function. Return #t if type is defined, #f otherwise.

Two procedures are the same. The name cf-check-decl corresponds to autoconf’s AC_CHECK_DECL.

A list of strings given to includes are emitted to the C source file before the inclusion of the testing header. You can give necessary headers and/or C preprocessor definitions there; if omitted, cf-includes-default provides the default list of such headers.

Function: cf-check-decls symbols :key includes if-found if-not-found

{gauche.configure} For each symbol in symbols, call cf-check-decl to see if it is declared. If it is, define HAVE_DECL_symbol to 1, and calls if-found with the symbol if provided. If it is not declared, define HAVE_DECL_symbol to 0, and calls if-not-found with the symbol if provided. This corresponds to autoconf’s AC_CHECK_DECLS.

The argument includes is passed to cf-check-decl.

This procedure returns an undefined value. This procedure is for side effects.

Note that, unlike other cf-check-* routines which leave HAVE_* macro undefined when the item isn’t found, this one always defines the macro and differentiate the result with its value. This behavior is the same as AC_CHECK_DECLS.

Function: cf-member-available? aggregate.member :key includes
Function: cf-check-member aggregate.member :key includes

{gauche.configure} The aggregate.member argument is a string of aggregate type name and its member concatenated by a dot, e.g. "struct password.pw_gecos". It can also be a submember, e.g. "struct foo.bar.baz". The aggregate part can be any type name (typedef-ed name is ok).

This test checks if member is a member of aggregate, and returns #t if so, or returns #f if not.

Two procedures are the same. The name cf-check-member corresponds to autoconf’s AC_CHECK_MEMBER.

A list of strings given to includes are emitted to the C source file before the inclusion of the testing header. You can give necessary headers and/or C preprocessor definitions there; if omitted, cf-includes-default provides the default list of such headers.

Function: cf-check-members members :key includes if-found if-not-found

{gauche.configure} For each aggregate.member in members, call cf-check-member. If the test passes, defines HAVE_aggregate_member, and calls if-found with aggregate.member if provided. If the test fails, calls if-not-found with aggregate.member if provided.

This corresponds to autoconf’s AC_CHECK_MEMBERS.

The include argument is passed to cf-check-member.

;; Defines HAVE_STRUCT_ST_RDEV and/or HAVE_STRUCT_ST_BLKSIZE
;; depending on their availability:
(cf-check-members '("struct stat.st_rdev"
                    "struct stat.st_blksize"))

This procedure is for side effects, and returns an undefined value.

Function: cf-func-available? func
Function: cf-check-func func

{gauche.configure} See if a function func is available. This emits C code to call func (with dummy declaration) and tries to compile and link, using current value of substitution parameter LIBS. The value of cf-includes-default is at the top of the emitted C code.

They return #t if func is available, #f otherwise.

Two procedures are the same. The name cf-check-func corresponds to autoconf’s AC_CHECK_FUNC.

Function: cf-check-funcs funcs :key if-found if-not-found

{gauche.configure} For each function name func in funcs, call cf-check-func to determine availability. If it is available, define HAVE_func, and calls if-found with func if provided. If it is not available, calls if-not-found with func if provided.

This corresponds to autoconf’s AC_CHECK_FUNCS.

This procedure is for side effects, and returns an undefined value.

Function: cf-lib-available? lib fn :key other-libs if-found if-not-found
Function: cf-check-lib lib fn :key other-libs if-found if-not-found

{gauche.configure} See if a library lib can be linked and a function fn in it is callable. Return #t it is, #t if not.

Two procedures are the same. The name cf-check-lib corresponds to autoconf’s AC_CHECK_LIB.

Give the name you pass after -l option to lib; for example, if you want to check availability of libm, you can say as follows:

(cf-check-lib "m" "sin")

This generates a C source that calls fn and try to compile and link it to generate executable. If linking lib requires additional libraries, it should be listed in other-libs:

(cf-check-lib "Xt" "XtDisplay" :other-libs '("-lX11" "-lSM" "-lICE"))

If compilation and linking succeeds, if-found is called at the tail position with the library name ("m" and "Xt" in the above examples, respectively) as the argument. The default behavior is to add -llib in the left of substitution parameter LIBS, and set HAVE_LIBlib definition, then returns #t.

If compilation or linking fails, if-not-found is called at the tail position with the library name. The default behavior is to return #f.

The default behavior of if-found and if-not-found allows cf-check-lib to be used as predicate as well. If you merery want to take an action depending on whether the library is found or not, you can write like this:

(unless (cf-check-lib "foo" "foo_fn)
  ... do something if libfoo isn't available ...)

Use if-found and/or if-not-found only if you want to override the default behaviors.

Function: cf-search-libs fn libs :key other-libs if-found if-not-found

{gauche.configure} Like cf-check-lib, but can be used if you’re not sure which library contains desired function. This corresponds to autoconf’s AC_SEARCH_LIBS. Note that this takes function name first, while cf-check-lib takes function name second—blame autoconf for this inconsistency.

First it tests if fn is available without any library in libs (that is, with the ones already in LIBS and specified in other-libs). If not, it tests each library in libs in turn.

If fn is found, if-found is called at the tail position, with the name of the library as an argument (if fn is available without any library, the argument is #f). If omitted, and a library is required, then the library is added to the substitution parameter LIBS. The default procedure returns #t.

If fn isn’t found in any of the libraries, if-not-found is called at the tail position with #f as the argument. The default procedure does nothing and just returns #f.

The default behavior of if-found and if-not-found allows cf-search-libs to be used as predicate as well. If you give alternative procedures, keep in mind that their return value will be returned to cf-search-libs.

Function: cf-path-x

{gauche.configure} This corresponds to autoconf’s AC_PATH_X. It checks if X11 is available, and returns three values.

The first value is a boolean value indicates if X11 is available. The second and third values are strings for the directory name to find X11 headers and libraries, respectively. The second and third value can be empty strings if the compiler doesn’t need additional flags to find X11 stuff.

This does not set other substituion parameters. You typically want to use cf-path-xtra below instead.

(In autoconf, AC_PATH_X sets shell variables to tell the results. In Scheme, it is more natural to use return values.)

Function: cf-path-xtra

{gauche.configure} Check X11 availability with cf-path-x above, and sets up the following substitution parameters:

X_CFLAGS

Additional CFLAGS needed to build with X11.

X_PRE_LIBS

Additional library link flags (-llib) that need to come before -lX11 flag.

X_LIBS

Additional library search flags (-Ldir) to link with X11. (Note: The name is for the compatibility with autoconf. It should really be named as X_LDFLAGS.)

X_EXTRA_LIBS

Additional library search flags (-Ldir) to link with X11. Those libraries should come after -lX11 flag.

This procedure corresponds to autoconf’s AC_PATH_XTRA.

Note that -lX11 is not included in those parameters; they must be specified explicitly.

If X11 is not available, those parameters get empty strings.

コンパイラを走らせる

The gauche.configure module provides a generic mechanism to construct a small test program, compile it, and run it. Currently we only support C and C++; we’ll add support for other languages as needed.

Parameter: cf-lang

{gauche.configure} Returns a current language, which is an opaque object. Currently C and C++ are supported; see cf-lang-C and cf-lang-C++ below.

The current language is used by compiler tests.

Function: cf-lang-C
Function: cf-lang-C++

{gauche.configure} Returns an opaque object representing C or C++, respectively. You can use them to parameterize cf-lang to run compiler tests.

(parameterize ([cf-lang (cf-lang-C++)])
  ... run compiler tests ...)
Function: cf-lang-program prologue body

{gauche.configure} Returns a string tree that consists a stand-alone program for the current language. Prologue and body must be a string or a list of strings. If it is a list, strings are concatenated with newlines. Prologue comes at the beginning of the source, and body is included in the part of the program that’s executed. If the current language is C, the code fragment:

(use text.tree)
(write-tree (cf-lang-program '("#include <stdio.h>"
                               "#include <stdlib.h>")
                             '("printf(\"()\");")))

would produce something like this:

#include <stdio.h>
#include <stdlib.h>

int main(){
printf("()");

; return 0;
}
Function: cf-lang-io-program

{gauche.configure} This is a convenience routine. It returns a string tree of a program in the current language, that creates a file named conftest.out, then exits with zero status on success, or nonzero status on failure.

Function: cf-lang-call prologue func-name

{gauche.configure} Returns a string tree of a program in the current language, that calls func-name as a function with no arguments.

Function: cf-try-compile prologue body

{gauche.configure} The arguments must be a string or a list of strings. If it is a list, it is taken as a list of lines, concatenated with newlines.

This test generates a program with the given content, using cf-lang-program, then try to compile it. On success, #t is returned. On failure, #f is returned. The generated program, command line, and the result is logged.

{gauche.configure} The arguments must be a string or a list of strings. If it is a list, it is taken as a list of lines, concatenated with newlines.

This test generates a program with the given content, using cf-lang-program, then try to compile and link it. On success, #t is returned. On failure, #f is returned. The generated program, command line, and the result is logged.

出力

Function: cf-output-default file …

{gauche.configure} A convenience routine to produce typical output. It does the following:

  • Generate gpd (Gauche package description) file using cf-make-gpd.
  • Generate VERSION file that contains the value of PACKAGE_VERSION substitution parameter.
  • Search Makefile.in’s under the source directory (the value of substitution parameter srcdir), and process them to produce Makefile’s. If file … are given, file.in are also processed as well to produce file.

    See cf-output below for the details.

  • If config header is registered by cf-config-headers, process them as well.
Function: cf-output file …

{gauche.configure} Generates file’s from the input templates. This corresponds to autoconf’s AC_OUTPUT.

For each file, a file named file.in is read as a template. Within the file, @PARAMETER@ is substituted with the value of (cf$ 'PARAMETER). If the named parameter isn’t registered, a warning is issued and the parameter is left unsubstituted.

If config headers are not registered via cf-config-headers, a substitution parameter DEFS is replaced with all the definitions in the form of -D.... For example, if you have checked header files foo/bar.h and foo/baz.h, DEFS gets the value -DHAVE_FOO_BAR_H -DHAVE_FOO_BAZ_H.

If config header is registered by cf-config-headers, they are processed as well. In such case, the substitution parameter DEFS gets the value -DHAVE_CONFIG_H.

Function: cf-config-headers header-or-headers

{gauche.configure} Sets up config header files to be processed. Usually a config header file is named config.h, and contains definitions determined by feature tests.

The header-or-headers argument may be a string header-spec or a list of string header-specs, where each header spec is a header file name (e.g. "config.h") or a header name and a input file name concatenated with a colon (e.g. "config.h:config.h.templ"). If it’s just a header name, input file name is assumed to be the header file name with ".in" appended.

The input template of config header file contains a bunch of #undef directives, such as the following:

/* Gauche ABI version string */
#undef GAUCHE_ABI_VERSION

/* Define if Gauche handles multi-byte character as EUC-JP */
#undef GAUCHE_CHAR_ENCODING_EUC_JP

/* Define if Gauche handles multi-byte character as Shift JIS */
#undef GAUCHE_CHAR_ENCODING_SJIS

/* Define if Gauche handles multi-byte character as UTF-8 */
#undef GAUCHE_CHAR_ENCODING_UTF_8

Once processed, the generated header file has either #undef line is replaced with #define, or commented out, depending on the definitions determined by feature tests.

/* Gauche ABI version string */
#define GAUCHE_ABI_VERSION "0.97"

/* Define if Gauche handles multi-byte character as EUC-JP */
/* #undef GAUCHE_CHAR_ENCODING_EUC_JP */

/* Define if Gauche handles multi-byte character as Shift JIS */
/* #undef GAUCHE_CHAR_ENCODING_SJIS */

/* Define if Gauche handles multi-byte character as UTF-8 */
#define GAUCHE_CHAR_ENCODING_UTF_8 /**/

Note that the lines other than #undef are copied as they are.

The substitution parameter DEFS behaves differently whether config header is specified or not. If no config header is registered, The value of DEFS is a C command-line arguments for definitions, e.g. -DGAUCHE_ABI_VERSION=0.97 -DGAUCHE_CHAR_ENCODING_UTF8. If config header files are registered, the value of DEFS becomes simply -DHAVE_CONFIG_H.

Function: cf-show-substs :key formatter

{gauche.configure} Print all substitution parameters; this is for debugging.

For each substitution parameter name and value, formatter is called with them; the default is (^[k v] (format #t "~16s ~s" k v)).

Function: cf-make-gpd

{gauche.configure} Generate gpd (Gauche package description) file, PACKAGE_NAME.gpd, where PACKAGE_NAME is the package’s name either taken form package.scm or the argument to cf-init. See gauche.package - パッケージメタ情報, for the package description file format.



For Development HEAD DRAFTSearch (procedure/syntax/module):
DRAFT