For Gauche 0.9.5


Next: , Previous: , Up: ライブラリモジュール - Gauche拡張モジュール   [Contents][Index]

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

Module: gauche.configure

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

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

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

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

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

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

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


Next: , Previous: , Up: ビルド用ファイルの生成   [Contents][Index]

9.7.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)

;; Argument declarations
(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 "")))

;; Initialization
(cf-init)

;; Tests & other parameter settings
(cf-path-prog 'GOSH "gosh")

;; Output
(cf-make-gpd)
(cf-echo (cf$ 'PACKAGE_VERSION) > "VERSION")
(cf-output "Makefile")

cf-* APIの呼び出しを、このようにトップレベルに書くかわりに、 関数としてまとめることもできます。コードのまとめかたは自由ですが、 実際にスクリプトが実行される際に、以下のステップを踏む必要があります。

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

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


Previous: , Up: ビルド用ファイルの生成   [Contents][Index]

9.7.2 Configure API

初期化

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

configureシステムを初期化します。これはconfigureスクリプト中で、 全ての機能テスト手続きに先立って必ず1回呼ばれなければなりません。

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

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

省略可能引数は以前のバージョンとの互換性のためのものです。package.scmが 無い場合、少なくともpackage-namepackage-versionを与える 必要があります。これらはconfigure変数の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で初期化されます。 パッケージ記述についての詳細はパッケージメタ情報を見てください。

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

コマンドライン引数

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

Make the configure script accept feature selection argument and package selection argument, respectively. The corresponding autoconf macros are AC_ARG_ENABLE and AC_ARG_WITH.

Those procedures must be executed before calling cf-init.

The feature and package arguments must be a symbol.

A feature selection argument is in a form of either --enable-feature=val, --enable-feature, or --disable-feature. The latter two are equivalent to --enable-feature=yes and --enable-feature=no, respectively. It is to select an optional feature provided with the package itself.

A package selection argument is in a form of either --with-package=val, --with-package and --without-package. The latter two are equivalent to --with-package=yes and --with-package=no, respectively. It is to select an external software package to be used with this package.

When cf-init finds these arguments, it adds entry of feature or package to the global tables, with the value val. Those global tables can be accessed with cf-feature-ref and cf-package-ref procedures below.

The help-string argument must be a string and is used as is to list the help of the option in part of usage message displayed by configure --help. You can use cf-help-string below to create a help string that fits nicely in the usage message.

If optional proc-if-given argument is given, it must be a procedure that accepts one argument, val. It is called when cf-init finds one of those arguments.

If optional proc-if-not-given argument is given, it must be a procedure that accepts no arguments. It is called when cf-init doesn’t find any of those arguments.

Function: cf-help-string item description

Return a string formatted suitable to show as an option’s help message. The result can be passed to help-string argument of cf-arg-enable and cf-arg-with. This corresponds to autoconf’s AS_HELP_STRING.

Call it as follows, and it’ll indent and fill the description nicely.

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

Lookup a symbol name from the global feature table and the global package table, respectively. These can be called after cf-init.

For example, if you’ve called cf-arg-enable with foofeature, and the user has invoked the configure script with --with-foofeature=full, then (cf-feature-ref 'foofeature) returns "full". If the user hasn’t given the command-line argument, #f is returned.

メッセージ

The cf-init procedure opens the default log drain that goes to config.log, and you can use log-format to write to it (See ユーザレベルのロギング, for the details of logging).

However, to have consistent message format conveniently, the following procedures are provided. They emits the message both to log files and the current output port (in slightly different formats so that the console messages align nicely visually.)

Function: cf-msg-checking fmt arg …

Writes out “checking XXX...” message. The fmt and arg … arguments are passed to format to produce the “XXX” part.

For the current output port, this does not emit the trailing newline, expecting cf-msg-result will be called subsequently.

Here’s an excerpt of the source that uses cf-msg-checking and cf-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"))))

This produces a console output like this:

checking whether the C compiler works... yes

while the log file records more info:

checking: whether the C compiler works
... whatever logging message from run-compiler-with-content ...
result: yes

This corresponds to autoconf’s AC_MSG_CHECKING.

Function: cf-msg-result fmt arg …

The fmt and arg … are passed to format, and the formatted message and newline is written out. For the log file, it records “result: XXX” where XXX is the formatted message. Supposed to be used with cf-msg-checking.

This corresponds to autoconf’s AC_MSG_RESULT.

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

Produces “Warning: XXX” and “Error: XXX” messages, respectively. The fmt and arg … are passed to format to generate XXX part. These corresponds to autoconf’s AC_MSG_WARN and AC_MSG_ERROR.

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

Convenience routine to replace shell’s echo command.

If the argument list ends with > file or >> file, where file is a string file name, then this works just like shell’s echo; that is, args except the last two are written to file, space separated, newline terminated. Using > supersedes file, while >> appends to it.

If the argument list doesn’t end with those redirection message, it writes out the argument to both the current output port and the log file, space separated, newline terminated. For the log file, the message is prefixed with “Message:”.

パラメータと定義

The configure script maintains two global tables, definition tables and substitution tables. Definition tables is used for C preprocessor definitions, and substitution tables are used for @PARAMETER@ substitutions.

Function: cf-define symbol :optional value

Registers C preprocessor definition of symbol with value. Value can be any Scheme objects, but it is emitted to a command line (in -DSYMBOL=VALUE form) or in config.h (in #define SYMBOL VALUE form) using display, so you want to avoid including funny characters. If value is omitted, 1 is assumed.

This corresponds to autoconf’s AC_DEFINE.

Function: cf-subst symbol value

Registers substitution parameter symbol with value. Value can be any Scheme objects; it’s display representation is used to substitute @SYMBOL@ in the template.

This corresponds to autoconf’s AC_SUBST, but we require the value (while autoconf can refer to the shell variable value as default).

Function: cf-have-subst? symbol

Returns true iff symbol has a substitution registered by cf-subst.

Function: cf-arg-var symbol

Lookup the environment variable symbol and if it is found, use its value as the substitution value. For example, if you call (cf-arg-var 'MYCFLAGS), then the user can provide the value of @MYCFLAGS@ as MYCFLAGS=-g ./configure.

This corresponds to autoconf’s AC_ARG_VAR, but we lack the ability of setting the help string. That’s because cf-arg-var must be run after cf-init, but the help message is constructed within cf-init.

Function: cf-ref symbol :optional default

This looks up the value of the substitution parameter symbol. If there’s no such substitution parameter registered, it returns default when it’s provided, otherwise throws an error.

Function: cf$ symbol

Looks up the value of the substitution parameter cf-ref, but it returns empty string if it’s unregistered. Useful to use within string interpolation, e.g. #"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

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 siently 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

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-check-header header :key includes

Check if a header file header exists and usable, by compiling a source program of the current language that includes the named header file. This is intended to be used as a predicate—returns #t if the header is usable, #f if not. This corresponds to autoconf’s AC_CHECK_HEADER.

If header requires other headers being included or preprocessor symbosl 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

Codify a common pattern of checking the availability of headers and sets C preprocessor definitions. This corresponds to autoconf’s AC_CHECK_HEADERS.

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

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.

コンパイラを走らせる

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
Function: cf-lang-program prologue body

Returns a string tree that consists a stand-alone program for the current language. Prologue and body must be a string tree. 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>\n" "printf(\"()\");\n"))

would produce something like this:

#include <stdio.h>

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

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

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
Function: cf-try-compile prologue body
Function: cf-try-compile-and-link prologue body

出力

Function: cf-output file …
Function: cf-show-variables :key formatter
Function: cf-make-gpd

Previous: , Up: ビルド用ファイルの生成   [Contents][Index]