[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
この章では,メーリングリストによく上がる質問をカバーします.
26.1 CVSと生成されるファイル | CVS and generated files | |
26.2 missing とAM_MAINTAINER_MODE | missing and AM_MAINTAINER_MODE | |
26.3 なぜAutomakeはワイルドカードをサポートしないのですか? | Why doesn't Automake support wildcards? | |
26.4 distclean後にビルドディレクトリに残っているファイル | Files left in build directory after distclean | |
26.5 なぜオブジェクトファイルの名前を変更することがあるのですか? | Why are object files sometimes renamed? | |
26.6 多くの出力を生成するツールを処理する | Writing rules for tools with many output files |
AutoconfとAutomakeを用いて作成したパッケージは,`configure'や `Makefile.in'といった生成されるファイルとともに配布されます.これ らのファイルは開発者のホストで生成され,それらをビルドするためにエンド ユーザが管理用のツールをインストールする必要が無いように配布されます. Lexスキャナー,Yaccパーサ,またInfoドキュメントのような,それ以外に生 成されるファイルは,同じ理由で通常配布されます.
例えば,`configure.ac'が変更されたときは`configure'をリビル
ドするためにautoconf
を実行します.`configure'が対応する
`configure.ac'より古くないように,開発者が確実に行なえます.
パッケージで配布されている,生成されたファイルは最新で,tar
でタイムスタンプを保存しているので,これらのリビルドのルールはユーザが
パッケージを展開しビルドするときも開始されません.
CVSキーワードを使用していない限り(この状況ではコミット時にファイルを更
新する必要があります),cvs commit
とcvs import -d
の処理中
にCVSが保持しているタイムスタンプは保持されます.
cvs checkout
を使用してファイルをチェックアウトしたとき,そのタ
イムスタンプは,チェックアウトしたリビジョンで設定されたタイムスタンプ
になります.
しかし,cvs update
したとき,ファイルの日付が更新されますが,
オリジナルのタイムスタンプはこのリビジョンになります.これは,
make
でソースファイルが更新されたことに確実に気付くことを意味
します.
このタイムスタンプの変更は,ソースと生成されたファイルの両方をCVSに保
持しているときは面倒です.CVSはアルファベット順にファイルを処理するの
で,cvs update
で両方のファイルを更新した後は,チェックイン時
に`configure.ac'より`configure'のほうが新しい場合でも,
`configure'より`configure.ac'が古いものとして表されます.
make
を呼び出すと,間違って`configure'のリビルドが開始され
ます.
基本的に二種類の管理者がいます.生成されるファイルを含め,すべての配布 されるファイルをCVSの元に保持している人,そして,生成されたファイルを CVSの外部に保持している人です.
CVSリポジトリはすべての配布されるファイルを含んでいるので,配布される ものが何かを正確に知っていて,前のバージョン全体をチェックアウトするこ とも可能です.
管理者は,生成されるファイルを展開する方法を知ることが可能です(例えば, Automakeを更新したとき,`Makefile.in'で生じたことを知り,大丈夫で あることを確認することが可能です).
チェックアウトしたプロジェクトをビルドするために,ユーザはautotoolが不 要で,リリースされたtarballと同様に動作します.
ユーザが,新しいものを取得するためにcvs checkout
する代わりに,
コピーを更新するためにcvs update
を使用する場合,タイムスタン
プは不正確になります.autoconf
やautomake
のような管
理者用のツールを,実行を開始したり試みたりするリビルドルールもあります.
実際,そのようなツールの呼び出しは,後で議論するmissing
スク
リプトで呼び出しにすべてラップされています(see section missing
とAM_MAINTAINER_MODE
).
missing
は,これらのツールがインストールされていないとき,ビ
ルドが続けられるように,タイムスタンプを修正します.
配布されている開発物では,開発者はバージョンが異なる管理ツールをインス トールしていることもよくあります.この状況では,失われたタイムスタンプ によるリビルドの開始が,生成されるファイルを間違って変更します.この問 題の解決方法はいくつかあります.
リビルドされるファイルがCVSのファイルと同じになるように,すべての開発 者が同じバージョンを使用する.(作業しているプロジェクトが異なるバージョ ンを使用しているとき,こうすることは難しくなります.)
または,チェックアウト後にタイムスタンプを修正するスクリプトを使用する (GCCの人々は,そのようなスクリプトを所有しています).
または,これらのリビルドルールすべてをデフォルトで利用不可能にするよう
に,`configure.ac'でAM_MAINTAINER_MODE
を使用します.これは,
missing
とAM_MAINTAINER_MODE
で更に議論していきます.
我々は間違ったリビルドに注目していますが,反対のことも生じます.CVSの タイムスタンプの処理で,古いと思われるファイルが最新のものになってしま うこともあるはずです.
例えば,開発者が編集された`Makefile.am'とリビルドされた `Makefile.in'を所有していて,両方のファイルを調査する直前に `Makefile.am'の変更を決定したと仮定します(変更に対応する `Makefile.in'をリビルドする前です).
この最後の`Makefile.am'の変更で,`Makefile.in'のコピーは古い
ものになっています.CVSはファイルをアルファベット順に処理するので,他
の開発者がツリー上でcvs update
するとき,`Makefile.in'が
`Makefile.am'より新しくなってしまいます.この開発者は,
`Makefile.in'が古いことが分からないでしょう.
CVSとmake
を平和に動作させる一つの方法は,生成されるファイルを
CVSに保存しないことで,すなわち,Makefile
のターゲット(派
生ファイルとも呼ばれます)をCVSの制御下におかないことです.
この方法では,開発者は生成されるファイルの変更で悩むことはありません. 全員が異なるバージョンを所有している場合は問題になります(もちろん互換 性があると仮定してもです).結局,タイムスタンプは失われ,ソースファイ ルへの変更は,これまでに議論してきた `Makefile.am'/`Makefile.in'の例のように失われてしまうはずで す.
欠点は,配布されるものの正確なコピーがCVSリポジトリに無いことと,チェッ クアウトしたものをビルド可能にする前に,様々な開発ツール(バージョンが 指定されるかもしれません)をユーザがインストールする必要があるというこ とです.しかし,結局は,CVSの仕事はバージョン管理であり,配布ではあり ません.
開発者が異なるバージョンのツールの使用を可能にすると,配布された開発物 のバグを隠すことにもなります.事実,開発者は,実際のリリースで生成され るファイルの代わりに,(テストであっても)自分が生成したファイルを使用し ます.tarballを準備している開発者は,使用しているツールのバージョンが 間違った出力を生成するものを使用している可能性があり(例えば,移植性の ないCファイル),他の開発者が,独自のバージョンのこのツールを使用してい ない場合,注意されることになるでしょう.
(タイムスタンプの問題が無いので)ここでは議論しませんが,それ以外に分類
されるファイルとして,パッケージとともに配布されるけれども,どこでも管
理されていないファイルがあります.例えば,gettextize
と
autopoint
(Gettext由来)や,libtoolize
(Libtool由来)
のようなツールは,パッケージにファイルをインストールしたり更新したりし
ます.
これらのファイルは,CVSに保持しようが保持しまいが,開発者のツール間の バージョンの違いについて,似たようなことが生じます.Gettextのマニュア ルにはこれに関するセクションがあります.CVS Issues: (gettext)CVS Issues section `Integrating with CVS' in GNU gettext toolsを参照して下さい.
missing
とAM_MAINTAINER_MODE
missing
missing
スクリプトは,いくつかの管理用ツールのラッパーで,要
求される管理用ツールを持っていないユーザのために設計されています.通常,
管理用ツールとは,autoconf
,automake
,
bison
等です.これらのツールで生成されるファイルは,パッケー
ジのその他のファイルとともに配布されるので,ユーザがビルドしたり,それ
らがconfigureで調査されている間は,これらのツールは要求されません.
しかし,理由があってリビルドのルールが開始され,足りないツールが呼び出
される場合,missing
はユーザに警告します.ツールが無いとき,
警告はされますが,ビルドの継続を可能にする方向で,missing
は
タイムスタンプを修正を試みます.例えば,autoconf
がインストー
ルされていない場合,missing
は`configure'を
touch
します.配布されるすべてのファイルがCVSに保持されている
場合,missing
のこの機能で,ユーザは管理用ツールが無く
ても,cvs update
で暗黙に指定されたタイムスタンプを回避して,
CVSからのパッケージをビルドすることが可能になります.
要求されるツールがインストールされている場合,missing
はそれ
を実行し,異常終了した後は継続しようとしません.これは開発時には正しい
もので,開発者は異常終了を修正したいものです.しかし,管理用ツールの違
うバージョンを持っているユーザは,リビルドルールが間違って開始されると
き,ビルドが終了しエラーになるかもしれません.ビルドの継続による異常終
了は,AM_MAINTAINER_MODE
で主張している論点の一つです.
AM_MAINTAINER_MODE
AM_MAINTAINER_MODE
は,"リビルドのルール"の呼び出しをデフォルト
で利用不可能にします.`configure.ac'にAM_MAINTAINER_MODE
が
あって,./configure && make
を実行する場合,make
は
`configure',`Makefile.in',LexやYaccの出力などのリビルドを*
決して*試みません.すなわち,一般的に配布されるが,通常ユーザが更新す
る必要が無いファイルに対するビルドルールを利用不可能にします.
./configure --enable-maintainer-mode
を実行する場合,これらのリ
ビルドルールが利用されるようになります.
ユーザ(や自分自身が)が失われたタイムスタンプ(see section CVSと生成されるファイル)でうんざりし
たくないからとか,単純に,リビルドルールを使わないようにして管理用ツー
ルを明示的に実行したいから,といった理由でAM_MAINTAINER_MODE
を
使用します.
AM_MAINTAINER_MODE
では,条件的なカスタムビルドのルールも利用不
可能にすることが可能になります.ユーザが利用不可能なおそれのある外部ツー
ルのルールを利用不可能にするため,この機能を使用する管理者もいます.
数年前,François PinardはAM_MAINTAINER_MODE
にいくつかの引数
を付けるよう指示しました.それらのほとんどは不安定になり得ます.依存性
を削除することで,非依存のビルドにすることができます.ソースファイルを
変更することで,生成されるファイルに影響がなくなり,このことで,注意さ
れないときでも非常に混乱するはずです.彼は,安定は管理者に限定すべきで
はなく(--enable-maintainer-mode
で提案されたもの),反対だと付け
加えました.ユーザが`Makefile.am'を編集すると,`Makefile.in'
を更新する,または警告を出力すべきですが(これがAutomakeで
missing
を使用する理由です),最終的に望むことは,何も起こらず,
ユーザは注意もされないことです(これは,AM_MAINTAINER_MODE
でリビ
ルドのルールを利用不可能にすることです).
AM_MAINTAINER_MODE
マクロを開発したJim Meyeringは,François
との議論に動揺し,パッケージからAM_MAINTAINER_MODE
を取り除きま
した.
すべてのファイルをCVSに保持しているプロジェクトで作業する手助けとなり,
違うバージョンのツールを所有している場合はmissing
が十分では
ないので,今でも,AM_MAINTAINER_MODE
を使用し続けている人はたく
さんいます.
開発者は怠けものです.ファイルの追加,削除,または名前の変更のたびに, `Makefile.am'の更新を忘れないようにする必要がないよう, `Makefile.am'でワイルドカードを使用したいときもよくあります.
これにはいくつかの欠点があります.
CVS(やそれに似たもの)を使用している管理者は,cvs add
やcvs
rm
を実行する必要があることを,とにかく覚えておく必要があります.とい
うわけで,`Makefile.am'も反射的にすぐ行なうようになります.
逆に,アプリケーションが完全ではない場合,`Makefile.am'にファイル
を追加する必要があるので,それをcvs add
することを覚えておく手助
けになります.
ワイルドカードを使用することで,間違ってファイルを配布しやすくなります. 例えば,開発者が(いわゆるテストケースで)調査するためのコードで,それは 配布物の一部にすべきではありません.
ワイルドカードを使用すると,間違ってファイルを削除しやすくなります.例 えば,ある開発者が新しいファイルを作成し,それをたくさんの場所で使用し ているが,これをコミットするのを忘れているとします.他の開発者は,不完 全なプロジェクトをチェックアウトしても,ファイルが足りなくても,問題無 く`make dist'を実行することが可能です.
ファイルをリストアップすると,配布するものを正確に制御できます.
配布されるべきファイルがツリーに無い場合,make dist
で文句を言わ
れます.さらに,リストアップしている以上のファイルを配布することもあり
ません.
おしまいに,ファイルを`Makefile.am'に追加し忘れることは滅多に無く, それは,追加していない場合,コンパイルもインストールもされず,テストす らできないでしょう.
それらすべてを却下するほとワイルドカードに十分な価値があるという反対意 見があるかもしれませんが,まだ哲学的な欠点もあります.Automakeにワイル ドカードを伝えるためのパッチを書き始める前に,主な技術的な問題を見てい きましょう.それは移植性です.
$(wildcard ...)
はGNU make
で動作しますが,他の
make
の実装では移植性がありません.
Automakeで$(wildcard ...)
をサポートする唯一の方法は,
automake
の実行時に$(wildcard ...)
を展開することで
す.結果として得られる`Makefile.in'には,$(wildcard ...)
が
使用されておらず,すべてのファイルをリストアップしているので移植性があ
ります.しかしそれは,ファイルを追加,削除,または名前の変更をするたび
に,開発者がautomake
を実行する必要があるということを意味します.
`Makefile.am'を編集するより,実際は若干勝っています.確かに,
emacs Makefile.am; make
と入力するよりautomake; make
と入
力する方が簡単で速いでしょう.しかし,この構文のサポートを追加するのに
十分なパッチを書くことを邪魔する人はいません.`Makefile.am'や個別
の`Makefile'の断片にファイルリストを生成するスクリプトを使う人も
います.
移植性に気を付けていなくても,GNU Makeだけをターゲットにしていて,なん
とかして$(wildcard ...)
を使用したい場合でも,処理されるファイル
をAutomakeが正確に知っている必要がある場所がたくさんあることを知ってお
くべきです.Automakeは$(wildcard ...)
を展開する方法を知らないの
で,これらの場所で使用することは不可能です.$(wildcard ...)
は,
Automakeが尊重するAC_SUBST
されている変数と比べてブラックボック
スになります.
-Wportability
フラグを使用すると,$(wildcard ...)
の構成物
は警告されるはずです.
これは(Files left in build directory after distclean),make
distcheck
時に遭遇する可能性がある診断結果です.
配布物に含まれるもので説明したように,make distcheck
では,このようなエラー
に対し,パッケージのビルドと調査を試みます.
make distcheck
は,パッケージのVPATH
のビルドを実行し,
make distclean
を呼び出します.make distclean
が実行された
後で,ビルドディレクトリに残っているファイルは,このエラーの後でリスト
アップされます.
この診断結果は,実際には二種類のエラーをカバーしています.
distcleanで忘れられているファイル.
間違ってリビルドされる配布ファイル.
残っている前者のファイルは配布されないので,クリーンするよう (see section クリーンされるもの)印が付いているものを修正します.これは明白で,文句を言 われても仕方がありません.
後者のバグは,理解し修正するのが常に容易だというわけではないので,例を
用いて説明します.パッケージにhelp2man
を使用してmanページを
ビルドしたいプログラムが含まれていると仮定します.GNU
help2man
は,コマンドの--help
と--version
の出力
から簡単なマニュアルページを生成します(see (help2man)Top section `Overview' in The Help2man Manual).help2man
のインストールをユー
ザに強制したくないので,以下のような設定を使用して生成されたmanページ
を配布するように決めました.
# This Makefile.am is bogus. bin_PROGRAMS = foo foo_SOURCES = foo.c dist_man_MANS = foo.1 foo.1: foo$(EXEEXT) help2man --output=foo.1 ./foo$(EXEEXT) |
これで,manページを効果的に配布します.しかし,make distcheck
は
以下のように異常終了するでしょう.
ERROR: files left in build directory after distclean: ./foo.1 |
なぜ`foo.1'がリビルドされたのでしょうか?その理由は,配布はされな いものの,`foo.1'は配布されないファイル`foo$(EXEEXT)'に依存 しているためです.`foo$(EXEEXT)'はユーザがビルドするので,それは 配布されている`foo.1'より常に新しいものになります.
make distcheck
はパッケージ内の矛盾をとらえます.ユーザが
help2man
をインストールする必要が無いように,`foo.1'を配
布するのが目的でしたが,このルールで今ではファイルが常にリビルドされ,
ユーザはどうしてもhelp2man
が必要になります.
`foo.1'がユーザにリビルドされないことを確実にする,または
`foo.1'の配布を諦めるかのいずれかにすべきです.
より一般的には,配布されるファイルのルールには,配布されないビルドされ るファイルに決して依存しないようにすべきです.生成されたものを配布する 場合,そのソースを配布してください.
上記の例を修正する一つの方法として,配布される`foo.1'が
`foo$(EXEEXT)'に依存しないようにします.例えば,foo
--version
とfoo --help
が,`foo.c'や`configure.ac'
が変更されない限り変更されない状況では,以下のような`Makefile.am'
を書くことが可能です.
bin_PROGRAMS = foo foo_SOURCES = foo.c dist_man_MANS = foo.1 foo.1: foo.c $(top_srcdir)/configure.ac $(MAKE) $(AM_MAKEFLAGS) foo$(EXEEXT) help2man --output=foo.1 ./foo$(EXEEXT) |
この方法では,`foo.1'は`foo$(EXEEXT)'が変更されるたびにリビ
ルドされません.make
はhelp2man
の前に
`foo$(EXEEXT)'を確実に更新します.これを確実にするもう一つの方法
は,バイナリとmanページに対して別のディレクトリを使用し,
SUBDIRS
をmanページがビルドされる前にバイナリがビルドされるよう
に設定することです.
`foo.1'を配布しないように決定することも可能です.この状況では, `foo.1'が`foo$(EXEEXT)'に依存するようにすると両方ともリビル ドされるので優れています.しかし,`foo.1'のビルドで `foo$(EXEEXT)'を実行するので,クロスコンパイルでパッケージ をリビルドすることは不可能です.
そのようなエラーがあるもう一つの状況は,配布されるファイルがパッケージ でビルドされるツールを用いてビルドされるときです.パターンは似ています.
distributed-file: built-tools distributed-sources build-command |
以下のように変更すべきです.
distributed-file: distributed-sources $(MAKE) $(AM_MAKEFLAGS) built-tools build-command |
または,クロスコンパイルで問題になる場合は`distributed-file'を配 布しないように選択することも可能です.
これらの例に意味がある状況をまとめます.
|
絶望的な状況では,配布物に含まれるもので説明したように,
distcleancheck_listfiles
を設定することで,この調査を利用不可能
にすることが可能です.こうする前に,make distcheck
が文句を言う
理由を必ず理解して下さい.distcleancheck_listfiles
はエラー
を隠す方法で,それを修正するものではありません.良いようにして下さい.
これは,ターゲットごとにコンパイルフラグが使用されているとき発生します. オブジェクトファイルは,同じソースから異なるフラグを用いてコンパイルさ れるオブジェクトが互いに壊されないように,名前を変更する必要があります. 以下の例を考えて下さい.
bin_PROGRAMS = true false true_SOURCES = generic.c true_CPPFLAGS = -DEXIT_CODE=0 false_SOURCES = generic.c false_CPPFLAGS = -DEXIT_CODE=1 |
二つのプログラムが同じソースからコンパイルされ,同じオブジェクトが共有
される場合は問題になるのは明らかで,それは,`generic.o'は
-DEXIT_CODE=0
と-DEXIT_CODE=1
の両方を用いてコンパ
イルすることが不可能だからです.このため,automake
は二つの異
なるオブジェクト,`true-generic.o'と`false-generic.o'をビル
ドするルールを出力します.
automake
は,オブジェクトファイルの名前を変更する必要があるか
どうかを決定するため,実際にはソースファイルが共有されているかどうかを
見ていません.ターゲットごとのコンパイルフラグを使用していることが判明
したときに,すべてのターゲットのオブジェクトの名前を変更するだけです.
ターゲットごとのコンパイルフラグが使用されていないときは,オブジェクト ファイルを共有しても問題ありません.例えば以下の例のように, `true'と`false'が両方とも`version.o'を使用しているとき です.
AM_CPPFLAGS = -DVERSION=1.0 bin_PROGRAMS = true false true_SOURCES = true.c version.c false_SOURCES = false.c version.c |
オブジェクトファイルの名前の変更は,_SHORTNAME
変数にも影響され
ることに注意して下さい(see section プログラムとライブラリの変数).
このセクションでは,複数の出力ファイルを生成するときに使用可能な
make
の特色を記述します.それはAutomake特有のものではありませ
んが,通常の`Makefile'で使用することが可能です.
一つの`data.foo'というファイルを読み込み,二つの`data.c'と
`data.h'という名前のファイルを生成する,foo
というプログ
ラムを想定します.我々は,以下の一つのものから二つのものへの依存をとら
える`Makefile'ルールを書こうとしています.
そのままのルールは間違っています.
# This is incorrect. data.c data.h: data.foo foo data.foo |
上記のルールが実際に伝えているのは,`data.c'と`data.h'がそれ
ぞれ`data.foo'に依存していて,それぞれがfoo data.foo
の実行
でビルド可能であるということです.言い替えると,以下と等価です.
# We do not want this. data.c: data.foo foo data.foo data.h: data.foo foo data.foo |
これは,foo
を二回実行するはずだということを意味します.
make
の実装では,最初の一つがビルドされた後に二番目のファイル
の存在を調査するよう十分に賢いものなので,普通は二回実行されないでしょ
う.すなわち,すでに存在していることがわかっています.しかし,場合によっ
ては二回実行される可能性もあります.
最も厄介な状況は,並行してmake
されるときです.`data.c'
と`data.h'が並行してビルドされる場合,二回foo data.foo
コマ
ンドが同時に実行されます.これは有害です.
もう一つの状況は,依存性(ここではdata.foo
)が偽のターゲットであ
る(またはそれに依存する)状況です.
並列したmake
の動作を解決し,偽の依存性は解決できない方法とし
て以下のものがあります.
data.c data.h: data.foo foo data.foo data.h: data.c |
上記のルールは以下と等価です.
data.c: data.foo foo data.foo data.h: data.foo data.c foo data.foo |
これで,並列したmake
は,`data.c'と`data.h'の連続し
たビルドになり,二番目は一回目で終っているので,もはや不要であることを
検出します.
このパターンを使用することで,おそらくほとんどの状況を十分満たすでしょ う.しかし,出力ファイルが多くなるにつれ(この手法では,すべての出力ファ イルを依存関係の完全な順番にする必要があり)難しくなるので,我々はより 複雑な解決方法を探りました.
もう一つの考えは,以下のように書くことです.
# There is still a problem with this one. data.c: data.foo foo data.foo data.h: data.c |
この考えは,foo data.foo
は`data.c'を更新する必要があるとき
だけ実行されますが,我々は,`data.h'が`data.c'に依存するとい
う一歩先の立場にいることになります.つまり,`data.h'が必要になり,
`data.foo'が古い場合,`data.c'の依存性によってビルドが開始さ
れるでしょう.
これでほとんど完璧ですが,我々は,`data.h'と`data.c'をビルド
しておき,その後で`data.h'を削除することを提案します.そうするこ
とで,make data.h
のとき`data.h'はリビルドされません.上記
のルールでは,`data.foo'に対応して`data.c'は更新する必要があ
りますが,既にそうなっています.
我々が必要なものは,`data.h'がないときにリビルドを強制するルール です.以下のようにします.
data.c: data.foo foo data.foo data.h: data.c @if test -f $@; then :; else \ rm -f data.c; \ $(MAKE) $(AM_MAKEFLAGS) data.c; \ fi |
上記では,出力と入力が多くなっても簡単です.出力の一つは,コマンド実行
の証拠として提供されるために必要なものが分かり,それはすべての入力に依
存し,それ以外の出力ファイルもすべてそれに依存します.例えば,
foo
に`data.bar'の読み込みを追加し,`data.w'と
`data.x'も出力させる場合,以下のように書くでしょう.
data.c: data.foo data.bar foo data.foo data.bar data.h data.w data.x: data.c @if test -f $@; then :; else \ rm -f data.c; \ $(MAKE) $(AM_MAKEFLAGS) data.c; \ fi |
この設定では,ちょっとした問題が残っています.foo
の出力は四
つのファイルですが,これらのファイルが生成される順序が分かりません.
`data.h'が`data.c'の前に作成されると仮定します.そうなると奇
妙な状況に陥ります.次にmake
が実行されると,`data.h'は
`data.c'より古くなり,二番目のルールが開始され,シェルは
if...fi
コマンドを実行しますが,実際にはthen
の中だけが実
行され,すなわち何も起こりません.言い替えると,我々が選択した証拠は
foo
が生成する最初のファイルではないので,make
は実
行しても何もしないシェルを開始します.
簡単な答えは,これが生じたときにタイムスタンプを修正することです.
data.c: data.foo data.bar foo data.foo data.bar data.h data.w data.x: data.c @if test -f $@; then \ touch $@; \ else \ rm -f data.c; \ $(MAKE) $(AM_MAKEFLAGS) data.c; \ fi |
もう一つの解決方法は,以前のものとは互換性がありませんが,
foo
の出力するものではなく,別の専用ファイルを証拠として使用
することです.
data.stamp: data.foo data.bar @rm -f data.tmp @touch data.tmp foo data.foo data.bar @mv -f data.tmp $@ data.c data.h data.w data.x: data.stamp @if test -f $@; then \ touch $@; \ else \ rm -f data.stamp; \ $(MAKE) $(AM_MAKEFLAGS) data.stamp; \ fi |
foo
が実行される前に`data.tmp'が作成されるので,そのタイ
ムスタンプはfoo
が出力するファイルより古くなります.そして,
foo
が失敗した場合は`data.stamp'を更新したくないので,
`data.stamp'をfoo
の実行後に名前を変更します.
このような専用の証拠を使用することで,出力ファイルのリストが前もって分
からないときも簡単に処理できます.例として,単一のコマンドで,たくさん
の`*.el'ファイルを`*.elc'にコンパイルする,以下のルールを考
えてください.ELFILES
の定義方法は(それが空ではない限り)問題にな
りません(空のターゲットはPOSIXでは受け入れられません).
ELFILES = one.el two.el three.el … ELCFILES = $(ELFILES:=c) elc-stamp: $(ELFILES) @rm -f elc-temp @touch elc-temp $(elisp_comp) $(ELFILES) @mv -f elc-temp $@ $(ELCFILES): elc-stamp @if test -f $@; then \ touch $@; \ else \ rm -f elc-stamp; \ $(MAKE) $(AM_MAKEFLAGS) elc-stamp; \ fi |
仕上げに,GNU make
は,パターンルールを使用することで複数の出
力ファイルを用いたルールを表現することが可能です(see (make)Pattern Examples section `Pattern Rule Examples' in The GNU Make Manual).パター
ンルールは移植性がないので,我々はここで議論しませんが,GNU
make
を想定したパッケージでは便利になるはずです.
[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This document was generated by Akihiro Sagawa on June, 8 2005 using texi2html 1.70.