make を使おう
註: この文書は『SoftwareDesign』2001年2月号 に掲載された記事の元となるものに手を加えたものです.
間違いを見つけたら,gotoken@notwork.org宛に御連絡くださると喜びます。
Copyright(c) 2001 by GOTO Kentaro. All rights reserved.
Cで書かれたプログラムを実行するまでには、少なくとも1度はすべてのソース をコンパイルしてリンクしなければなりませんが、一部に修正を加えた場合は 関係するプログラムだけを再コンパイル、リンクすれば十分です。このとき必 要な作業だけを行なうのがmakeの役割です。Makefileにプログラムの依存関係 を記述してやればmakeは必要なコマンドだけを実行します。こうしてmake を 使うことで開発効率が大幅に改善されるのです。
Perlの作者である Larry Wall さんはその著書 ``Programming Perl''
[WCO00] の中で、プログラマの3大資質として lazziness(無精)、
impatience(短気)、hubris(傲慢)を挙げています。このうちもっとも重要とさ
れる無精は、エネルギーの総消費量を押えるためにどんな努力もしてしまう性
分のことだと説いています(単にズボラなだけではないことに注意 :-)。実際、
ソフトウェアの開発過程は自動化できることをすべて自動化するという無精の
原則で発展してきました。系統だてられた自動化は単純なミスを防ぐ最良の方
法なのです。その最たるものが make でしょう。ちょっとの手間をかけ
て Makefile というものを書いておけば、make がコンパイル作
業の多くを自動化してくれるのです。この自動化によって劇的に省略される手
間にくらべれば Makefile の書き方を覚える労力はまさに些細なものだ
といって良いでしょう。
1章でみたように分割コンパイルを行なえば、コードの再利用やコンパイル時
間の節約をすることができるのですが、make の助けがなければこれら
の利点を発揮するのはかえって面倒なことでしょう。そういったわけで
make の使い方、いいかえれば Makefile の書き方はぜひ知って
おきたいものです。
make の機能ははそれほどたくさんではありませんが、ここで紹介しき
れるほど少なくもないので、本稿ではその基本的なもののうち、とくに知って
おきたいところだけを取り上げます。make は Version 7 AT&T UNIX と
いう昔のUNIXで初めて登場しましたが、その後いろいろな子孫が生まれ、そ
れぞれに独自の進化をとげています。ここではいずれの make にも共通
することを主に取り上げますが、とくにフリーソフトウェアで重要なふたつの
分家であるBSDとGNUの make の違いもいくつか紹介します。
make ってなに?
ひとことでいえば make は Makefile に従ってコマンドを生成す
るだけものです。それだけ聞くとスクリプト*1に似ていると思うかも知れませんが、実際はだいぶ違います。ま
ずは簡単な例で概略をみてみましょう。
いま、calc というTTYベースのプログラムを作成しているとします。こ
のプログラムは、calc.c, eval.c, parse.c をそれぞれコ
ンパイルしてできる3つのオブジェクトファイルと libm ライブラリをリンク
すれば実行できます。すべてをコマンドラインから与えるなら次の通りです。
$ cc -c calc.c $ cc -c eval.c $ cc -c parse.c $ cc -o calc calc.o eval.o parse.o -lm
calc を作るには calc.o, eval.o, parse.o が必要
です。言い替えれば calc は calc.o, eval.o,
parse.o に依存します。このことを表す Makefile は次の通りで
す。ただし、2行目の先頭はタブ文字です。
calc: calc.o eval.o parse.o cc -o calc calc.o eval.o parse.o -lm
この2行だけからなる Makefile を用意して make を実行すれば
次のような結果を見ることになるでしょう。
$ make calc cc -c calc.c cc -c eval.c cc -c parse.c cc -o calc calc.o eval.o parse.o -lm
make の引数に与えた calc はターゲットと呼ばれます。
ターゲットを省略すると Makefile のなかで一番最初に現れるターゲッ
トを作ろうとします。いまの場合は Makefile の先頭のターゲットは
calc でしたから、次のようにコマンドラインではターゲットを省略す
ることができます。
$ make
ところで、*.c から *.o を作る方法を Makefile に記述
していなかったのに、make はきちんと cc を起動しました。あ
とで触れるように、make はいくつかの作り方をあらかじめ知っている
ので、とくに指定しなければその作り方を実行します。
make の本領
次に、いったん calc を作ったあとで parse.c を修正したとし
ます。ふたたび make を実行してみましょう。
$ make cc -c parse.c cc -o calc calc.o eval.o parse.o -lm
make は必要な作業だけを行ないました。このように修正に応じて必要
なコマンドだけを行なうことが make の最大の役割です。もし、
calc が十分に新しく、何も実行する必要がなければ make はそ
のことを告げるだけです。
$ make `calc' is up to date.
さて、いま作っている calc を利用してGUI版の calcg を作った
とします。calcg は calc.c の代わりに calcg.c を使い、
さらに widget.c という部品を用意しました。また、libX11とlibXext
の関数も使ったので、これらのライブラリもリンクする必要があります。この
場合は Makefile には次の3行を書き足せば良いのです。
calcg: calcg.o eval.o parse.o widget.o
cc -o calcg \
calc.o eval.o parse.o widgets \
-L/usr/X11R6/lib -lXext -lX11 -lm
そして、calcg を作るには make calcg を実行します。
calcg を calc の規則のあとに付け足したので、calcg は
Makefile 中の最初のターゲットではないため calcg を省略する
ことはできないのです。
$ make calcg
cc -c calcg.c
cc -c widget.c
cc -o calcg \
calcg.o eval.o parse.o widget.o \
-L/usr/X11R6/lib -lXext -lX11 -lm
このように、Makefile の中には複数のターゲットの作り方を記述する
ことができます。ターゲットの名前が書いてある行には依存関係が書かれてい
るので依存関係行と呼びます。依存関係行のコロンの右側に羅列されて
あるものはコンポーネントと呼ばれます。またコマンドが書いてある行
を(シェル)コマンド行と呼びます。
Makefile ではマクロを使うこともできます。たとえば cc
の代わりに gcc を使いたいとしましょう。このとき Makefile
中のcc をすべてgccに書き換えてしまうと、今度は cc を
使いたくなったときにまた書き直さなくてはならなくなります。正解は
cc を ${CC} と書き直し、CC=gcc としておくことです。
また、すでに一度 make を実行していれば、*.o があるので、な
にも起こらないはずです。手動で rm を実行してもいいのですが、消し
忘れると面倒なので、通常は clean というダミーターゲット を
用意しておきます。ついでに calc と calcg の両方を作るダミー
ターゲットall も用意しておきましょう。all は最初のターゲッ
トにしておくと便利でしょう。結局Makefileは次のようになります。
CC = gcc
all: calc calcg
calc: calc.o eval.o parse.o
${CC} -o calc calc.o eval.o parse.o -lm
calcg: calcg.o eval.o parse.o widget.o
${CC} -o calcg calc.o eval.o parse.o \
-L/usr/X11R6/lib -lXext -lX11 -lm
clean:
rm -f *.o calc calcg
試しに使ってみましょう
$ make clean
rm -f *.o calc
$ make
wooky% make
gcc -c calc.c
gcc -c eval.c
gcc -c parse.c
gcc -o calc calc.o eval.o parse.o -lm
gcc -c calcg.c
gcc -c widget.c
gcc -o calcg calcg.o eval.o parse.o widget.o \
-L/usr/X11R6/lib -lXext -lX11 -lm
ターゲットを複数指定した場合は左から順に作られます。よって上の2つのコ マンドは次の1つのコマンドにまとめることができます。
$ make clean all
また、gcc ではなく再び cc を使いたくなったら、次のコマンド
を実行すれば良いのです。
$ make clean all CC=cc
いくつもの重要なことをまだ紹介していませんが、make と Makefile
が何であるのか、またどう使うのかを示すことはできました。
makeがやること
make は起動されると次のような原理で動作します。最終的なゴールは
指定されたターゲットを最新のものにすることです。そのためには、まず指定
されたターゲットが依存するコンポーネントを最新にした後、ターゲットとコ
ンポーネントの最終更新時刻をくらべ、ターゲットの方が古ければ(つまりター
ゲットが最新でなければ)、コマンド行を実行します。
ターゲットの最終更新時刻とはターゲットと同名のファイルの最終更新時刻の ことで、ls -l で得られる時刻情報と同じものです。ターゲットと同名 のファイルが見つからない場合も最新ではないと判断されます。
コンポーネントを最新にする手順は指定されたターゲットを最新にするの同様 です。コンポーネントが更になにかに依存している場合は再帰的に最新にする 手続きが行なわれます。もし、この手順を進めていくうちにターゲットと 同名のファイルが見つからず、なおかつその作り方が見つからない場合は次の ようなエラーメッセージを出して作業を中止します(このメッセージは前節で calc を clac と打ち間違えると見ることができます)。
make: *** No rule to make target `clac'. Stop.
make が実行しているコマンドがエラーを起こすと、やはりそこで作業
を中止します。コマンドがエラーを起こしたとは、そのコマンドの終了ステー
タスが0でないことを意味します(コラム「終了ステータス」参照)。
次のように依存関係が循環している場合はエラーとなります。
a: b b: c c: a
この場合、いずれのターゲットを make しようとしても、次のような
エラーを見ることになります*2。
(GNUのmakeの場合)
make: Circular c <- a dependency dropped.
make: Nothing to be done for `a'.
(BSDのmakeの場合)
Graph cycles through a
`a' not remade because of errors.
ちなみに、依存関係のある仕事をやらなければならない順番に並べるにはトポ ロジカルソート[Oku91]というアルゴリズムが用いられます。
Makefileの書き方
これまで見たように Makefile には3種類のものがあります。すなわち、
依存関係行、依存関係行に関連づけられたシェルコマンド行、そしてマクロ定
義行です。
Makefile では # から行の終りまでがコメントとして扱われ、こ
の部分はmake の動作に影響を与えません。文字通りコメント(注釈)を
いれたり、あるいは行を変更する場合にもとの行をとっておくために使われる
のはプログラム言語と同様です。
## Choose library # LDFLAGS = -lcpml LDFLAGS = -lm
すべてに共通する規則として行の継続が挙げられます。これは、長い行を人間
が読み書きしやすくするために折り返すことができるというものです。すでに
calcg の規則で見たように、行末にバックスラッシュ「\を置か
れていると、次の行がその行の続きとして解釈されます。ただし、バック
スラッシュと改行文字の間に空白を置いてはいけません。これはエディタ
の上では発見しにくいので注意が必要です。同様に発見が難しく、またもっと
もありがちな間違いは、コマンド行の先頭がタブになっていないことです。こ
れらを発見する一つの方法は
$ cat -t -e Makefile
を実行することです[OT91]。このふたつのオプションをつけると
cat はタブを ^I と表示し、行の終りを $ と表示します。
コラム 「間違い探し」も参照して下さい。
Makefile でマクロを定義するには等号を用います。
COMMONOBJS = eval.o parse.o LDFLAGS = -lm
参照は $ に続けてマクロの名前を { } で囲んだものを使います。
calc: ${COMMONOBJ} calc.o
${CC} -o calc ${COMMONOBJ} ${COMMONOBJ} ${LDFLAGS}
右辺が空のマクロは長さが0の文字列に展開されます。以下の規則では、
B の値は xz になります。
A =
B = x${A}z
マクロはコマンドラインからも与えることができます。
$ make A=y
空白を含む値をコマンドラインで渡すにはクオートしなければなりません。
$ make 'A=y z'
マクロをコマンドラインから与える場合、環境変数として渡すこともできます
が、同名のマクロが Makefile で定義されている場合は、そちらが優先
されます。次の実行例を見て下さい。
$ cat Makefile
FOO = xxx
BAR =
env:
echo ${FOO},${BAR},${BAZ}
$ env FOO=foo BAR=bar BAZ=baz make
echo xxx,,baz
xxx,,baz
逆にコマンドラインから与えられたマクロが有効なとき環境変数として設定さ れます。
ところで make はこれから実行しようとするコマンドを表示してから実
行しますが、この「コマンドをあらかじめ表示する」という機能を止めたい場
合があります。たとえば上の例のように echo を使って利用者にメッセージを
表示させたい場合などです。このようなときは、コマンドの先頭に @
をおくと、そのコマンドは黙って表示されます。
$ cat Makefile
FOO = xxx
BAR =
env:
@ echo ${FOO},${BAR},${BAZ}
$ env FOO=foo BAR=bar BAZ=baz make
xxx,,baz
また、あらかじめ定義されているマクロもたくさんあります。これらのデフォ ルトの値を調べるには、次のようにします。
(GNUのmakeなど)
$ make -p
(BSDのmake)
$ make -d g1
あらかじめ定義されているマクロのほとんどは後で述べるデフォルトのサフィッ
クスルールに影響を与えるマクロです。一例としては、CC、CFLAGS、
LDFLAGS、LDLIBS などがあります。
また特別な意味を持つマクロの一つに SHELL があります。このマクロ
は、コマンドを実行するときに使うシェルを表すもので、デフォルトの値は処
理系によって異なります。
マクロの参照時に値の一部を書き換える方法も用意されています。たとえば、
次の例では、SRCS を使って新たなマクロ EUCSRCS を作ります。
SRCS = sora.c irono.c taxi.c
EUCSRCS = ${SRCS:.c=_euc.c}
この Makefile のなかにコマンド echo ${EUCSRC} があれば、次
のような出力をします。
sora_euc.c irono_euc.c taxi_euc.c
つまりコロンの後ろにある文字列を等号の後ろにある文字列で置き換えます。
依存関係行は次の形をしています。
ターゲット: コンポーネント ...
ターゲットはすでに見たように make の引数として与えれるものですが、 いくつかの便利な書き方が用意されています。まず、複数のターゲットが同じ ものに依存するとき、コロンの左側に並べて書くことでこれらを束ねて書くこ とができます。
calc.o perse.o eval.o: calc.h
また、一つのターゲットに対して二つ以上の依存関係行を書くことができます (ただしコマンド行はそれらの依存関係行に対して多くても一つにしか書けません)。
calc.o: calc.h calc.o: calc.c define.h
そして、サフィックスルールは知っておかなければ損をするたぐいのものです。
冒頭で示した calc の Makefile の例で、*.c から
*.o を作る方法をしていないのはデフォルトの規則が仮定されているた
めだと述べましたが、これは具体的には次のような規則です。
.c.o:
${CC} ${CFLAGS} -c $<
これは なんとか.c から なんとか.o を作るということをサフィッ
クス*3についてま
とめて書いたもので、サフィックスルールと呼ばれます。
.c.o:
${CC} ${CFLAGS} -c $<
ここで登場する $< はターゲットの現在のソースを表す内部マクロです。
具体的に説明しましょう。次のターゲット calc を解決する場合、まず
calc.o、eval.o、parse.o の3つを解決しようとします。
calc: calc.o eval.o parse.o
calc.o を解決する仮定では、まず Makefile 内に依存関係が記
述されていないかを探し、なければデフォルトのサフィックスルールを探しま
す。そし て、サフィックスルール .c.o が見つかり、$<に
calc.cが代入され、次にcalc.cを探し見つかれば、
cc が実行されるのです。
さてサフィックスルールを記述するためには make にサフィックスを追
加登録してやる必要があります。たとえば LaTeX のファイル(.tex)か
ら、DVIファイル(.dvi)とPSファイル(.ps)を作るためには新しく
3つのサフィックス.tex、.dvi、.psを登録する必要があ
ります。登録するには .SUFFIX: に続けて書きます。ここでは現在のターゲッ
トを表す内部マクロ $@ を使っています。
.SUFFIX: .tex .dvi .ps
LATEX = platex
DVI2PS = dvi2ps
.tex.dvi:
${LATEX} $<
.dvi.ps:
${DVI2PS} $< > $@
make は .c や .o のような典型的なサフィックスをいく
つもあらかじめ知っています。make が何を知っているかは、マクロの
デフォルトの値を調べる方法と同じようにして知ることができます。
以上で Makefile の基本的な部分をすべて紹介しました。これだけ知っ
ておけば、かなり複雑な Makefile も書くことができると思います。こ
れより先は大きなプログラムに適用する場合やライブラリの作成にまつわる話
題となりますので自習にお任せします。
make に関する定評のあるテキストは『make 改訂版』[OT91]です。
この本は AT&T の System V Release 4 の make を取り上げています。
本稿ではあまり大きなソフトウェアに適用する際の問題点を挙げることができ
ませんでしたが、この本では ar コマンドで作られるアーカイブファイ
ルの取り扱いやカレントディレクトリ以外にあるコンポーネントやターゲット
を作る方法、そしてその問題点と解決法も書かれています。現在ではさまざま
な種類の make が存在しますが、この本を読めば共通する部分を学ぶこ
とができるでしょう。共通しない点についての注意点や調査方法も書かれてい
ます。
個別の make のコマンドラインオプションや特別な機能は man
make で知ることができます。数多く存在するmake のなかでも、PC
UNIX が広まった現在では、とりわけBSDとGNUの make が重要さを増し
てきています。どちらも条件分岐構文や特別なマクロ代入のような拡張をそれ
ぞれのやりかたで採用しています。またいずれの make も並行実行に対
応しています。これはmake の行なう処理の性格上、ディスクアクセス
による待ち時間が存在するため、とくに速いCPUを積んだマシンでは効果的で
す。
BSDの make は pmake から派生したものです。pmake につい
てはBSDではオンラインで参照できるチュートリアル[Boo]が用意されて
います。その所在は man make を確認して下さい。ただし、これは1987
年頃に書かれたもので新しい機能は載っていません。FreeBSD の場合、ports
という名前で知られるソフトウェアをインストールするシステムがあり大変便
利なものですが、これは make を利用して作られています。ports は数
千の Makefile とデータベースファイルからなる巨大な make シ
ステムです。これはターゲットとマクロの使い方を約束することで成り立って
います。
一方、GNU の make は Linux では標準ですが、他の環境では
gmake という名前でインストールされていることもあります。この
make は AT&T の make を含む形で大幅に拡張されています。GNU
の make の詳細なマニュアル[FSF]もまたオンラインで読むこと
ができます。こちらは GNU の優れた文書システムである info 形式で提供さ
れています。少々古くなりましたが以前の info の翻訳は書籍として出版され
ています。GNU General Public Licence (いわゆるGPL)で配布されているフリー
ソフトウェアには GNU の make でなければコンパイルできないものも
あります。
またUNIXのプログラミングツール全般にいえることですが、今日では、書籍や
Webページのようなドキュメントを参照するほかにフリーソフトウェアで実際
に使われている Makefile を読むという勉強法もあります。ただし、あ
まり大きなソフトウェアの場合は Makefile もそれなりに大きく、読む
のも大変です。人の書いた Makefile を学習を目的として読むならば、
小さなソフトウェアの Makefile を参考にするのが良いでしょう。また、
具体的な問題にぶつかった時に、似たようなことをしている Makefile
にあたりをつけて読むとわかることがあるかも知れません。
make を使ったコンパイルをはじめたならば、あなたのソフトウェア開
発における意識的な自動化の出発点になるでしょう。自動化された手続きを採
用することの必要性と重要性は『達人プログラマー』[TH00]で鋭く言及さ
れています。この本は単なる技術書ではなくプログラミングの生産性を高める
ための pragmatic (現実的)な tips が満載です。
本稿が make を使うきっかけになり、あなたの無精を発揮させることが
できれば幸いです :-)
Adam de Boor, ``PMake - A Tutorial'', オンラインテキスト (BSDに付属
FreeBSDならば /usr/share/doc/psd/12.make/ にある)
``GNU Make Manual'', infoファイル (インストールされていれば、Emacsで M-x infoで見ることができる. 89年版の Richard Stallman, Roland McGrath, ``GNU Make A Program for Directing Recompiltation'', Free Software Fundation の邦訳は出版されている: 戸松豊和『GNUリファレンス マニュアル MAKE』, アディソン・ウェスレイ・パブリッシャーズ・ジャパ ン (1993))
奥村晴彦, 『C言語による最新アルゴリズム事典』, 技術評論社 (1991), pp198-199
Andrew Oram, Steve Talbott, ``Managing Projects with make'', 2nd edition, O'Reilly (1991) (邦訳: 矢吹道郎監訳, 菊池彰訳『make 改訂版』, オライリー・ジャパン (1997))
David Thomas, Andrew Hunt, ``The Pragmatic Programmer'', Chapter 8. Pragmatic Project, Adison Wesley (2000) (邦訳: 村上雅章, 『達人プロ グラマー』, 第8章「達人のプロジェクト」, ピアソン・エデュケーション (2000))
Larry Wall, Tom Christiansen & Jon Orwant, ``Programming Perl'', 3rd edition, O'Reilly (2000) (この版の邦訳はまだありませんが第2版はあります: 近藤嘉雪訳『プログラ ミングPerl改訂版』, オライリー・ジャパン (1997))
UNIXではコマンドは終了ステータス(exit status)というものを返します。終
了ステータスはC言語では exit の引数に与えられたものですが、一般
にはそのコマンドが成功した場合に0を返し、失敗した場合はそれ以外の値を
返すことになっています。終了ステータスはコマンドが成功したか失敗したか
を知るための唯一の方法です。終了ステータスは例えば次のようなシェルのワ
ンライナーで利用することができます。
$ cc -o hoge hoge.c && hoge test
この例では cc が成功したときにかぎり hoge test が実行され
ます。make によるコマンド実行も同様で、失敗した時点で残りの作業
は中止されます。Makefile を書く際に問題になりやすいのは rm
と mkdir の終了ステータスです。rm は clean ターゲッ
トに書かれますが、引数で指定したファイルが存在しない場合はエラー、つま
り0以外の終了ステータスが返ります。しかし、これは不便なことが多いため、
rm には必ず終了ステータスを0で終らせるためのオプション -f
が用意されています。次のような実験をすればわかります。
$ rm xxx
rm: xxx: No such file or directory $ echo $? 1 $ rm -f xxx $ echo $? 0
ここで出てくる $? は最後に実行されたコマンドの終了ステータスを表 すシェル変数です。
いっぽう install ターゲットに書かれることの多い mkdir には
rm -f のような便利なオプションはありません。このような場合のため
に Makefile には「コマンドの前に - をつけるとそのコマンド
が失敗しても無視して続きを実行する」という機能が用意してあります。次の
実験では mkdir のエラーが意図的に無視されています。
$ cat Makefile
xxx: - mkdir xxx touch xxx/afile $ make xxx mkdir xxx touch xxx/afile $ make xxx mkdir: xxx: File exists *** Error code 1 (ignored) touch xxx
なお終了ステータスは、main 関数で return を呼ぶのは
exit を呼ぶのと全く同じことです。main で return を場
合、コンパイラに怒られないために main の型は int としてお
くのが良いでしょう。一方、main から exit を呼んで終る場合
も main の型を void にすればコンパイル時に起こられるので
int にします。
タブと空白と改行前の空白はエディタの上で見分けが付かないことが多いのですが、不幸なこ
とに make は継続行の終りとコマンド行の先頭でこれらを区別すること
を要求するため Makefile の典型的な間違いの原因になります。本文で
述べたように cat を使って調べるの一つの方法ですが、あまり見やす
くはありません。次のRubyプログラムはxtermやktermの上で実行すると、これ
らの間違いの候補を目立つように表示するものです。単に実行すれば怪しい空白を
赤く表示し、ページャにパイプすれば太い「#」で置き換えたものを表示しま
す。
# mkmfview.rb
# - enphasize wrong spaces in Makefile
ARGV << "Makefile" if ARGV.empty?
def redspace(n)
"\e[41m#{' '*n}\e[m"
end
def boldhash(n)
"#\b#" * n
end
if STDOUT.tty?
alias em redspace
else
alias em boldhash
end
ARGV.each do |file|
IO.foreach(file) do |l|
l.sub!(/^( +)/){em($1.size)}
l.sub!(/\\( +)$/){"\\"+em($1.size)}
print l
end
end
Makefile を作るための道具」
もしあなたが X Window アプリケーションのプログラミングに make を
使いたいと思うなら imake のことを学ぶべきです。imake は
IMakefile というひな型から Makefile を作るもので、ローカル
の設定に合ったコンパイラのオプションを調べる手間が省けるだけでなく、他
の環境でもコンパイルできる Makefile が書けるという利点があります。
なお通常は imake をコマンドラインから入力することはなく、
xmkmf というコマンドを通じて起動されます。
Makefile を作るための imake は本来汎用ですが、X Window 以
外に適用するのはあまり易しくありません。現在では本特集の3章で取り上げ
られる GNU の autoconf を使うのが一般的です。移植を考えている場
合は是非とも知っておきましょう。Makefile の作成を助けてくれるツー
ルに makedepend があります。これも X のために作られたものですが、
imake と違いずっと広く使えます。これは
$ makedepend *.[ch]
のようにソースファイルを引数に与えて実行すると、インクルードに関する依
存関係を Makefile に追加します。#ifdef のような部分も理解
するので、環境にあった依存関係が生成されるのが特長です。ただしある程度
大規模なソフトウェアでないとうまみはないかも知れません。
もし人が書いたプログラムや、すでにあるプログラムの Makefile を書
かなければならなくなったときは、どの関数がどのファイルで定義されている
かを詳しく知る必要があります。とりあえず grep を使ってみるのも手
です。GNU の grep の -l と -L オプションはそれぞれ指
定されたパターンを含むファイルと含まないファイルの名前だけを表示します。
プログラムの内部を細かく追跡する必要がある場合は、ctags や GNU
の etags といったツールが有効です。これらはC言語の構文を知ってお
り、どのシンボルがどこで定義されたかを調べ、vi や emacs か
らブラウズすることを可能にします。もっと手っ取り早くブラウズするには、
cscope や htags といったツールが良いでしょう。
cscope*4 はcursesベー
スのCプログラムブラウザです。指定されたシンボルが定義されている場所や
使われている場所をサーチし、そのファイルを見ることができます。
Global*5 の一部である
htags はそれを HTML で実現するもので、HTMLブラウザを使ってCのコー
ドを探検することができます。
*1 コマンドを羅列した実行可能
ファイル
*2 古い make だともっとわかりにくい
エラーになるようです
*3 文字列の終りの部分、つまり .c と .o
*4<URL:http://cscope.sourceforge.net>
*5<URL:http://www.tamacom.com/global/>