Welcome to my web page. This page is written in Japanese.
Code is EUC-JP.

Makefile を用意

Makefile とは

たいていのソフトウェアは、コンパイルおよびインストールに make を使用しています。このコマンドはほとんどの UNIX 系システムに標準で用意されていますし、様々な拡張などをされている GNU make もあります。
コマンド make を実行するためには Makefile が必要になります。Makefile とは、コマンド make に対して、コンパイルをするために必要な依存関係などのルールや実際に実行するプログラムやスクリプトなどを記述しているファイルのことです。
ソフトウェアによっては "Makefile" がソースファイルのアーカイブに含まれている場合もあります。なかには "makefile" という名前になっている場合もありますし、システム毎の suffix を付けた Makefile を用意しているものもあります。
例えば libpng では以下のような Makefile 達が用意されています。
  makefile.aco  makefile.dec  makefile.lnx  makefile.s2x  makefile.sun
  makefile.ama  makefile.dj2  makefile.mip  makefile.sco  makefile.tc3
  makefile.atr  makefile.hux  makefile.msc  makefile.sgi  makefile.w32
  makefile.bor  makefile.knr  makefile.os2  makefile.std  makefile.wat
この場合、もしインストールするシステムが DEC Alpha であれば "makefile.dec" を使用することになりますし、Solaris 2.x であれば "makefile.s2x を使用することになります。
実際に make を実行する前には、この Makefile の内容を自分の環境に合うように修正しなければいけません。
よく行なわれる修正は、ヘッダファイルやライブラリのディレクトリの指定などです。例えば libpng の各 Makefile は、その中に以下のような記述があります。
# Where the zlib library and include files are located
#ZLIBLIB=/usr/local/lib
#ZLIBINC=/usr/local/include
ZLIBLIB=../zlib
ZLIBINC=../zlib
libpng をコンパイルするには事前に zlib をインストールしておかなければいけないのですが、そのインストールした zlib のヘッダファイルとライブラリのディレクトリをここで指定する必要があります。
例えば zlib のヘッダファイルは /usr/local/include へ、そしてライブラリは /usr/local/lib へインストールした場合は、上記の内容を以下のように修正することになります。
# Where the zlib library and include files are located
ZLIBLIB=/usr/local/lib
ZLIBINC=/usr/local/include
#ZLIBLIB=../zlib
#ZLIBINC=../zlib
説明が後になりましが、Makefile 内の "#" は、そこから行末までをコメントとみなします。つまり "#" からその行末までの記述はコマンド make の実行に影響を与えません。
Makefile の書き方についての簡単な解説は後述します。
最近はこのようにユーザーが Makefile の修正をせずに済むような工夫がされているソフトウェアがあります。それらのソフトウェアでは Makefile を用意する代りに、Imakefile や configure が用意されています。
その場合ユーザーは、xmkmf や用意された configure を実行することによって自分の環境に適した Makefile を作成することができます。

Imakefile とは

Imakefile とは、コマンド xmkmf や imake を実行して Makefile を作成する際のテンプレートファイルです。基本的に xmkmf や imake は、使用しているシステムの X Window System に対して適切な Makefile を作成するために使用されますので、最近の X 上で動くソフトウェアではたいてい Imakefile が用意されているようです。
通常 xmkmf とは、その中で imake を実行する、短いシェルスクリプトになっています。これにより、通常ユーザーが imake を直接実行する必要はほとんどなく、たいていは xmkmf を実行することで Makefile を作成することができます。
コマンド xmkmf の使い方は簡単です。たんに Makefile を作成するためだけであれば、以下のようにとくにオプションも与えずに xmkmf を実行することで作成されます。
$ xmkmf
ソフトウェアによってはオプション "-a" を付けて実行したほうが適切な場合があります。
$ xmkmf -a
これば以下を実行することと同じ働きをします。
$ xmkmf 
$ make Makefiles
$ make includes
$ make depend
たいていのソフトウェアは Imakefile を修正することなく xmkmf で Makefile を作成し、コンパイルすることができます。ときには Imakefile を自分で修正する場合もありますが、それはたいてい付加機能を付けたいなどの場合です。

configure の使い方

