Makefileを書くのに疲れた人のためのSCons
dtlのサンプルプログラムやテストプログラムのビルドをSConsでやってみた。
dtlの複数あるサンプルプログラムのMakefileはこんな風になっている。
Makefile
CPP = g++ CPPFLAGS = -c -O2 -Wall OBJS_FLAGS = -O2 -o STRDIFF_OBJS = strdiff.o common.o STRDIFF3_OBJS = strdiff3.o common.o UNIDIFF_OBJS = unidiff.o common.o UNISTRDIFF_OBJS = unistrdiff.o common.o INTDIFF_OBJS = intdiff.o INTDIFF3_OBJS = intdiff3.o PATCH_OBJS = patch.o common.o FPATCH_OBJS = fpatch.o common.o ALL_TARGETS = strdiff strdiff3 unidiff unistrdiff intdiff intdiff3 patch fpatch DEPENDENCY_FILE = Makefile.depend .cpp.o: $(CPP) $(CPPFLAGS) $< all : $(ALL_TARGETS) strdiff : $(STRDIFF_OBJS) $(CPP) $(OBJS_FLAGS) $@ $(STRDIFF_OBJS) strdiff3 : $(STRDIFF3_OBJS) $(CPP) $(OBJS_FLAGS) $@ $(STRDIFF3_OBJS) unidiff : $(UNIDIFF_OBJS) $(CPP) $(OBJS_FLAGS) $@ $(UNIDIFF_OBJS) unistrdiff : $(UNISTRDIFF_OBJS) $(CPP) $(OBJS_FLAGS) $@ $(UNISTRDIFF_OBJS) intdiff : $(INTDIFF_OBJS) $(CPP) $(OBJS_FLAGS) $@ $(INTDIFF_OBJS) intdiff3 : $(INTDIFF3_OBJS) $(CPP) $(OBJS_FLAGS) $@ $(INTDIFF3_OBJS) patch : $(PATCH_OBJS) $(CPP) $(OBJS_FLAGS) $@ $(PATCH_OBJS) fpatch : $(FPATCH_OBJS) $(CPP) $(OBJS_FLAGS) $@ $(FPATCH_OBJS) clean: ${RM} *.o *~ $(ALL_TARGETS) depend: @echo "generating dependency file" @$(CPP) -MM *.cpp > $(DEPENDENCY_FILE) include $(DEPENDENCY_FILE)
各サンプルプログラムがターゲットになっていて、依存関係の解析はGCCの-MMオプションを使ってMakefile.dependに出力し、そのMakefile.dependをMakefileがインクルードするようにしている。
makeでビルド
$ make g++ -c -O2 -Wall strdiff.cpp g++ -c -O2 -Wall common.cpp g++ -O2 -o strdiff strdiff.o common.o g++ -c -O2 -Wall strdiff3.cpp g++ -O2 -o strdiff3 strdiff3.o common.o g++ -c -O2 -Wall unidiff.cpp g++ -O2 -o unidiff unidiff.o common.o g++ -c -O2 -Wall unistrdiff.cpp g++ -O2 -o unistrdiff unistrdiff.o common.o g++ -c -O2 -Wall intdiff.cpp g++ -O2 -o intdiff intdiff.o g++ -c -O2 -Wall intdiff3.cpp g++ -O2 -o intdiff3 intdiff3.o g++ -c -O2 -Wall patch.cpp g++ -O2 -o patch patch.o common.o g++ -c -O2 -Wall fpatch.cpp g++ -O2 -o fpatch fpatch.o common.o $
一方、同じことをSConsでやろうとするとこうなる。
SConstruct
env = Environment(CCFLAGS='-Wall -O2') targets = { 'strdiff' : ['strdiff.cpp', 'common.cpp'], 'intdiff' : ['intdiff.cpp'], 'strdiff3' : ['strdiff3.cpp', 'common.cpp'], 'intdiff3' : ['intdiff3.cpp', 'common.cpp'], 'unidiff' : ['unidiff.cpp', 'common.cpp'], 'unistrdiff' : ['unistrdiff.cpp', 'common.cpp'], 'patch' : ['patch.cpp', 'common.cpp'], 'fpatch' : ['fpatch.cpp', 'common.cpp'] } for target in targets: objs = targets[target] env.Program(target, obs)
Makefileみたいに奇妙で覚えづらい呪文($@, $<, $^, $%, $?, $+, $*)はないし、
Pythonで書けるからとてもプログラムっぽくなった。
しかもdependターゲットはもう必要ない!(ここ重要)
sconsでビルド
$ scons scons: Reading SConscript files ... scons: done reading SConscript files. scons: Building targets ... g++ -o common.o -c -Wall -O2 common.cpp g++ -o fpatch.o -c -Wall -O2 fpatch.cpp g++ -o fpatch fpatch.o common.o g++ -o intdiff.o -c -Wall -O2 intdiff.cpp g++ -o intdiff intdiff.o g++ -o intdiff3.o -c -Wall -O2 intdiff3.cpp g++ -o intdiff3 intdiff3.o common.o g++ -o patch.o -c -Wall -O2 patch.cpp g++ -o patch patch.o common.o g++ -o strdiff.o -c -Wall -O2 strdiff.cpp g++ -o strdiff strdiff.o common.o g++ -o strdiff3.o -c -Wall -O2 strdiff3.cpp g++ -o strdiff3 strdiff3.o common.o g++ -o unidiff.o -c -Wall -O2 unidiff.cpp g++ -o unidiff unidiff.o common.o g++ -o unistrdiff.o -c -Wall -O2 unistrdiff.cpp g++ -o unistrdiff unistrdiff.o common.o scons: done building targets. $
ただ、プロジェクトの規模が大きくなるとSConsは使えないらしい↓
http://twitter.com/taku910/status/13854036710:twitter:detail:left
もうちょっと詳しめなのを↓に書きました。