この章ではGNUプログラム用にMakefileを記述する際の慣習について書いてあります。
Makefileには次の行を毎回含めるべきです。
SHELL = /bin/sh
…というのは、環境からSHELL
変数を受け継ぎ得るシステム上でのトラブルを避けるためです。(GNU make
ではこれは全く問題になりません。)
別のmake
プログラムには非互換のサフィックスリストや暗黙ルールがあり、場合によって混乱をきたしたり動作不良を起こします。このため次のように、個々のMakefileで必要なサフィックスだけを明示的にサフィックスリストにセットするのが良策です。
.SUFFIXES: .SUFFIXES: .c .o
はじめの行でサフィックスリストをきれいさっぱり除去して、次の行でこのMakefileで暗黙ルールに渡されてもいいサフィックスを全部書き込みます。
コマンド実行の際に`.'がパスにある事を仮定しないで下さい。make作業中にパッケージングした一部のプログラムを実行させる必要があるときは、プログラムがmake作業の一環とした場合の`./'を利用しているか、あるいはファイルのソースコードが変更されていない場合の`$(srcdir)/'を利用しているか、という事をどうかはっきりさせておいてください。これらの接頭語以外のものについてはカレントのサーチパスが利用されます。
ユーザーは`configure'に対する`--srcdir'オプションを利用してディレクトリを別にすることが可能なので(ビルド時のディレクトリである)`./'か(ソースディレクトリである)`$(srcdir)/'かの見極めは重要です。以下のようなルールでは…
foo.1 : foo.man sedscript sed -e sedscript foo.man > foo.1
…ビルド時のディレクトリがソースディレクトリでなかった場合、`foo.man'や`sedscript'はソースディレクトリにあるために失敗する事になります。
GNU make
を使う場合はソースファイルを検出するのに`VPATH'に頼れば、依存関係ファイルがたった一つしかない場合はそのソースファイルの場所によらず`$<'というmake
の自動変数がそのファイルの代わりをしてくれるのでちゃんと動作してくれることになります。(make
製品の多くは暗黙ルールでのみ`$<'をセットします。) 次のようなMakefileのターゲットは…
foo.o : bar.c $(CC) -I. -I$(srcdir) $(CFLAGS) -c bar.c -o foo.o
…かわりに次のように書くべきです。
foo.o : bar.c $(CC) -I. -I$(srcdir) $(CFLAGS) -c $< -o $@
…としなければ、`VPATH'が正しく動作しません。ターゲットに複数の依存関係がある時は明示的に`$(srcdir)'を使うのがにルールを正常に動作させる一番簡単な方法になります。例えば上で示した`foo.1'というターゲットについてはこう書くのが最良です。
foo.1 : foo.man sedscript sed -e $(srcdir)/sedscript $(srcdir)/foo.man > $@
GNUの配布物には普通、ソースでないファイル——例えばFlexかBison、Automake、Autoconfからの出力やInfoファイル——が含まれています。通常これらのファイルはソースディレクトリにあるため、常にビルドディレクトリではなくてソースディレクトリにあるべきです。このためこれらを更新するMakefileのルールでは更新されたファイルをソースディレクトリに吐き出します。
ですがもし配布物にファイルがなければ、その場合、いかなる事情があっても通常のプログラム構築でソースディレクトリを修正すべきではないためMakefileがソースディレクトリにそのファイルを吐き出すべきではありません。
最低でも、並行するmake
で構築してインストールさせるターゲット(とそのサブターゲット全部)をためしに作成するようにしておいて下さい。
Makefileのコマンド(やconfigure
のようないかなるシェルスクリプトも。)はcsh
ではなくsh
で実行するように記述してください。絶対ksh
やbash
の特別な機能は使わないで下さい。
構築やインストールを行ってくれるconfigure
スクリプトとMakefileのルールは次のディレクトリ以外のユーティリティディレクトリでは使うべきではありません。
cat cmp cp diff echo egrep expr false grep install-info ln ls mkdir mv pwd rm rmdir sed sleep sort tar test touch true
gzip
という複雑なプログラムはdist
ルールにおいて利用できるものです。
これらのプログラムで通常サポートされるオプションは打っ遣って下さい。例えば`mkdir -p'はお手軽ですがほとんどのシステムでサポートされていないため利用しないで下さい。
シンボリックリンクはかなり多くのシステムではサポートされていないので、これをmakefileで作成するのは避けたほうが賢明です。
構築、インストールを行うMakeifileのルールではコンパイラや関連するプログラムを使う事も可能ですが、ユーザーが自由に置き換えることができるようにmake
の変数を経由して利用すべきです。以下にそういうプログラムをいくつか掲載しておきます。
ar bison cc flex install ld ldconfig lex make makeinfo ranlib texi2dvi yacc
こういうプログラムを実行する際は以下のmake
の変数を利用して下さい。
$(AR) $(BISON) $(CC) $(FLEX) $(INSTALL) $(LD) $(LDCONFIG) $(LEX) $(MAKE) $(MAKEINFO) $(RANLIB) $(TEXI2DVI) $(YACC)
ranlib
かldconfig
を使う際はプログラム自身がシステムに存在しなかった場合に悪い事が起きないように配慮すべきです。それらのコマンドからのエラーを無視して、これらのコマンドの失敗は問題にならなかった事をユーザーに伝えるメッセージをコマンド前に出力するように手配してください。(Autoconf `AC_PROG_RANLIB'マクロがこの作業の手助けになってくれるでしょう。)
シンボリックリンクを利用する場合、シンボリックリンク機能がないシステムのためにフォールバックをインプリメントすべきです。
Makeの変数を経由して利用できる追加ユーティリティは次のものです。
chgrp chmod chown mknod
別のユーティリティを使うにはそれらのユーティリティがあるとわかっている特定のシステムだけのために部分的にMakefileで(またはスクリプトで)使うのはOKです。
Makefileでは特定のコマンドやオプションなどを上書きする変数を提供すべきです。
特にほとんどのユーティリティプログラムは変数を経由させて実行したほうがよく、Bisonを使うならばBISON
という名前の変数に`BISON = bison'という値がデフォルトで入っていますので、Bisonを使う必要がある場合は常に$(BISON)
で参照して下さい。
ln
やrm
、mv
などのようなファイル管理ユーティリティはユーザーが他のプログラムに置き換える必要がないので、このように変数を介して参照する必要はありません。
プログラム名をもつ変数はそれぞれにオプション変数という、プログラムにオプションを与える変数を併用すべきです。プログラム名を持つ変数に`FLAGS'を添えるとそれがオプション変数になります——BISONFLAGS
がこの例です。(この決まりごとの例外としてCコンパイラにはCFLAGS
、yaccにはYFLAGS
、lexにはLFLAGS
がありますが、これは標準的な機能なので保持しています。) プリプロセッサで実行されるコンパイルコマンドについてはすべてCPPFLAGS
を使うように、リンクを行うコンパイルコマンドについてはld
を直接使うのと同じようにすべてLDFLAGS
を使ってください。
特定のファイルのコンパイルを適切に行うのにCコンパイラオプションが必要不可欠な場合、CFLAGS
にはそういうオプションを含めないで下さい。ユーザーはCFLAGS
を自由に自分たちで指定できるような状態を望みます。なのでその代わりにCFLAGS
とは別に、次のように明示的にコンパイルコマンドで書くか暗黙のルールを定義して必要なオプションをCコンパイラに渡すようにして下さい。
CFLAGS = -g ALL_CFLAGS = -I. $(CFLAGS) .c.o: $(CC) -c $(CPPFLAGS) $(ALL_CFLAGS) $<
`-g'オプションは適切なコンパイルに要求されるものではないためCFLAGS
に含めます。これは単にデフォルトで推奨されるだけものである、と考えてくれてかまいません。デフォルトでGCCでコンパイルするためにセットアップされたパッケージなら、`-O'をCFLAGS
などのデフォルト値として含めておくといいかもしれません。
CFLAGS
はコンパイルコマンドの最後、コンパイラオプションを格納する他の変数より後に入力すれば、ユーザーがCFLAGS
を他のオプションを上書きするのに使えるようになります。
CFLAGS
は(コンパイル時、リンク時どちらにおいても)常にCコンパイラ起動時に利用されるべきです。
Makefileでは毎回INSTALL
という変数を定義して、システムにファイルをインストールさせる基本的なコマンドをそこに入れるべきです。
INSTALL_PROGRAM
とINSTALL_DATA
という変数もMakefileで毎度定義するべきです。(どちらもデフォルトで$(INSTALL)
になるべきです。) それで実行ファイルや非実行ファイルのそれぞれで実際のインストール作業ではこれらの変数をコマンドとして使うべきです。これらの変数は次のようにして利用してください。
$(INSTALL_PROGRAM) foo $(bindir)/foo $(INSTALL_DATA) libfoo.a $(libdir)/libfoo.a
インストール用コマンドの第二引数は常にディレクトリ名ではなくファイル名を用いてください。インストールされるそれぞれについて別々に一つずつコマンドを使ってください。
インストールディレクトリは常に変数で名前をつけ、標準ではない場所でも簡単にインストールできるようにすべきです。これらの変数の標準的な名前は下に記述してあります。ここに示す名前は標準ファイルシステムレイアウトに基づいた変数で、SVR4, 4.4BSD, Linux, Ultrix v4やその他現代のOS(オペレーティングシステム)で利用されているものです。
次の二つの変数はインストールのためのルートをセットするものです。他のインストールディレクトリはこの二つのうち一つのサブディレクトリになるようにし、この二つ以外のディレクトリ以下にならないようにすべきです。
prefix
のデフォルト値は`/usr/local'にすべきです。完全なGNUシステムをビルドする時はプリフィックスは空っぽになり、`/usr'が`/'に対するシンボリックリンクになります。(Autoconfを使っている方は`@prefix@'のように記述してください。)
exec_prefix
のデフォルト値は$(prefix)
にすべきです。(Autoconfを使っている方は`@exec_prefix@'のように記述してください。)
一般的に$(exec_prefix)
は(実行可能ファイルやサブルーチンライブラリなどの)機種特有ファイルを格納するディレクトリに対して利用され、それに対し$(prefix)
はそれ以外のディレクトリに対して直接利用されます。
実行可能プログラムは以下のディレクトリのうち一つにインストールされます。
プログラムが実行中に利用するデータファイルは二つの方法で分類されます。
これは異なる6つの可能性を生み出しますが、オブジェクトファイルとライブラリ以外の機種依存ファイルの利用は思いとどめて下さい。それ以外のデータファイルは独立構造にしたほうがずっときれいですし、一般的に難しいことではありません。
そういうことで、Makefileでディレクトリを指定するために使う変数をここに示します。
libdir
の値は`/usr/local/lib'にすべきですが、`$(exec_prefix)/lib'のように記述します。
(Autoconfを使っている方は`@libdir@'のように記述してください。)
lispdir='${datadir}/emacs/site-lisp' AC_SUBST(lispdir)
includedir
に依り、もう一つはoldincludedir
に依ります。
oldincludedir
の値が空っぽかどうかをチェックすべきです。もし空っぽなら利用しようとさせないほうが良く、ヘッダファイルの二度目のインストール作業をキャンセルさせるべきです。
そのパッケージに由来するヘッダファイルでない限りはパッケージでこのディレクトリに存在するヘッダを置換させないようにすべきです。つまりあなたの持っているFooパッケージが`foo.h'というヘッダファイルを提供するものであり、(1)もともと`foo.h'がないか、(2)すでに存在する`foo.h'がそのFooパッケージに由来するか、のどちらかに当てはまる場合は、
oldincludedir
ディレクトリにヘッダファイルをインストールさせるべきです。
`foo.h'がFooパッケージに由来するものかどうかを知らせるにはファイルにコメントの一部として魔法の文字列を入力しておき、その文字列に対してgrep
します。
UNIX形式のmanページは以下のうち一箇所にインストールします。
最後に以下の変数をセットすべきです。
configure
シェルスクリプトで挿入されます。
(Autconf利用者は`srcdir = @srcdir@'を使ってください。)
例えば、
# Common prefix for installation directories. # NOTE: This directory must exist when you start the install. prefix = /usr/local exec_prefix = $(prefix) # Where to put the executable for the command `gcc'. bindir = $(exec_prefix)/bin # Where to put the directories used by the compiler. libexecdir = $(exec_prefix)/libexec # Where to put the Info files. infodir = $(prefix)/info
プログラムで標準のユーザー指定ディレクトリの一つに大量のファイルをインストールさせる場合、そのプログラムに対して個々のサブディレクトリでグループ化するのが便利でしょう。こうする場合はそれらのサブディレクトリを作成するinstall
ルールを記述することになります。
ユーザーがサブディレクトリ名を上で挙げたどれか変数の値に含めてくれる事を期待してはいけません。インストールディレクトリについての変数名の組を同一にする、という発想はいくつかの異なるGNUパッケージに対して全く同じ値をユーザーに指定させられるようにするためにあるのです。これを便利にさせるには、すべてのパッケージで(ユーザーがちゃんとしてくれた場合に)分別を持った動作をするように設計しなければならないのです。
すべてのGNUプログラムではMakefileに以下のターゲットがあるべきです。
install-strip
ターゲットを使えばこれを行えます。
install
ターゲットルールは、できるなら`make all'が行われてる最中はプログラムがビルドされるディレクトリ内を全く修正しないように記述して下さい。こうするとプログラムをあるユーザーがビルドし、別のユーザーがインストールするという場合に便利だからです。
コマンドはファイルがインストールされるディレクトリがすでに存在するものではなかった場合、その全部を作成するようにすべきです。prefix
とexec_prefix
という変数の値で指定されたディレクトリもそうですし、必要なサブディレクトリ全部についてももちろんです。下で述べるようなinstalldirs
ターゲットに依るのもこうする一つの手段です。
UNIX manページドキュメントシステムがインストールされていないシステムが存在する場合の用心として、make
にエラーを無視させるようにするためにmanページをインストールするすべてのコマンドの前に`-'を使って下さい。
Infoファイルをインストールするには`$(infodir)'にInfoファイルを$(INSTALL_DATA)
(コマンド指定のための変数の項を参照)でコピーしてそれからinstall-info
プログラムがある場合それを実行します。install-info
とはInfo `dir'ファイルを編集して所定のInfoに対するメニューエントリーを追加したり更新したりするようにするプログラムのことで、Texinfoパッケージの一部として提供されています。次にInfoファイルを一つインストールするサンプルルールを示します。
$(infodir)/foo.info: foo.info $(POST_INSTALL) # scrdirにあるinfoファイルよりも新しいinfoファイルが"."にある事があります。 -if test -f foo.info; then d=.; \ else d=$(srcdir); fi; \ $(INSTALL_DATA) $$d/foo.info $@; \ # ある場合だけinstall-infoを実行する。 # 行の前に`-'をつけるのではなくて`if'をそのまま使うので # install-infoからのちゃんとしたエラーに気づきます。 # `$(SHELL) -c'を使うのは不明なコマンドがある場合に素直 # に失敗してくれないシェルがあるからです。 if $(SHELL) -c 'install-info --version' \ >/dev/null 2>&1; then \ install-info --dir-file=$(infodir)/dir \ $(infodir)/foo.info; \ else true; fi
install
ターゲットを記述する際はコマンド全部を次の三つ…普通のコマンド、前インストールコマンド、後インストールコマンドに分類しなければなりません。インストールコマンドのカテゴリーの項を見て下さい。
install
のようですが、インストール中は実行可能ファイルを度外視します。多くの場合、このターゲットはとても単純に定義できます。
install-strip: $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' \ install通常、ある実行可能プログラムにバグが全くないかどうか怪しい場合に実行可能ファイルを度外視するというのはお勧めしません。ですが、除外した実行可能ファイルを実際実行するためにインストールし、一方、除外しなかった実行可能ファイルにバグがあった場合をどこかよそに保持しておく事が理に適っている場合もあります。
distclean
で削除されるものを典型的に含んでいて、その上さらにBisonで作成されるCソースファイル、タグテーブル、Infoファイルなどがプラスされます
「ほとんどのもの」といったのは`make maintainer-clean'というコマンドの実行では、たとえ`configure'がMakefileのルールを用いて更新し得るものであったとしても`configure'を削除すべきではないという理由があったからです。より一般的には`make maintainer-clean'は`configure'の実行時やプログラムビルド時に存在している必要のあるものはどれも削除すべきではありません。
`maintainer-clean'ターゲットは、普通のユーザーではなくてパッケージのメンテナンスを行う人が利用するようにインストールされています。`make maintainer-clean'が削除するファイルのいくつかは再構築時に特別なツールが必要かもしれません。それらのファイルは通常配布物に含まれているため、それらの再構築を簡単にするさせるよう腐心する必要がありません。配布物の完全版の梱包を再び解く必要があるとわかった場合に私たちを責めないで下さい。
これをユーザーに気づかせる配慮をするには、特別なmaintainer-clean
ターゲットに対するコマンドは次の二つからはじめる必要があります。
@echo 'このコマンドはメンテナンス実行者用であり、リビルドに' @echo '特別なツールが必要なファイルでも削除します。'
info: foo.info foo.info: foo.texi chap1.texi chap2.texi $(MAKEINFO) $(srcdir)/foo.texiMakefileで
MAKEINFO
という変数を定義しなければなりません。これはmakeinfo
プログラムを実行すべきであり、Texinfobの配布物の一部です。
通常、GNUの配布物にはInfoファイルがついており、この事はInfoファイルがソースディレクトリにあることを意味します。だから、Infoファイルに対するmakeルールはソースディレクトリで更新するようにすべきです。ユーザーがパッケージをビルドした時は普通、はじめから更新されているものなのでMakeはInfoファイルを更新しません。
dvi: foo.dvi foo.dvi: foo.texi chap1.texi chap2.texi $(TEXI2DVI) $(srcdir)/foo.texiMakefileで
TEXI2DVI
という変数を定義しなければなりません。これはtexi2dvi
というプログラムを実行すべきもので、このプログラムはTexinfoの配布物の一部です。(3) ちゃんと依存関係を書くかGNU make
にコマンドを提供させる事を許可するかのどちらかになります。
ln
かcp
を使って適切なファイルをそのサブディレクトリ内にインストールし、それからサブディレクトリをtar
することです。
tarファイルをgzip
で圧縮してください。例えば、GCCバージョン1.40の実際の配布ファイルは`gcc-1.40.tar.gz'といいます。
dist
ターゲットは配布物にあるすべての非ソースファイルに明示的に依存させ、配布物にあるものは最新版だという事をはっきりさせる必要があります。
GNU Coding Standardsの`Making Releases'の項を見て下さい。
以下のターゲットは便利なプログラムに対して慣習的な名前として提案されているものです。
installcheck
installdirs
# すべてのインストールディレクトリ(例…$(bindir))が実際に存在するように、 # 必要ならディレクトリを作成します。 installdirs: mkinstalldirs $(srcdir)/mkinstalldirs $(bindir) $(datadir) \ $(libdir) $(infodir) \ $(mandir)このルールではコンパイルが行われるディレクトリは修正すべきではありません。 インストールディレクトリを作成するだけにすべきです。
install
ターゲットを記述する際はすべてのコマンドを三つのカテゴリに分類しなければなりません。すなわち、普通のコマンド、前インストールコマンド(pre-installation)、後インストールコマンド(post-installation)の三つです。
普通のコマンドは適切な場所にファイルを移動し、モードを設定します。従うパッケージのみに由来するファイル以外は全く変更を行いません。
前インストールと後インストールのコマンドは他のファイルを変更する事もでき、具体的にはグローバルコンフィギュレーションファイルやデータベースを編集する事ができます。
前インストールコマンドは典型的に通常のコマンドより前に実行され、後インストールコマンドは典型的に通常のコマンドの後に実行されます。
後インストールコマンドは、install-info
を実行するための利用がもっとも一般的です。これは、完全に、インストールするパッケージからのみによる(Infoディレクトリ)ファイルを変更するため通常のコマンドとは併用できません。パッケージのInfoファイルをインストールする通常のコマンドのあとにする必要があるため、後インストールコマンドになります。
ほとんどのプログラムでは前インストールコマンドを全く使う必要がありませんが、必要な場合があるのでこの機能を保持しています。
install
ルールのコマンドを三つのカテゴリに分類するにはカテゴリー行を間に挿入して下さい。カテゴリー行ではその次に続くコマンドのカテゴリーを指定します。
カテゴリ行はタブと、特別なMake変数への参照からなり、最後に自由にコメントをつけます。使える変数は3つあり、それぞれのカテゴリに対して1つ使い、変数名でカテゴリーを決めます。これら3つの変数は通常定義されていないので(それにmakefileでこれらを定義すべきではありませんが)、普通の実行ではカテゴリ行は全く実行されません。
次に3つの有効なカテゴリ行を示し、その意味をコメントで説明します。
$(PRE_INSTALL) # 前インストールコマンドが続きます。 $(POST_INSTALL) # 後インストールコマンドが続きます。 $(NORMAL_INSTALL) # 通常のコマンドが続きます。
install
ルールのはじめに一つのカテゴリ行を使わない場合、最初のカテゴリ行までの全コマンドが普通のコマンドとして分類されます。カテゴリ行を全く使わない場合は全コマンドが普通のコマンドとして分類されます。
uninstall
のためのカテゴリ行として次のものがあります。
$(PRE_UNINSTALL) # 前アンインストールコマンドが続きます。 $(POST_UNINSTALL) # 後アンインストールコマンドが続きます。 $(NORMAL_UNINSTALL) # 通常のコマンドが続きます。
典型的に前アンインストールコマンドはInfoディレクトリからのエントリーを削除するのに利用する事になります。
install
かuninstall
かのターゲットがインストール作業のサブルーチンとして動作する依存関係を持っている場合、それぞれの依存関係のコマンドをカテゴリ行からはじめるべきであり、メインターゲットのコマンドもカテゴリ行ではじめるべきです。こうすると、どの依存関係が実際に動作しているかを考えなくても各コマンドが正しいカテゴリにちゃんとなっているようにすることができます。
前インストールと後インストールのコマンドでは次のもの以外のプログラムを実行すべきではありません。
[ basename bash cat chgrp chmod chown cmp cp dd diff echo egrep expand expr false fgrep find getopt grep gunzip gzip hostname install install-info kill ldconfig ln ls md5sum mkdir mkfifo mknod mv printenv pwd rm rmdir sed sort tee test touch true uname xargs yes
こうやってコマンドを区別する理由はバイナリパッケージを作成するためです。典型的にバイナリパッケージは全部の実行可能ファイルやインストールに必要なその他のファイルを格納しており、それをインストールするための方法を独自に持っています——だから普通のインストールコマンドを実行する必要がないのです。ですが、バイナリパッケージのインストールには前インストールや後インストールのコマンドを実行する必要があります。
バイナリパッケージをビルドするプログラムは前インストールと後インストールのコマンドを抽出することで動作します。次に前インストールコマンドを抜き出す方法の一つを示します。
make -n install -o all \ PRE_INSTALL=pre-install \ POST_INSTALL=post-install \ NORMAL_INSTALL=normal-install \ | gawk -f pre-install.awk
上の`pre-install.awk'というファイルに次のものを格納する事ができます。
$0 ~ /^\t[ \t]*(normal_install|post_install)[ \t]*$/ {on = 0} on {print $0} $0 ~ /^\t[ \t]*pre_install[ \t]*$/ {on = 1}
前インストールコマンドの結果ファイルはバイナリパッケージインストール作業の一部としてシェルスクリプトとして実行されます。