GNU make って便利だなって話
Lab の課題で Unix の Makefile について学習するという課題が出たので GNU make についてまとめていこうと思います。
make とは
プログラムのビルド作業を自動化するツール。コンパイル、リンク、インストール等のルールを記述したテキストファイル(makefile)に従って、これらの作業を自動的に行う。
Wikipediaより
自分のイメージとしてはコンパイルやクリーンなどを自動化できるツールというようなイメージです。
make の仕方
Makefile というテキストファイルに作業内容を記述します。
具体例と共に触れて行きましょう。
以下のような構成のディレクトリ foo があったとします。
foo$ ls
main.c
bar.c bar.h
foobar.c foobar.h
main.c は bar.c と foobar.c から構成されていて、
bar.c は bar.h に、foobar.c は foobar.h に依存しています。
はじめに Makefile を作成します。
foo$ touch Makefile
作成した Makefile を適当なエディタで開きます。
とりあえず以下の内容を書き込みます。
この時、インデントは tab でおこなってください。
CC = gcc TARGET = main OBJS = bar.o foobar.o all: $(OBJS) $(CC) main.c -o $(TARGET) $(OBJS) .c.o: $(CC) -c $< bar.o: bar.h foobar.o: foobar.h
Makefile の解説
1 ~ 3 行目では変数宣言を行っています。
1 行目では CC という変数に gcc を代入しています。
2 行目で 変数 TARGET に生成される実行ファイルの名前を代入しています。
3 行目では 変数 OBJS に実行ファイル作成時に使用するオブジェクトファイルの名前を代入しています。
5 行目では all は慣用名で、 $(OBJS) に含まれる全てのターゲットを構築します。
実際に make と打った際に実行されるのがこのブロックです。
6 行目には具体的な処理を書いており、以下の実行結果の 4 行目に表されるプログラムが実行されています。
8, 9 行目では オブジェクトファイル ( .o ファイル) は必ず .c ファイルから生成されるというルールがあることを利用して、.o ファイルが必要になった際に .c ファイルから .o ファイルを自動で生成しています。
11, 12 行目では .o ファイルが依存している .h ファイルを宣言しています。
実行結果
foo$ make gcc -c bar.c gcc -c foobar.c gcc main.c -o main bar.o foobar.o foo$ ls Makefile main.c main bar.c foobar.c bar.h foobar.h bar.o foobar.o foo$ ./main ・・・ ・・・
実行ファイルや .o ファイルが生成されていることが確認できると思います。
make clean をしよう
make には ターゲットと呼ばれるものを追加することで様々なプログラムを以下のように実行することができます。
make $(target)
ターゲットには前述の all の他に clean や install などがあります。
all は特別で、下のどちらで打っても同じ結果になります。
make make all
clean について少し触れていきましょう
make clean ですること
clean は基本的に make 時に作った不要なファイルなど (例えば .o ファイルなど) を削除するためのものです。
以下のように新しくターゲットを追加することができます。
ここで TARGET や OBJS は前述の Makefile で定義したものと同じです。
clean: rm -rf $(TARGET) rm -rf $(OBJS)
これは以下のように実行できます。
foo$ make clean rm -rf main rm -rf bar.o foobar.o
make pkg をしよう
今度は ディレクトリをパッケージ化してみましょう。
ターゲット名は pkg とし、ファイルを tar.gz 形式で圧縮します。
方針
はじめにディレクトリを作ります。 (ディレクトリ名はなんでも良いです。)
そのディレクトリにソースファイルを全てコピーします。
そのディレクトリを tar.gz 形式で圧縮します。
その後作成したディレクトリを削除します。
これを Makefile に書くと以下のようになります。
FILE = Makefile main.c bar.c bar.h foobar.c foobar.h DIR = test pkg: if [ -d $(DIR) ]; then rm -rf $(DIR); fi mkdir $(DIR) cp $(FILE) ./$(DIR) tar zcvf $(DIR).tar.gz $(DIR) rm -rf $(DIR)
1, 2 行目は変数宣言を行なっています。
5 行目では test という名前のディレクトリが存在していた場合にそのディレクトリを削除しています。
6 行目で test ディレクトリを作成し、
7 行目で FILE に宣言されたファイルを作成した test ディレクトリにコピーしています。
8 行目で test ディレクトリを圧縮し、tar ファイルを生成します。
9 行目では不要になった test ディレクトリを削除しています。
実行結果
foo$ make pkg if [ -d test ]; then rm -rf test; fi mkdir test cp main.c Makefile bar.c bar.h foobar.c foobar.h ./makelab1 tar zcvf test.tar.gz test a test a test/bar.h a test/foobar.h a test/main.c a test/Makefile a test/bar.c a test/foobar.c rm -rf test foo$ ls Makefile main.c bar.c bar.h foobar.c foobar.h test.tar.gz foo$ tar -zxvf test.tar.gz x test/ x test/bar.h x test/foobar.h x test/main.c x test/Makefile x test/bar.c x test/foobar.c foo$ ls Makefile main.c bar.c bar.h foobar.c foobar.h test
tar ファイルが生成されていること、解凍すると test ディレクトリが生成されていることが確認できると思います。
終わり
gnu make について解説をしてきました。
gnu make は使いこなせるようになると非常に便利です。
ぜひ使ってみてください。