Makefile: build all ".c"
数行の小さいテストプログラムのためいちいちビルドするのが面倒だなと・・
カレントディレクトリの全てのソースファイルを一気にビルドできればなと・・
ネットで調べながら試行錯誤の結果・・・
source(Makefile)
# Makefile # build all ".c" file in current directory CC=gcc SRCS=$(wildcard *.c) OBJS=$(patsubst %.c,%.o,$(SRCS)); all: $(OBJS) for i in $(OBJS) \ do \ EXE=`basename $$i .o`; \ $(CC) -o $$EXE $$i; \ done .c.o: $(CC) -c $< clean: rm -f $(OBJS)
できた.動作確認.
sample execution
% ls Makefile a.c b.c c.c % make gcc -c a.c gcc -c b.c gcc -c c.c for i in a.o b.o c.o; \ do \ EXE=`basename $i .o`; \ gcc -o $EXE $i; \ done % ls -l total 92K -rw-r--r-- 1 aki 256 Oct 12 03:56 Makefile -rwxr-xr-x 1 aki 4713 Oct 13 00:46 a -rw-r--r-- 1 aki 85 Oct 12 03:48 a.c -rw-r--r-- 1 aki 860 Oct 13 00:46 a.o -rwxr-xr-x 1 aki 4713 Oct 13 00:46 b -rw-r--r-- 1 aki 85 Oct 12 02:19 b.c -rw-r--r-- 1 aki 860 Oct 13 00:46 b.o -rwxr-xr-x 1 aki 4713 Oct 13 00:46 c -rw-r--r-- 1 aki 85 Oct 12 02:20 c.c -rw-r--r-- 1 aki 860 Oct 13 00:46 c.o
完璧.が,もう少しクールなMakefileがあるかも.
今回はこれで満足
Makefile
Makefile概要
Cなどでプログラムを作るとき1つのファイルで処理が終わってしまうような簡単なプログラムなら,
% ls source.c % gcc source.c % ls a.out source.c
のようにそのソースをコンパイル&リンクして実行ファイルを得れば良いが,数10,数100のファイルなどからなる大きなプログラムになると
% ls 死ぬほど多いソースファイル % gcc 死ぬほど多いソースファイル
などとやっていては1回の実行なら良いが,バグが見つかり1つのファイルのみを修正してコンパイル&リンクをしようとしたとき,再び全てのファイルについてコンパイル&リンクをしなくてはならず時間効率が悪い.そこでMakefileとmakeコマンドを用いると,修正したファイルのみをコンパイルし,リンクを行うということが可能である.コンパイルの時間が短縮できるとともにコマンドをいちいち打つ必要がないため手間も省け,効率的である.
まずは基本
同じディレクトリ内に以下のような3つのファイルがある.(Makefile, hello.c, helloworld.c)
このうちプログラムのソースはhello.cとhelloworld.cこの2つのファイルをMakefileとmakeコマンドを使ってコンパイル,リンクする.
source(Makefile)
# Makefile helloworld: helloworld.o hello.o gcc -o helloworld helloworld.o hello.o helloworld.o: helloworld.c gcc -c helloworld.c hello.o: hello.c gcc -c hello.c clean: rm -f helloworld.o hello.o
source(hello.c)
#include <stdio.h> void hello(void) { printf("hello world\n"); }
source(helloworld.c)
#include <stdio.h> int main(int argc,char *argv[]) { void hello(void); hello(); return 0; }
ここで以下のようにコマンドを打つ
% ls Makefile hello.c helloworld.c % make gcc -c helloworld.c gcc -c hello.c gcc -o helloworld helloworld.o hello.o % ls Makefile hello.c hello.o helloworld helloworld.c helloworld.o % ./helloworld hello world
makeコマンドを実行すると
gcc -c helloworld.c gcc -c hello.c gcc -o helloworld helloworld.o hello.o
の3コマンドが実行されていることがわかる.まず,上2つでコンパイルを行い,オブジェクトファイルを作成,その後リンクしhelloworldという実行ファイルを生成する.
この状態でもう一度makeする.
% make make: `helloworld' は更新済みです
既にhelloworldは最新版でありコンパイル&リンクは必要ないので何も実行されない.
次にMakefileの最後の2行
clean: rm -f helloworld.o hello.o
これはmakeコマンドの引数に指定すると,指定されたコマンドを実行すると言う意味である.
この場合
rm -f helloworld.o hello.o
が実行され,helloworld.oとhello.oというリンクに使われたオブジェクトファイルが2つ削除される.
% ls Makefile hello.c hello.o helloworld helloworld.c helloworld.o % make clean rm -f helloworld.o hello.o % ls Makefile hello.c helloworld helloworld.c %
マクロ,サフィックスルール
Makefileを以下のように修正する.helloworld.cとhello.cは使いまわしする.
source(Makefile)
# Makefile CC=gcc OBJS=helloworld.o hello.o helloworld: helloworld.o hello.o $(CC) -o $@ $(OBJS) .c.o: gcc -c $< clean: rm -f $(OBJS)
3,4行名
CC=gcc OBJS=helloworld.o hello.o
は代入文でCCにgccを,OBJSにhelloworld.o hello.oを代入することを表す.
代入された変数を参照するには$(変数名)のようにする.
この場合,7行目
$(CC) -o $@ $(OBJS)
の$(CC)はgccに,$(OBJS)はhelloworld.o hello.oに置き換えられる.
同じく7行目$@は現在のターゲットのフルネームを取得する.ここではhelloworldに置き換えられる.つまり7行目
$(CC) -o $@ $(OBJS)
は,
gcc -o helloworld helloworld.o hello.o
に置き換えられる.
次に9,10行目
.c.o: gcc -c $<
は,.cのファイルを.oファイルに変換するということを表す.
$<はターゲットに依存している単一のファイルをに置き換えられる.この場合,hello.oが依存されているときは,
gcc -c hello.c
に置き換えられ,helloworld.oが依存されているときは,
gcc -c helloworld.c
に置き換えられる.以上を踏まえてmakeコマンドを実行する.
% rm helloworld % ls Makefile hello.c helloworld.c % make gcc -c helloworld.c gcc -c hello.c gcc -o helloworld helloworld.o hello.o % ls Makefile hello.c hello.o helloworld helloworld.c helloworld.o % ./helloworld hello world % make clean rm -f helloworld.o hello.o % ls Makefile hello.c helloworld helloworld.c %
上記のmakeコマンドと同じ結果を得られた.
このようにマクロ,サフィックスルールを用いることによりMakefileの汎用性を高めることができる.
Makefileについてはこれくらい知っておけば大体大丈夫だと思う.