ソースが複階層化された場合のMakefile(第五回)
まだバグがあるかもしれない。後日追って詳細を追記したい。
ソースファイルが複数階層に分かれた場合に対応したMakefileが完成!
試行錯誤の末、以下に示すMakefileが完成した。このMakefileは以下のことが可能
- 依存関係の自動解決(ヘッダファイルも含む)
- 中間生成ファイルの別ディレクトリ化(OBJDIRで指定)
- 下位階層も含めたソースファイルの検索(拡張子がcppのものを検索して追加)
- コンパイルしたくないディレクトリの除外(NOMAKEDIRで指定)
前回の問題点
前回は複階層化されたものに完全に対応していなかった。原因はOBJDIR内に中間ファイルを置くためのサブディレクトリをMakefileが自動で作成しないからだった(詳しくは実行してみて)。
今回の改善点
まず問題だった手動ディレクトリ生成を自動化した。これによりソースファイルが複階層化されていても問題なくコンパイルできるようになった。また、前回はwildcard関数によりcppファイルを検索していたが、UNIXのfindコマンドを使うことにより下位階層も検索可能になった。さらに参考にしたサイトよりコンパイルが不要なディレクトリを追加できるようになった。コンパイルしたくない(Makefileのルートパス+)除外ディレクトリ名+%で除外できる。
プログラムを新しく作る度にMakefileの変更点が多い、またどこを変えるんだっけ?と時間の無駄を省くために主要な変更点をUser settingにまとめた。基本的にここを適切なものに変更するだけで階層が分かれていようがコンパイルできる...はず。
今後の課題
プリコンパイルヘッダの実装である。試験的に実装してみたところ、基本的には正常動作するが大量のファイルを変更した際になぜかセグる(Segmentation error)問題があった。C++で外部ライブラリをバンバン使う身においてはプリコンパイルヘッダによるコンパイル速度の高速化もできれば達成したい。
################################################################ # # Makefile # # - search recursively the source file # # Time-stamp: "2013-12-18 15:53:50 Gmaj7sus4" # ################################################################ #--------------------------------------------------------------- # User setting #--------------------------------------------------------------- TARGET = main INCLUDES = -I./include LDFLAGS = -lyaml-cpp NOMAKEDIR= .git% data% doc% src/bin% OBJDIR = objs #--------------------------------------------------------------- # Don't change the following #--------------------------------------------------------------- GCC = g++ CFLAGS = -O2 -MMD -MP -Wall -Wextra CPPS = $(shell find * -name *.cpp) SRCS = $(filter-out $(NOMAKEDIR), $(CPPS)) DIRS = $(dir $(SRCS)) BINDIRS = $(addprefix $(OBJDIR)/, $(DIRS)) OBJS = $(addprefix $(OBJDIR)/, $(patsubst %.cpp, %.o, $(SRCS))) # patsubstは空白で区切られたものか指定の文字列に置換 DEPS = $(OBJS:.o=.d) TILS = $(patsubst %.cpp, %.cpp~, $(SRCS)) ifeq "$(strip $(OBJDIR))" "" OBJDIR = . endif ifeq "$(strip $(DIRS))" "" OBJDIR = . endif default: @[ -d $(OBJDIR) ] || mkdir -p $(OBJDIR) @[ -d "$(BINDIRS)" ] || mkdir -p $(BINDIRS) @make all --no-print-directory ./$(TARGET) all : $(OBJS) $(TARGET) $(TARGET): $(OBJS) $(LIBS) $(GCC) -o $@ $^ $(LDFLAGS) $(OBJDIR)/%.o: %.cpp $(GCC) $(CFLAGS) $(INCLUDES) -o $@ -c $< clean: @rm -rf $(TARGET) $(TILS) $(OBJDIR) -include $(DEPS)
- 参考サイト