メモの日々


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(Mecklenburg,Robert/著 Mecklenburg,RobertWilliam/著 ほか) オライリーの GNU Make 第3版 が一番参考になると思うけど、持ってない。立ち読みはした。

ウェブ上のリソースをメモ。

GNU `make' (GNU)
本家にあるマニュアル。
GNU make 日本語訳(Coop編) (ecoop.net)
上のマニュアルの日本語訳。とても役に立つが少し古い。
GNU Make の使い方 (みねこあ)
オライリー本にあるテクニックが紹介されていたので参考にした。結局あまり難しいことはしなかったけれど。