configure とは、コンパイルに必要なヘッダファイルやライブラリ、そしてシステムコールや関数が存在しているかなどを自動的に調べ、それらの情報をもとにおよそ適切な Makefile を作成するプログラムです。
通常 configure はシェルスクリプトで用意されています。
現在この configure を採用しているソフトウェアは非常に多く存在します。これは GNU の autoconf を使用することで簡単に configure を作成することができ、しかも実際に Makefile を作成するために、それが非常に有効な手段であるからです。当然ながら GNU の配布形態を採用しているソフトウェアはたいていこの configure を使用して Makefile を作成できます。
この configure は、ほとんどの場合以下のように実行するだけでユーザーのシステムに適した Makefile を作成します。
$ ./configure
しかし完全に自動で行なうのは無理な場合もあり、ソフトウェアによってはオプションを指定する必要があります。例えば lynx の構築に ncurses の使用を指定する場合はオプション "--with-screen=ncurses" を与えますし、GTK+ を日本語が使用できるように構築するため、locale として ja_JP.ujis を指定するには、オプション "--with-locale=ja_JP.ujis" を与えて configure を実行します。
configure が持つオプションを調べるためには、たいていオプション "--help" を与えて実行することで調べられます。
$ ./configure --help
ここで出力される内容を見れば、だいたい理解できると思いますが、よく使う代表的なものをいくつか挙げておきます。
--prefix
インストール先を指定します。 たいていの場合は、デフォルトは /usr/local です。
--bindir
実行ファイルのインストール先を指定します。 デフォルトは $(prefix)/bin です。
--libdir
ライブラリのインストール先を指定します。 デフォルトは $(prefix)/lib です。
--includedir
ヘッダファイルのインストール先を指定します。 デフォルトは $(prefix)/include です。
--program-prefix
プログラム名の頭に付ける名前を指定します。
"--prefix" は、例えばそのサイトでは、/opt/local/ 以下にソフトウェアをインストールするように決めているなどという場合に使用します。もしくは Linux の Slackware を使用していて、古いコマンドと入れ換えたい場合などに /usr を指定する場合もあります。
"--program-prefix" は、例えば GNU tar をインストールするとき、gtar という名前にしたい場合に "--program-prefix=g" と指定します。
例として、GNU tar を /opt/local 以下に gtar という名前でインストールしたい場合は以下のように configure を実行します。
$ ./configure --prefix=/opt/local --program-prefix=g
コンパイルオプションを指定したい場合は、環境変数を使って configure に指示します。例えば C のソースファイルをコンパイルする際の C コンパイラへのオプションは "CFLAGS" に、オブジェクトファイルをリンクする際のオプションは "LDFLAGS" にそれぞれ値を設定して configure を実行します。例として "CFLAGS""-O2 -Wall" を、そして "LDFLAGS""-s" を設定したい場合は以下のように実行します。
$ env CFLAGS='-O2 -Wall' LDFLAGS=-s ./configure
ただし、稀にこの設定が有効にならないソフトウェアがあります。その問題はたいてい configure よりも、Makefile の雛形である Makefile.in にあります。そのような場合は Makefile.in を修正してから configure を実行するか、configure を実行したあとで作成された Makefile を修正するか、もしくは make の実行時にオプションとして指定するなどの手段をとる必要があります。
ソフトウェアによっては、GNU autoconf で生成される configure とは違う独自のシェルスクリプトを用意して Makefile を作成するものもあります。例えば perl や mnews です。
perl では Configure という名前でシェルスクリプトが用意されており、ある程度は自動的に調べますが、必要に応じてユーザーに質問をしてきます。一方 mnews では config.sh と config.jsh という名前でシェルスクリプトが用意されています。前者が英語版で後者が日本語版です。このシェルスクリプトもユーザーにいくつかの質問をし、その答えにもとづいて適切な Makefile を作成します。
なお、GNU の configure にしろ、独自に用意されているシェルスクリプトであるにしろ、それらを実行する際には必ず "./" とパスを指定して実行するようにしてください。上記の実行例でも "./configure" としています。シェルは環境変数 PATH の内容にそってコマンドを探します。通常はカレントディレクトリである "." は PATH に含めませんし、場合によってはカレントディレクトリ以外のディレクトリに同名のコマンドが存在していて、それを起動してしまうことがあるかもしれないからです。余計な面倒に悩まされないためにも、カレントディレクトリに存在するコマンドを実行する場合は、必ず "./コマンド名" とパスを指定して実行する癖を付けておいたほうがよいでしょう。

基本的な構文規則

