makedepend(1) Makefile における依存関係を生成する

書式

makedepend [ -Dname=def ] [ -Dname ] [ -Iincludedir ] [ -Yincludedir ] [ -a ] [ -fmakefile ] [ -oobjsuffix ] [ -pobjprefix ] [ -sstring ] [ -wwidth ] [ -v ] [ -m ] [ -- otheroptions -- ] sourcefile ...

説明

makedepend プログラムは sourcefile のそれぞれを順に読み込み、C のプリプロセッサと同様に解析する。 この際には、 #include ディレクティブがコンパイル時にどのように使われるかを正しく知るため、 #include, #define, #undef, #ifdef, #ifndef, #endif, #if, #elif #else の全てを処理する。 全ての #include ディレクティブは、他の #include を含んでいるファイルを参照することができ、これらのファイルにおいてもディ レクティブの解析が行われる。

sourcefile が直接・間接的に含んでいる全てのファイルが、 makedepend の文脈において依存関係と呼ばれるものである。 この依存性は、依存性が変化したときに再コンパイルすべきファイルを make(1) に指示する方法で makefile に書き込まれる。

デフォルトの動作では、 makedependmakefile という名前のファイルがあれば、これに出力を書き込む。 このファイルがない場合には、 Makefile に出力を書き込む。 -f オプションを使うと、別の名前の makefile を指定することができる。 makedepend は依存関係の出力の区切りを見つけるため、まず makefile 中で

# DO NOT DELETE THIS LINE -- make depend depends on it.

という行か、 -s オプションで与えられた行を探す。 この行が見つかった場合には、そこから makefile の末尾までは全て削除され、 ここから makedepend の出力が行われる。 見つからなかった場合には、プログラムは make ファイルの末尾にこの文字列 が追加され、出力はそれ以降に行われる。 コマンド行で指定された sourcefile のそれぞれに対し、 makedepend


     sourcefile.o: dfile ..

の形式の行を makefile に書き込む。 ここで、sourcefile.o はコマンド行で与えられた名前のサフィッ クスを ``.o'' に置き換えたものであり、dfilesourcefile を解析している時に #include ディレクティブ内で発見された依存関係、つまりそのファイルがインクルード しているファイルである。

``make depend'' と打ち込めば makefile の依存関係を最新の状態にできるよ うにするため、通常は makedepend は makefile 中のターゲットとして使われる。 この例を示す:
    SRCS = file1.c file2.c ...
    CFLAGS = -O -DHACK -I../foobar -xyz
    depend:
            makedepend -- $(CFLAGS) -- $(SRCS)

オプション

