2009年06月14日(日) [長年日記]
- マウス左手継続中。まだ慣れない。
■ [c++][c][dev] C++用Makefileのサンプル
GNU makeは奥が深すぎて嫌になるな。今日考えた、C++のプログラムをビルドするためのGNU make用のMakefileをメモ。Cでも同様のはず。おかしな所があったら教えてください。
ソースファイルとMakefileの構成は次のようになっているとする。Makefileは1つだけ。
. |-- Makefile `-- src |-- aaa | |-- a.cpp | |-- a.h | `-- ccc | |-- c.cpp | `-- c.h |-- bbb | |-- b.cpp | `-- b.h `-- main.cpp
これを make すると次のようになる。build ディレクトリが作られそこに *.o と *.d と実行ファイルsampleが作られる。
. |-- Makefile |-- build | |-- sample | `-- src | |-- aaa | | |-- a.o | | |-- a.o.d | | `-- ccc | | |-- c.o | | `-- c.o.d | |-- bbb | | |-- b.o | | `-- b.o.d | |-- main.o | `-- main.o.d `-- src | (src以下は変わらないので省略)
次にメモとMakefileを示す。
- *.dはヘッダファイルも考慮した依存関係を記述したファイル。GNU makeのマニュアルに説明がある。そこに書いてあるよりもシンプルな処理にしたけど。
- ビルド対象とするディレクトリをMakefileに列挙する必要がある。ここを自動化することもできると思うけど、列挙する方が便利なこともある。
- ソースファイルは自動で見つける。拡張子が cpp のファイルは全てビルド対象とみなす。
- ターゲットは all と clean しか作ってない。
# GNU make 用です build_base_dir = build program = $(build_base_dir)/sample # ここにビルド対象とするディレクトリを全て書く src_dirs = src src_dirs += src/aaa src_dirs += src/aaa/ccc src_dirs += src/bbb CPPFLAGS = -I src CXXFLAGS = -Wall -g sources = $(wildcard $(addsuffix /*.cpp, $(src_dirs))) objects = $(sources:%.cpp=$(build_base_dir)/%.o) depends = $(addsuffix .d, $(objects)) build_dirs = $(addprefix $(build_base_dir)/, $(src_dirs)) .PHONY: all all: $(build_dirs) $(program) .PHONY: clean clean: rm -rf $(build_base_dir) $(program): $(objects) $(CXX) $(LDFLAGS) -o $@ $^ $(build_base_dir)/%.o: %.cpp $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $< $(CXX) $(CPPFLAGS) -MM $< \ | sed 's|^\([^\.]*\)\.o|$(@D)/\1\.o|' > $@.d $(build_dirs): mkdir -p $@ -include $(depends)
実行すると手元の環境では次のように表示された。
$ make --version GNU Make 3.81 Copyright (C) 2006 Free Software Foundation, Inc. これはフリーソフトウェアです. 利用許諾についてはソースを ご覧ください. 商業性や特定の目的への適合性の如何に関わらず, 無保証です. This program built for i486-pc-linux-gnu $ make mkdir -p build/src mkdir -p build/src/aaa mkdir -p build/src/aaa/ccc mkdir -p build/src/bbb g++ -I src -Wall -g -c -o build/src/main.o src/main.cpp g++ -I src -MM src/main.cpp \ | sed 's|^\([^\.]*\)\.o|build/src/\1\.o|' > build/src/main.o.d g++ -I src -Wall -g -c -o build/src/aaa/a.o src/aaa/a.cpp g++ -I src -MM src/aaa/a.cpp \ | sed 's|^\([^\.]*\)\.o|build/src/aaa/\1\.o|' > build/src/aaa/a.o.d g++ -I src -Wall -g -c -o build/src/aaa/ccc/c.o src/aaa/ccc/c.cpp g++ -I src -MM src/aaa/ccc/c.cpp \ | sed 's|^\([^\.]*\)\.o|build/src/aaa/ccc/\1\.o|' > build/src/aaa/ccc/c.o.d g++ -I src -Wall -g -c -o build/src/bbb/b.o src/bbb/b.cpp g++ -I src -MM src/bbb/b.cpp \ | sed 's|^\([^\.]*\)\.o|build/src/bbb/\1\.o|' > build/src/bbb/b.o.d g++ -o build/sample build/src/main.o build/src/aaa/a.o build/src/aaa/ccc/c.o build/src/bbb/b.o
■ [dev] GNU makeの参考資料
オライリーの GNU Make 第3版 が一番参考になると思うけど、持ってない。立ち読みはした。
ウェブ上のリソースをメモ。
- GNU `make' (GNU)
- 本家にあるマニュアル。
- GNU make 日本語訳(Coop編) (ecoop.net)
- 上のマニュアルの日本語訳。とても役に立つが少し古い。
- GNU Make の使い方 (みねこあ)
- オライリー本にあるテクニックが紹介されていたので参考にした。結局あまり難しいことはしなかったけれど。