GNU make


makeとは?

プログラムだけとは限りませんが、作業が複雑になるにつれ、 その分必要とする手間が増えます。 例えば、プログラムをコンパイルする環境が変われば、 コンパイラへ渡すオプションや参照するファイルの場所も変わります。 こう言った作業に伴う手間の縮小及び自動化を行うためのツールがmakeです。 makeは数多くのUNIX標準ツールとして用意されていますが、 今回は汎用性の高いGNU makeについて取り上げます。

GNUとは ?

Makefileコマンドの使い方

操作

キー

makeを実行する

make

代わりのファイルをMakefileとして使う

make -f Sample.mk

makeを実際実行せず、結果だけを提示する

make -n all


では、起動してみましょう。makeと打ち込んでみてください。ディレクトリ内にMakefileが無ければ、"Makefileがなく、何をmakeするべきか指定されていない"と表示されます。

$ make
gmake: *** No targets specified and no makefile found. Stop.
代わりにオプションとして-nを渡すと、実行されずに、その実行結果だけが表示されるはずです。
$ make -n
makeコマンドは何も引数を渡さなければ、Makefileというファイルの中のallというエントリ内のコマンドを実行しようとします。他のファイルをMakefileの代わりに読み込む場合は-fオプションで読み込むファイルを指定します。
$ make -f Sample.mk clean

Makefile の書き方

Makefile の中には、プログラムを作成する規則を書きます。規則は以下のように書きます。 コマンドの行は、行頭にタブ(Tab)が必要です。コマンドは1行ずつシェルへ渡されて実行されます。

ターゲット: 依存するファイル(複数あってよい)
(Tabの後) コマンド

依存するファイルがターゲットよりも新しければ、コマンド行は1行ずつシェルへ渡されて 実行されます。 もし、helloworld.c が hello.h というファイルをインクルードしているとすると、 Makefileは以下のようになります。

helloworld: helloworld.o
		    gcc -o helloworld helloworld.o

helloworld.o: helloworld.c hello.h
	        gcc -c helloworld.c

この Makefile には二つの規則が書かれています。まず、helloworldというファイルが helloworld.o に依存していることを示し、helloworld.o が変更されたならば( helloworld よりも変更された日付が新しいとき)、gccコマンドで helloworld を生成するというものです。
2つ目の規則は、helloworld.oが helloworld.c と hello.h に依存していて、いずれかが 変更されたときには gccコマンドで helloworld.o を生成するというものです。-c オプションは 拡張子が .o のオブジェクトファイルを生成することを意味します。

プログラムを変更した後は、単純に、
$ make 
と入力すると、最新の helloworld が生成されます。

Makefile 規則の詳細

変数

Makefile の中で変数を定義することができます。helloworld が helloworld.o と gutentag.o の2つのオブジェクトから生成されるのであれば、以下のような規則を書くことができます。
OBJECTS = helloworld.o gutentag.o
helloworld: $(OBJECTS)
		    gcc -o helloworld $(OBJECTS)
変数を使うと繰り返しを避けることができます。

暗黙の規則と変数

make には、暗黙の規則があります。暗黙の規則で定義される主たる変数を次に示します。
変数 意味 デフォルト
CC Cコンパイラ cc
CFLAGS Cコンパイラのフラグ
LDFLAGS リンカのフラグ
CXX C++コンパイラ g++
CXXFLAGS C++コンパイラのフラグ
CPP Cプリプロセッサ $(CC) -E
CPPFLAGS Cプリプロセッサのフラグ
もし、デバッグ用のバイナリファイルを作成するのであれば、CFLAGSに -g オプションを指定します。
$ make CFLAGS=0g helloworld
暗黙の規則と変数は、次のように -p オプションを使って表示 することができます。
$ make -p

別の例

別の例で、実際につかってみましょう。まず以下のソースコードをダウンロードしてみましょう。

helloworld_gtk.c
Makefile

このプログラムの中身は複雑になるので省きますが、前回書いたhelloworld.cというプログラムをポップアップ化したものです。コンパイルして実行すると画面に新しいウィンドウが現れ、「Hello World!」と表示されます。他に異なる点として、グラフィック関係の「ライブラリ」をリンクさせる必要があります。

ライブラリとはソフトウェアの一部を他ソフトウェアで再利用可能にするためのソフトウェアと言えます。この場合、0から新しくウィンドウを表示するためのグラフィックを書く手間を省くため、既存のグラフィックライブラリをこのプログラムへ含めます。また、ライブラリを利用することでソフトウェア間の互換性を保つこともできるため、今日のソフトウェアを開発する上では必要不可欠な要素であると言えます。

今回はgtkというグラフィックライブラリを使うことにします。 では、実際にどのように記述するかを説明します。

## コンパイラの指定
CC = gcc

## gccの最適化オプション
OPTIMIZE = -O2

## GLIB, GTKのバージョン
GDK_VER=1.2
GLIB_VER=1.2
GTK_VER=1.2

## コンパイラフラグ
CFLAGS = $(OPTIMIZE) -I. -I/usr/include/gtk-$(GTK_VER) -I/usr/include/glib-$(GLIB_VER) -I/usr/lib/glib/include

## コンパイルコマンド実行
## hello:hello.c の部分をプログラムのファイル名に合わせて変更
## 例: program.c ならば program:program.c に変更

all: helloworld_gtk

helloworld_gtk:helloworld_gtk.c
$(CC) $(CFLAGS) $@.c -o $@ -lgtk -lgdk -lglib

clean:
rm -f *.o
一つずつ細かく見ていきます。
## コンパイラの指定
CC = gcc

## gccの最適化オプション
OPTIMIZE = -O2

## GLIB, GTKのバージョン
GDK_VER=1.2
GLIB_VER=1.2
GTK_VER=1.2
## コンパイラフラグ CFLAGS = $(OPTIMIZE) -I. -I/usr/include/gtk-$(GTK_VER) -I/usr/include/glib-$(GLIB_VER) -I/usr/lib/glib/include

makeでは独自の変数を宣言することができます。これにより、変数の値を状況に応じて変更することができます。この例ですと、CコンパイラとしてGNU ccを使い、最適化するように宣言を行います。また、グラフィックライブラリはバージョン1.2系列のものを使うようにしてしています。最後に、Cコンパイラ自身へのオプションとして、先程挙げた最適化を行い、さらに各種設定パラメータを含んだヘッダファイルを含めた検索すべきディレクトリを指定しています。

## コンパイルコマンド実行

all: helloworld_gtk

helloworld_gtk:helloworld_gtk.c
	$(CC) $(CFLAGS) $@.c -o $@ -lgtk -lgdk -lglib

次に、コマンドの宣言を行います。makeはデフォルトでallというカテゴリで宣言されたコマンドを実行します。通常はmakeする場合は複数のプログラムを同時にコンパイルしますが、今回は一つだけですので「helloworld_gtk」と宣言します。

そのあとに、helloworld_gtkの中身を記述します。 コンパイラは上で宣言したCCとそのオプションを宣言し、ファイル名はこのカテゴリの名前、即ち「helloworld_gtk」.cを加えたものとなります。-oオプションはコンパイル後の実行ファイル名、この場合は「helloworld_gtk」と言う名前で生成します。最後に、リンクするべきライブラリを宣言します。今回はgtk, gdk, glibの三つを使います。

さて、実際makeしてみましょう。helloworld_gtk.cとMakefileのあるディレクトリでmakeを実行してみましょう。

$ make

helloworld_gtkという実行ファイルが生成されたはずです。最後に、これを実行してみましょう。

$ ./helloworld_gtk