imake や xmkmf もしくは configure で作成された Makefile ならばともかく、作者が用意してくれた Makefile などの場合、その内容を読んで自分のシステムに適切な設定、もしくは修正をしなければいけない場合があります。そのようなときは、Makefile の極々基本的な構文規則は知っておく必要があります。
Makefile の構文規則はある意味非常にデリケートなところがあります。例えばタブで記述しなければいけない箇所にスペースを使用してしまったり、もしくはその逆のことをしてしまうと、それだけで make はエラーメッセージを表示して終了してしまいます。
そのため Makefile の書き方は難しいと考えている人もいるかもしれません。
ちょっとした Makefile ならば読めて何をしているのか判るように、そして簡単な設定、もしくは修正ならばできるように、ここでは極々基本的な構文規則を解説します。
まず、以下に極簡単な Makefile の内容を挙げます。この例での行番号は解説の便宜のために付けているもので、実際の Makefile には無いことに注意してください。
     1  # CC = cc
     2  # CFLAGS = -g
     3  # LDFLAGS = -g
     4
     5  CC = gcc
     6  CFLAGS = -O2 -Wall
     7  LDFLAGS = -s
     8
     9  SRCS = main.c opt.c
    10  OBJS = main.o opt.o
    11
    12  TARGET = a.out
    13
    14  $(TARGET): $(OBJS)
    15          $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
    16
    17  main.o: main.c
    18          $(CC) $(CFLAGS) -c $? -o $@
    19
    20  opt.o: opt.c
    21          $(CC) $(CFLAGS) -c $? -o $@