ユーザが cc(1) と同じオプションを使えるようにするため、このプログラムは処理できないオ プションは全て無視する。
-Dname=def または -Dname 定義を行う。 このオプションを指定すると makedepend のシンボルテーブル内に name に対する定義が作られる。 =def を指定しなかった場合には、シンボルは ``1'' と定義される。
-Iincludedir
インクルードディレクトリを指定。 このオプションを指定すると、 makedepend#include ディレクティブを処理するときに検索するディレクトリのリストを includedir の最後に追加する。 デフォルトでは makedepend は標準のインクルードディレクトリ(普通は /usr/include だが、コンパイラ 固有のディレクトリも含まれることがある)だけを検索する。
-Yincludedir
全ての標準インクルードディレクトリを、指定した1つのインクルードディレ クトリに置き換える。単に標準のインクルードディレクトリの検索をさせたく ない場合には、 includedir を省略することができる。
-a
依存関係部分の置き換えは行わないで、ファイルの末尾に追加するようにする。
-fmakefile
ファイル名を指定する。 このオプションにより、 makedepend の出力先に別の makefile を指定することができる。 ``-'' をファイル名に指定すること(つまり-f-)により、既存のファ イルを修正するのではなく、標準出力に出力を行うことができる。
-oobjsuffix
オブジェクトファイルのサフィックス。 システムによっては、オブジェクトファイルのサフィックスが ``.o'' でない かもしれない。 このオプションを使って別のサフィックスを指定することができる。 例えば、 -o.b によってサフィックス ``.b'' をすることや、 -o:obj によって ``:obj'' を指定することができる。
-pobjprefix
オブジェクトファイルのプレフィックスを指定する。 プレフィックスがオブジェクトファイルの名前の最初に追加される。このオプ ションは通常、他のディレクトリにあるオブジェクトファイルを指定するとき に使う。 デフォルトではプレフィックスは空文字列である。
-sstring
区切り文字列を開始する。 このオプションを使うと、 makedepend が makefile 内で別の区切り文字列を探すように指定できる。
-wwidth
行の幅を指定。 可読性のため、通常 makedepend は出力する全ての行が78文字を越えないことを保証している。 このオプションを使うとこの幅を変えることができる。
-v
詳しい表示を行う。 このオプションを指定すると、 makedepend はそれぞれのファイルがインクルードしたファイルのリストを標準出力に出力 する。
-m
複数回のインクルードに対して警告表示を行う。 このオプションを指定すると、 あるファイルが他のファイルを複数回インクルードした際には makedepend が警告を出す。以前のバージョンの makedepend ではこれはデフォルトの動作であった。複数回のインクルードをエラーとみな さないような C コンパイラの動作にもうまく適合できるように、このデフォ ルト動作は変更された。このオプションは以前との互換性のために残されてお り、複数回のインクルードに関連する問題のデバッグに利用できる。
-- options --
引き数リスト内に "--" がある場合、その後に続く makedepend が認識できない引き数は無視される(関連するメッセージも表示されない)。こ の特別な扱いは、再び "--" が現れるまで続く。 このようにして makedepend は、通常は make のマクロの CFLAGS に現れるような難解なコンパイラの引き数をうまく回避する ことができる(前述の のセクションを参照)。 "--" に挟まれていても、 makedepend が認識することができるオプションは全て通常通り扱われる。

アルゴリズム

このプログラムで使われている方法は、筆者が知っているどんな「依存関係生 成プログラム」よりも圧倒的に速い動作を可能にしている。 この高性能のポイントは2つの仮定を置くことである。 第一点は、同じ makefile でコンパイルされる全てのファイルのほとんどに対 しては、同じ -I オプションと -D オプションが使われることである。第二点は同じディレクトリにあるほとんど のファイルは、だいたい同じファイルをインクルードすることである。

これらの仮定を与えると、 makedepend がそれぞれの makefile に対して1度だけ呼ばれ、同時にこの makefile が管 理する全てのソースファイルは makedepend を呼び出す際のコマンド行に現れることを期待できる。 makedepend はソースファイルとインクルードファイルをそれぞれ1度だけ解析し、ソース ファイルとインクルードファイルに対する内部シンボルテーブルを1つ管理す る。 こうすると、コマンド行での最初のファイルの解析には、通常の C のプ リプロセッサの処理時間に比例する時間がかかる。 しかし、それ以降のファイルについては、一度解析したインクルードファイル が再び解析されることはない。

例えば、 file1.cfile2.c, の2つのファイルをコンパイルすることを考える。 この2つのファイルは header.h をインクルードし、 header.hdef1.hdef2.h をインクルードするものとする。 コマンド


    makedepend file1.c file2.c

を実行したとき、 makedepend は最初に file1.c を解析し、次に header.h を解析し、それから def1.hdef2.h を解析する。 makedepend は、最後にこのファイルに関する依存関係が


    file1.o: header.h def1.h def2.h

であることを決定する。 しかし、 makedependfile2.c を解析し、このファイルも header.h をインクルードすることを発見したときには、このファイルの解析は行われな い。この場合は、 file2.o の依存関係のリストに対して header.h, def1.h, def2.h が単純に追加される。

バグ

makedepend は SVR4 の #predicate(token-list) というプリプロセッサ式の解析は行うが、 評価は行わない。このような式は単純に真と仮定される。 そのため、正しくない #include ディレクティブが評価されることがある。

2つのファイル file1.cfile2.c を解析することを考える。両方のファイルとも def.h をインクルードするものとする。 実際には file1.c からインクルードされた場合と file2.c からインクルードされた場合では、 def.h がインクルードするファイルのリストは変化するかもしれない。 しかし、 makedepend は一度あるファイルに対する依存関係を見つけると、これを固定のものとして 扱う。

著者

Todd Brunhoff, Tektronix, Inc. and MIT Project Athena