Autoconfは,二つのレイヤーのトップに書かれています.それは,純粋なM4プ ログラムで便利なマクロを提供しているM4sugarと,シェルスクリプト の生成に専念するマクロを提供するM4shです.
このバージョンのAutoconfでは,二つのレイヤーはまだ実験段階で,そのイン ターフェースは将来変更される可能性があります.実際問題,文章化さ れていないものは使用しないでください.
既存のマクロの最も一般的な問題は,不適当な引用符です.このセクションで は,Autoconfのユーザは飛ばすことができますが,マクロを書く人は読む 必要があり,最初にAutoconfで採択された引用符を利用する方法を正 当化し,最後に経験則を述べます.前者を理解すると後者で役立ちます.
適切な引用符の重要性を完全に理解するため,最初にAutoconfでの特殊な文字 が何かを知る必要があります.`#'はマクロ展開が実行されない内部コメ ントの導入で,`,'は引数のセパレータ,`['と`]'はそれらの 引用符,そして最後は,(M4が対の一致を試みる)`('と`)'です.
マクロ呼び出しの微妙な状況を理解するために,最初に明らかな失敗を紹介し なければならないでしょう.以下で"明確にされ"ていて,実生活でも見つか るでしょうが,それらは通常ごまかしです.
ハッシュと改行まで実行することで導入されるコメントは,トップレベルへの 不明瞭なトークンです.アクティブな文字はそうではなくなり,マクロの展開 もありません.
# define([def], ine) =># define([def], ine)
マクロの展開があるごとに,引用符も展開されます.すなわち,第一レベルの 引用符は削除されます.
int tab[10]; =>int tab10; [int tab[10];] =>int tab[10];
これを覚えていなければ,読者は絶望しながらもマクロのarray
を使用
してみるでしょう.
define([array], [int tab[10];]) array =>int tab10; [array] =>array
期待する結果を正しく出力するにはどうすれば良いでしょうか (2)?
さて,アクティブな文字と以下の単に最初の引数を返す小さなマクロを用いた マクロで,対話的に進めていきましょう.
define([car], [$1])
上記の二組の引用符はdefine
の引数の一部ではありません.そうでは
なく,define
の引数の検索が試みられるときに,それらはトップレベ
ルで理解されます.そのため,それは以下のように書くことと等価です.
define(car, $1)
しかし,`configure.ac'が不必要な引用符を避けることは受け入れても かまいませんが,より強固で,完全な形式を提案する必要もあるAutoconfマク ロにとっては悪い慣習です.
トップレベルでは,二つの可能性があります.引用符で囲む,または囲まない での二つです.
car(foo, bar, baz) =>foo [car(foo, bar, baz)] =>car(foo, bar, baz)
特殊文字に注目してみましょう.
car(#) error-->EOF in argument list
閉じカッコはコメント内に隠れてしまいます.引用符を推測することで,トッ プレベルでは以下のように理解します.
car([#)]
適切な引用符は,もちろんこの問題を修正します.
car([#]) =>#
読者は,以下の例の方が理解しやすいかもしれません.
car(foo, bar) =>foo car([foo, bar]) =>foo, bar car((foo, bar)) =>(foo, bar) car([(foo], [bar)]) =>(foo car([], []) => car([[]], [[]]) =>[]
これを覚えていると,マクロがマクロを呼び出し,マクロがマクロを呼び出し ...となっているような状況も調査することが可能です.
これ以降の例では,以下のマクロを使用しています.
define([car], [$1]) define([active], [ACT, IVE]) define([array], [int tab[10]])
追加の埋め込まれたマクロ呼び出しは,それぞれ興味深い引用符について,そ の他の可能性を導き出します.
car(active) =>ACT car([active]) =>ACT, IVE car([[active]]) =>active
最初の状況では,トップレベルではcar
の引数を探し,`active'
が見つかります.M4はマクロを適用する前のその引数と等価なので,
`active'は展開され,結果として以下のようになります.
car(ACT, IVE) =>ACT
二番目の状況では,トップレベルはcar
の最初で唯一の引数として
`active'を与えるので,結果として以下のようになります.
active =>ACT, IVE
すなわち,マクロが呼び出された後で,引数が評価されます.三番目
の状況では,car
は`[active]'を受けとり,結果として以下のよ
うになります.
[active] =>active
上記で見たものと同じですね.
より現実的な例を適用して,上記の例に与えてみましょう.
car(int tab[10];) =>int tab10; car([int tab[10];]) =>int tab10; car([[int tab[10];]]) =>int tab[10];
う〜ん? 最初の状況は簡単に理解できますが,なぜ二番目が間違っていて,
三番目は正しいのでしょうか?それを理解するために,M4がマクロを展開した
後,結果として生じるテキストがすぐにマクロを展開に従って引用符が取り除
かれることを知っておく必要があります.これは,引用符の削除が二回行なわ
れることを意味します -- 最初に引数としてcar
マクロに渡されると
き,二回目はcar
マクロが最初の引数を展開するときです.
Autoconfマクロcar
の作者として,ユーザがcar
の引数を二重の
引用符にする必要があることは間違っていると考えるようにし,マクロを
修正してください.引用符で囲まれているcar
に対して,それ
をqar
と呼ぶことにしましょう.
define([qar], [[$1]])
そして,qar
が適切に修正されていることを調査してみます.
qar([int tab[10];]) =>int tab[10];
あぁ!そうした方が良さそうですね.
しかし,自分が行なったことに注意してください.現在その引数はリテラル文 字列ですが,引数を展開した結果をユーザが使用したい場合,引用符で 囲まれていないマクロを使用する必要があります.
qar(active) =>ACT
car
を用いて行なっていたことを再生成したい状況を考えます.
car([active]) =>ACT, IVE
まだ駄目ですね.cpp
マクロの組を生成するマクロを使用したい状況を
考えてみましょう.
define([my_includes], [#include <stdio.h>]) car([my_includes]) =>#include <stdio.h> qar(my_includes) error-->EOF in argument list
このマクロqar
は,引数を二重に引用符で囲むので,ユーザはマクロの
呼び出しを引用符で囲まないままにしておくよう強制されるので,それは危険
です.カンマとその他のアクティブなシンボルは,マクロに渡される前にM4で
解釈され,それはユーザが期待している手法ではないことが多いものです.ま
た,qar
は,他のマクロとは異なる動作をするので,Autoconfでは避け
るべき例外になります.
changequote
の弊害
特に夜も遅くなると,適切な引用符をバイパスする誘惑が大きくなることも多
いものです.そして,経験豊富なAutoconfのハッカーの多くは,最終的に暗黒
の力に支配され,最終兵器を持ち出します.それはchangequote
です.
M4組み込みのchangequote
は,言語の構文を必要に応じて調整すること
を可能にするプリミティブの組に属しています.例えば,M4では引用符として
デフォルトで``'と`''を使用しますが,シェルプログラムの文脈
(そして,ほとんどの実際のプログラミング言語)では,それは利用可能なもの
の中での最悪の選択です.シェルコードでの(`'this''と``that`'
のような)文字列とバッククオートされた式と,通常のプログラミング言語で
使用される(`'0''のような)リテラル文字のため,多くの対にならない
``'と`''が存在します.そのような文脈での厳密なM4の引用符が
(変更)不可能な場合は,悪夢になります.そのような文脈でM4を役立たせるた
め,それを設計した人は別の引用符の組の選択を可能にする
changequote
を装備しました.M4sugar,M4sh,Autoconf,そして
Autotestでは,すべてのものが`['と`]'の使用を選択しています.
それらが滅多に使用されない文字という理由だけでなく,対にならない
ことも滅多に無い文字という理由もあります.
構文形式がコメントだということを指定するため(M4がHTMLページを生成する
ために使用されるとき,`changecom(<!--, -->)'が一般的だと分かるで
しょう)のchangecom
と,それ以外の構文の詳細を変更するための
changeword
とchangesyntax
(n番目の引数を示す,デフォルトで
`$'となっている文字や,引数の周りを囲むカッコなど)のような,それ
以外のマジックプリミティブもあります.
これらのプリミティブは,特定の分野に対してM4がより役に立つようにするた
め,本当に意味があるものです.それらはコマンドラインオプションのように
考えるべきです.それらは,@option{--quotes},@option{--comments},
@option{--words},そして--syntax
のようなものです.それにもかか
わらず,M4ライブラリ自身が含まれる(追加のオプションが必要無い)ように,
M4の組み込みとして実装されています.
そこに問題があります@enddots{}
問題は,M4スクリプトの途中で,その初期化を目的としてそれを使用するとき に発生します.これは,あまり注意していない場合,甚大な影響があるはずで す.実行の途中で言語を変更しているようなものです.構文の変更と それからの復帰が十分でないことが多いものです.その間でマクロの呼び出し を行なった場合,現在の構文はおそらくマクロを実装していないので,これら のマクロは失われることになります.
Autoconfマクロを書いているとき,標準的なAutoconfの引用符の規則で表現す ることが難しい,特殊な文字を生成する必要が生じるかもしれません.例えば, `['以外の全ての文字に一致する正規表現`[^[]'を出力する必要が あるかもしれません.この表現は,対称ではないカッコを含んでいるので,M4 マクロの中に簡単に書き込むことはできません.
以下の四文字表記(quadrigraph)の一つを使用することで,この問題を 解決することが可能です.
四文字表記は,@command{m4}が実行された後,変換処理の終りの段階で置換さ れるので,M4の引用符の邪魔になりません.例えば,文字列`[^@<:@]' は,その引用符で囲まれている状態に依存せず,出力では`[^[]'として 現れます.
空の四文字表記を使用することも可能です.
AC_FOO
をコメントとして書きたいかもしれませんが,
@command{autom4te}は展開されていない`AC_*'を確実に受けとります.
そのときは,`AC@&t@_FOO'と書いてください.
`@&t@'の名前はPaul Eggertの提案です.
私は,`@&t@'の語呂合わせに称賛を与えるべきでしょう.`&'は 私自身の発明ですが,`t'はSteve Bourne(Bourneシェルで有名です)によっ て書かれたALGOL68Cコンパイラのソースコードが由来となっていて,そ こでは空の文字列を示すために`mt'を使用しています.Cでは,それは以 下のようなものになるでしょう.
char const mt[] = "";しかし,ソースコードは当然Algol 68で書かれています.
彼が`mt'を得た場所を,私は知りません.それは独自の発明かもしれま せんし,当時のケンブリッジ大学のコンピュータ研究所で,一般的な語呂合わ せだったのかもしれません.
終りに引用符の経験則を述べます.
カッコの組ごとに引用符の組
特にマクロ定義では,多過ぎる引用符もだめ,少な過ぎる引用符も駄目です. カッコを使用する必要があるマクロ(通常Cのプログラム文や正規表現の中)で は,適切に引数を引用符で囲んでください!
以下のような断片を用いたAutoconfプログラムを読むことはよくあります.
AC_TRY_LINK( changequote(<<, >>)dnl <<#include <time.h> #ifndef tzname /* For SGI. */ extern char *tzname[]; /* RS6000 and others reject char **tzname. */ #endif>>, changequote([, ])dnl [atoi (*tzname);], ac_cv_var_tzname=yes, ac_cv_var_tzname=no)
それは,AC_TRY_LINK
はすでに二重に引用符で囲まれているの
で, 全く無駄になり,実際は以下のようにするだけで十分です.
AC_TRY_LINK( [#include <time.h> #ifndef tzname /* For SGI. */ extern char *tzname[]; /* RS6000 and others reject char **tzname. */ #endif], [atoi (*tzname);], [ac_cv_var_tzname=yes], [ac_cv_var_tzname=no])
M4に親しんでいる読者は,M4が引数をまとめる(collect)ときに `changequote(<<, >>)'と`<<' `>>'の両方を飲み込むので, これら二つの例が厳密に等価であることに注意してください.これらの引用符 は引数の一部ではありません!
単純にしてみると,上記の例は以下のようになります.
changequote(<<, >>)dnl <<[]>> changequote([, ])dnl
その代わりに単純に以下のようにします.
[[]]
引数を(規則で)二重に引用符で囲まないマクロを用いると,二重の引用は(危 険な)文字列になります.
AC_LINK_IFELSE([AC_LANG_PROGRAM( [[#include <time.h> #ifndef tzname /* For SGI. */ extern char *tzname[]; /* RS6000 and others reject char **tzname. */ #endif]], [atoi (*tzname);])], [ac_cv_var_tzname=yes], [ac_cv_var_tzname=no])
引用符が十分でない状況で望みがなくなった場合どうすればいいかということ については,See section 四文字表記.
新たに書かれたマクロを用いて@command{configure}スクリプトを作成すると き,マクロにより多くの引用符を加える必要があるかどうかの調査は,気を付 けて吟味してください.一つ以上の単語がM4の出力に現れない場合,より多く の引用符が必要になります.迷ったときは引用符です.
しかし,引用符のレイヤーが多過ぎる可能性もあります.この場合は,結果と して得られる@command{configure}スクリプトは,展開されていないマクロが 含まれているでしょう.@command{autoconf}プログラムは,@samp{grep AC_ configure}を行なうことでこの問題を調査します.
Autoconf自身のものに加え,M4sugar,M4sh,そしてAutotestを含めた Autoconfスイートは,M4にかなり依存しています.使い方が異なるこれらはす べて,@command{m4}の上のレイヤーに集約したいという共通の要求を具体化し ました.それは@command{autom4te}(3)です.
@command{autom4te}は,基本的に@command{m4}自身に置き換わるものとして考 慮されるべきです.
コマンドライン引数は,M4のものをモデルにしています.
autom4te options files
ここでのfilesは,直接@command{m4}に渡すものです.正規の展開に加 え,それは四文字表記(see section 四文字表記)と,出力の現在の行の `__oline__'の置換を処理します.それは,filesに対して拡張さ れた構文もサポートしています.
もちろん,それはAutoconfの一般的のオプションのサブセットをサポートして います.
@command{m4}の拡張として,それらは以下のオプションが含まれます.
AC_DIAGNOSE
のSee section メッセージの報告. 以下の特殊な値が含まれます.
WARNINGS
は尊重されます.
@command{autom4te -W category}は,実際に悪いことを実行したかのよ
うに動作します.
autom4te --warnings=syntax,$WARNINGS,category@command{autom4te}のデフォルトと
WARNINGS
を利用不可能にしたいけ
れども,(例えば)時代遅れの構成物に関する警告は利用可能にしたい場合,
@option{-W none,obsolete}を使用するべきでしょう.
@command{autom4te}はエラーのバックトレースを表示しますが,警告は表示し
ません.警告も表示したい場合,@option{-W error}を渡してください.例え
ば以下のような`configure.ac'を考えます.
AC_DEFUN([INNER], [AC_RUN_IFELSE([AC_LANG_PROGRAM([exit (0)])])]) AC_DEFUN([OUTER], [INNER]) AC_INIT OUTER以下のようになるでしょう.
$ autom4te -l autoconf -Wcross configure.ac:8: warning: AC_RUN_IFELSE called without default \ to allow cross compiling $ autom4te -l autoconf -Wcross,error -f configure.ac:8: error: AC_RUN_IFELSE called without default \ to allow cross compiling acgeneral.m4:3044: AC_RUN_IFELSE is expanded from... configure.ac:2: INNER is expanded from... configure.ac:5: OUTER is expanded from... configure.ac:8: the top level
file.m4f
は
file.m4
で置換されます.これは,ファイルが固められていると
きだけに実行されるマクロ,通常はm4_define
の追跡で役に立ちます.
例えば以下のように実行します.
autom4te --melt 1.m4 2.m4f 3.m4 4.m4f input.m4これは以下を実行したのと等価です.
m4 1.m4 2.m4 3.m4 4.m4 input.m4一方,以下を実行した場合を考えます.
autom4te 1.m4 2.m4f 3.m4 4.m4f input.m4これは以下と等価です.
m4 --reload-state=4.m4f input.m4
autom4te 1.m4 2.m4 3.m4 --freeze --output=3.m4fこれは以下に対応します.
m4 1.m4 2.m4 3.m4 --freeze-state=3.m4f
それ以外の@command{m4}上の追加機能として,@command{autom4te}がその結果 をキャッシュするというものがあります.@acronym{GNU} M4は,標準出力を生 成すると同時にトレースすることが可能です.トレースは@acronym{GNU}ビル ドシステムで重点的に使用されています.@command{autoheader}は, `config.h.in'をビルドするために,@command{autoreconf}は,使用され ている@acronym{GNU}ビルドシステムの構成要素を決定するために, @command{automake}は`configure.ac'をパースするため等として使用し ています.@command{m4}の長い実行結果を保存するために,通常の展開を実行 している間,トレースはキャッシュされます(4).このキャッシュ(実際に は複数ある) は,ディレクトリ`autom4te.cache'に保存されます.いつ でも削除して大丈夫です(特に,理由があれば@command{autom4te}はそ れが捨てられてしまったと考えます).
トレースは@acronym{GNU}ビルドシステムに重きをおいて実装されているので, @command{autom4te}は,M4と比較して高度なトレース機能を提供していて, キャッシュを利用する手助けとなります.
最後に,@command{autom4te}は@dfn{Autom4teライブラリ(Autom4te libraries)}の概念を導入します.それらは,強力ですが非常にシンプルな機 能から成り立っています.コマンドライン引数の組み合わせの組です.
M4sugar
M4sh
Autotest
Autoconf
例として,Autoconfがデフォルトの場所`/usr/local'にインストールさ れている場合,`autom4te -l m4sugar foo.m4'を実行することは, `autom4te --prepend-include /usr/local/share/autoconf m4sugar/m4sugar.m4f --warning syntax foo.m4'を実行することと厳密に等価 となります.再帰的な展開も適用します.`autom4te --language m4sh foo.m4'を実行することは,`autom4te --language M4sugar m4sugar/m4sh.m4f foo.m4'と同じで,すなわち,`autom4te --prepend-include /usr/local/share/autoconf m4sugar/m4sugar.m4f m4sugar/m4sh.m4f --mode 777 foo.m4'と同じになります.言語の定義は, `autom4te.cfg'に保存されます.
`~/.autom4te.cfg' (すなわち,ユーザのホームディレクトリにあるとき) と,`./.autom4te.cfg' (すなわち,@command{autom4te}が実行されるディ レクトリにあるとき)で,@command{autom4te}をカスタマイズすることが可能 です.順番として,最初に`autom4te.cfg'を読み込み,そして `~/.autom4te.cfg',そして`./.autom4te.cfg',そして最後にコマ ンドライン引数を読み込みます.
これらのテキストファイルでは,コメントは#
ではじまり,空の行は無
視されます.カスタマイズは,言語ごとを基本に実行され,
`begin-language: "language"'と`end-language:
"language"'の組みで囲まれます.
言語のカスタマイズとは,現在の言語の定義にオプションを追加すること (see section @command{autom4te}の呼び出し)を意味します.オプションと一般的な引数は, `args: arguments'で始まります.argumentsを引用符で囲 むことによって伝統的なシェルの構文を使用してもかまいません.
例として,Autoconfのキャッシュ(`autom4te.cache')を大域的に利用不 可能にするため,以下の行を`~/.autom4te.cfg'に含めます.
@verbatim ## ------------------ ## ## User Preferences. ## ## ------------------ ##
begin-language: "Autoconf" args: --no-cache end-language: "Autoconf"
M4自身は非常に小さいけれど十分な,汎用マクロの組を提供しています. M4sugarは,追加の一般的なマクロを導入しています.その名前は,Lars J. Aas によってつくり出されました:"Readability And Greater Understanding Stands 4 M4sugar".
いくつか例外がありますが,全てのM4ネイティブなマクロは,`m4_'疑似
名前空間に移動されていて,例えば,M4sugarではdefine
を
m4_define
に名前を変えるなどのようになっています.
M4マクロには再定義されているものもあり,ネイティブな同義語とわずかに互 換性がなくなっています.
m4_dnl
は定義され
ていません.
m4_undefine
を参照してください.
m4exit
に対応します.
ifelse
に対応します.
m4_ifdef([macro], [m4_undefine([macro])])
それで,組み込みのものの動作に復旧します.
patsubst
に対応します.m4_patsubst
の名前は,
epatsubst
で拡張した正規表現の構文を提供する,@acronym{GNU} M4の
最上位のM4shの将来のバージョンに対して残されています.
m4_undefine
を参照してください.
regexp
に対応しています.m4_regexp
の名前は,
eregexp
で拡張した正規表現の構文を提供する,@acronym{GNU} M4の最
上位のM4shの将来のバージョンに対して残されています.
m4wrap
に対応しています.
二つの連続して呼び出されるm4_wrap
が,そのままトークンとして渡さ
れるという予期しない結果となる危険が無いように,textを`[]'
で終えることが推奨されます.
m4_define([foo], [Foo]) m4_define([bar], [Bar]) m4_define([foobar], [FOOBAR]) m4_wrap([bar]) m4_wrap([foo]) =>FOOBAR
以下のマクロは,引用符のレベルを追加したり削除したりすることで,評価の 順序全体を制御するものです.それらは,ハードコアなM4プログラマに対して 意味があります.
以下の例は,(i)これらの例を使用していない,(ii)m4_quote
を使用し
ている,(iii)m4_dquote
を使用している,といったそれぞれの間の差
を強調することを目的としています.
$ cat example.m4 # Overquote, so that quotes are visible. m4_define([show], [$[]1 = [$1], $[]@ = [$@]]) m4_divert(0)dnl show(a, b) show(m4_quote(a, b)) show(m4_dquote(a, b)) $ autom4te -l m4sugar example.m4 $1 = a, $@ = [a],[b] $1 = a,b, $@ = [a,b] $1 = [a],[b], $@ = [[a],[b]]
M4sugar提供の目的は,怪しげはパターン,つまり出力に現れるべきではない トークンを記述しているパターンを定義するためです.例えば,Autoconf `configure'スクリプトに`AC_DEFINE'や`dnl'のようなトーク ンが含められている場合,おそらく何か問題が発生するでしょう(通常は,余 分な引用符のためにマクロが評価されていないためです).
M4sugarは,`^m4_'と`^dnl$'に一致する全てのトークンを禁止しま す.
もちろん,これらの一般的な規則の例外に遭遇する可能性もあり,例えば, `$m4_flags'を参照する必要があるかもしれません.
m4_pattern_forbid
パターンに一致しているものも含まれます.
M4shは,"mash"と発音し,移植性の高いBourneシェルスクリプトを生成する ことが狙いです.この名前はLars J. Aasが発明し,Webster's Revised Unabridged Dictionary (1913)にメモがあります(5)}.
Mash \Mash\, n. [Akin to G. meisch, maisch, meische, maische, mash, wash, and prob. to AS. miscian to mix. See "Mix".]
- 混合成分の塊を,こう解や圧搾でパルプ状に軟らかくして絞った@enddots{}
- 動物に与える粉餌やぬかと水を混ぜたもの.
- 混乱.トラブル. [Obs.] --Beau. & Fl.
今しばらくは,広範囲の使用に十分なほど熟していません.
M4shは,実験してみると残念ながら移植性が無い,一般的なシェルの構成に対 する移植性の高い代替物を提供しています.
Go to the first, previous, next, last section, table of contents.