まず、前述もしましたが Makefile 内の "#" は、コメントの開始を意味する文字として使われていますので、そこから行末までをコメントとみなされて無視されます。したがってこの Makefile の 1 行目から 3 行目は、コマンド make の実行に影響を与えません。
次に 5 行目から 7 行目まで、そして 9 行目、10 行目、および 12 行目はマクロの定義を行なっています。つまり 5 行目はマクロ "CC""gcc" を、そして 6 行目は "CFLAGS""-O2 -Wall" を定義しています。もちろんその他の 7 行目、9 行目、10 行目、そして 12 行目も同様です。
Makefile の記述は行末にバックスラッシュ("\")を記述することで次の行へ継続させることができます。したがって、例えば 9 行目と 10 行目は以下のように複数行で記述することもできます。
        SRCS = main.c \
               opt.c
        OBJS = main.o \
               opt.o
これらの、マクロに定義された値は以降 "$(マクロ名)" もしくは "${マクロ名}" として参照することができます。これにより、例えば 14 行目の "$(TARGET)""a.out" で置き換えられ、同様に "$(OBJS)""main.o opt.o" で置き換えられることになります。つまり 14 行目は以下のように記述されていることと同じことになります。
        a.out: main.o opt.o
これらのマクロの参照は、必ず括弧でくくられている必要があります。マクロは "$PATH""$HOME" といった環境変数に似ているように見えるかもしれませんが同じではありませんので注意してください。なお例外としてマクロ名が一文字であるならば括弧でくくらずに参照することができます。
マクロは、別のマクロを使って定義することも可能です。例えば以下のように記述することも可能です。
        prefix = /usr/local
        bindir = $(prefix)/bin
        libdir = $(prefix)/lib
この場合の "$(bindir)" は /usr/local/bin になり、同様に "$(libdir)" は /usr/local/lib になります。
ソースファイルが少数であるならばよいのですが、その数が多くなりますとそれぞれを全て "SRCS" に記述し、かつそれらの suffix である ".c"".o" に変更しただけのものを "OBJS" に記述するのは非常に面倒であり、ときには間違いのもとにもなります。このような苦労を軽減するためにマクロには文字列置換の機能があります。
この文字列置換を使うと、例えば 10 行目は以下のように記述することができます。
        OBJS = $(SRCS:.c=.o)
この "$(SRCS:.c=.o)" は結果的に suffix の置き換えが行なわれます。つまりマクロ "$(SRCS)" で評価され、それぞれのファイル名の ".c"".o" に置き換えらます。そしてその置き換えられた値が "OBJS" に定義されます。したがってこの記述はもとの 10 行目と同じ値がマクロ "OBJS" に定義されることになります。
この文字列置換は、GNU make をはじめ、現在ではほとんどの UNIX システムに標準に用意されている make で使えると思いますが、BSD 系列のシステムの中には使えない場合もありますので注意してください。
14 行目以下はターゲットエントリです。上記の例では三つのエントリがあります。そして各エントリには、ターゲット、依存ファイル、およびターゲットを作成する方法であるコマンド行によって構成されています。
例えば 14 行目は、"$(TARGET)" つまり "a.out""$(OBJS)" つまり "main.o opt.o" の二つのファイルに依存していることを示します。そしてこの二つの依存ファイルに対してターゲットである "a.out" が最新でない場合、最新状態への更新のためにコマンド行である 15 行目が実行されることになります。
これは 17 行目と 18 行目、そして 20 行目と 21 行目のターゲットエントリも同様です。
なお、コマンド行は必ずタブで始まっていなければいけません。つまり第一カラムは必ずタブでありスペースを記述してはいけないことに注意してください。通常のエディタではタブとスペースの違いが視認しにくいためか、ここをスペースで始めてしまうことは初心者などによく見られる間違いです。逆に他の箇所、つまりコマンド行以外ではタブで始めることは間違いです。GNU make はある程度許してくれますが、UNIX システムに標準に用意されているコマンド make はこれを許してくれないものも実在します。これもまた初心者などによく見られる間違いですので気を付けてください。
少々話がずれますが、以下のように実行することで Makefile 内のタブと行末をチェックすることができます。
$ cat -vte Makefile
もちろん出力が長い場合はページャー (more や less など) を使用して見るようにしてください。
コマンド cat のオプション "-v" はタブ、ニューライン、および改ページなどを除く非プリント文字を表示します。オプション "-t" はタブを "^I" として表示します。オプション "-e" は行末を識別できるように "$" を表示します。
タブと行末だけを知りたい場合はオプション "-t""-e" だけでもよい環境もありますが、システムによっては "-v" も付けないと "-t""-e" を黙って無視する場合がありますので、"-v" も付けるように憶えておいたほうがいいでしょう。
話をもとに戻しますが、実はコマンド行を独立した行で書く必要はありません。セミコロン(";")で分けて一行で記述することができます。例えば 14 行目と 15 行目は、以下のようになります。
        $(TARGET): $(OBJS) ; $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
これは、コマンド行がタブで始まらなければいけないという規則の唯一の例外です。しかしこのような記述は通常されていません。少なくとも著者は、修正しなければいけないとされる Makefile において、このような記述がされていることを見たことはありません。
コマンド行にある "$@""$?" は組み込みマクロ、もしくは動的マクロと呼ばれるものです。まず "$@" は現在のターゲット名になりますし、"$?" は現在のターゲットにたいする依存ファイルになります。
したがって、もし 14 行目から 21 行目を一切マクロを使わずに記述すると以下のようになります。
    14  a.out: main.o opt.o
    15          gcc -O2 -Wall -s -o a.out main.o opt.o
    16
    17  main.o: main.c
    18          gcc -O2 -Wall -c main.c -o main.o
    19
    20  opt.o: opt.c
    21          gcc -O2 -Wall -c opt.c -o opt.o
上記の例ではコマンド行は全て一行で済んでいますが、複数の行を記述することもできます。
        clean:
                rm -f $(TARGET)
                rm -f $(OBJS)
この記述を Makefile に追加しますと、"make clean" として make を実行することにより、"rm -f a.out""rm -f main.o opt.o" が実行されることになります。しかしこの場合気を付けなければいけないことは、各行は別々のプロセスで実行されるということです。
以下の記述が Makefile にあるとします。
        clean:
                cd src
                rm -f *.o
これは、おそらく期待通りに動作はしないでしょう。このような場合はセミコロン(";")を使って一行で記述をし、一つのプロセスで実行されるようにする必要があります。例えば以下のように記述することになります。
        clean:
                cd src ; rm -f *.o
なお、コマンド行もまた、行末にバックスラッシュ("\")を記述することで次の行へ継続させることができますので、以下のようにも記述できます。
        clean:
                cd src ; \
                rm -f *.o
この方法はサブディレクトリを持っているソフトウェアでよく利用されます。例えば以下のような記述です。
        all:
                for i in $(SUBDIRS) ; do \
                  ( cd $$i && $(MAKE) ) \
                done
これは、マクロ "SUBDIRS" に定義された各サブディレクトリで make を実行するためのコマンド行です。
コマンド行内では、シェル変数には "$" を二つ付けていることに注意してください。一つの "$" はマクロを表わしますので意味が異なります。"$" を二つ記述することで、そのうちの一つをコマンド make が取り除いてシェルに渡されます。