他にもMakefileに関する記事を書いていますが、この記事だけで読んでも問題ありません。目次→Makefileの書き方に関する備忘録 - minus9d's diary
少し複雑な構成を持つC++のコード群からバイナリをビルドするための良いMakefileの例を makefile - How to place object files in separate subdirectory - Stack Overflow に見つけたので共有します。
目標
まず、以下のようなソースコードを持っているとします。src
はC++のソースコードを格納するディレクトリで、その下のディレクトリ構造は決まった形をもたないものとします。include
はヘッダファイルのみを格納するディレクトリです。
/your_project /src /subdir1/a.cpp, a.h b.cpp, b.h /subdir2/subsubdir/c.cpp, c.h d.cpp, d.h /include e.h
これをビルドして以下のようにするのを目標とします。
/your_project /src /include /obj 中間生成物置き場 /bin 最終バイナリ置き場
Makefile
前出のページを参考に、自分なりに取捨選択して書き直したMakefileが以下です。このファイルは、your_projectディレクトリの直下に置かれているものとします。
# 参考:https://stackoverflow.com/questions/5178125/how-to-place-object-files-in-separate-subdirectory # C++のコンパイラ CXX := g++ # 生成するバイナリの名前 TARGET := target # ディレクトリ名 SRCDIR := src BUILDDIR := obj TARGETDIR := bin # 拡張子名 SRCEXT := cpp DEPEXT := d OBJEXT := o # コンパイル、リンクのフラグ CXXFLAGS := -Wall -g -std=c++14 LDFLAGS := INC := -Isrc -Iinclude #--------------------------------------------------------------------------------- # DO NOT EDIT BELOW THIS LINE #--------------------------------------------------------------------------------- sources := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT)) objects := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(subst $(SRCEXT),$(OBJEXT),$(sources))) dependencies := $(subst .$(OBJEXT),.$(DEPEXT),$(objects)) # Defauilt Make all: directories $(TARGETDIR)/$(TARGET) # Remake remake: cleaner all # ディレクトリ生成 directories: @mkdir -p $(TARGETDIR) @mkdir -p $(BUILDDIR) # 中間生成物のためのディレクトリを削除 clean: @$(RM) -rf $(BUILDDIR) # 中間生成物のためのディレクトリと最終生成物のためのディレクトリを削除 cleaner: clean @$(RM) -rf $(TARGETDIR) # 自動抽出した.dファイルを読み込む -include $(dependencies) # オブジェクトファイルをリンクしてバイナリを生成 $(TARGETDIR)/$(TARGET): $(objects) $(CXX) -o $(TARGETDIR)/$(TARGET) $^ $(LDFLAGS) # ソースファイルのコンパイルしてオブジェクトファイルを生成 # また、ソースファイルの依存関係を自動抽出して.dファイルに保存 $(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT) @mkdir -p $(dir $@) $(CXX) $(CXXFLAGS) $(INC) -c -o $@ $< @$(CXX) $(CXXFLAGS) $(INC) -MM $(SRCDIR)/$*.$(SRCEXT) > $(BUILDDIR)/$*.$(DEPEXT) @cp -f $(BUILDDIR)/$*.$(DEPEXT) $(BUILDDIR)/$*.$(DEPEXT).tmp @sed -e 's|.*:|$(BUILDDIR)/$*.$(OBJEXT):|' < $(BUILDDIR)/$*.$(DEPEXT).tmp > $(BUILDDIR)/$*.$(DEPEXT) @sed -e 's/.*://' -e 's/\\$$//' < $(BUILDDIR)/$*.$(DEPEXT).tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $(BUILDDIR)/$*.$(DEPEXT) @rm -f $(BUILDDIR)/$*.$(DEPEXT).tmp # Non-File Targets .PHONY: all remake clean cleaner
このMakefileでは、"DO NOT EDIT BELOW THIS LINE" より上にある項目を自分の環境に合わせて変更し、make
とコマンドを打つことで、バイナリがbin
以下にできるようになります。
また、ソースコードの依存関係も自動で抽出するので、あるファイルを更新したあとmake
すると、そのファイルに依存するすべてのファイルに再コンパイルがかかります。
使い方は以下の通りです。