#概要
cmake
を使っても良いのだけど、ちょっとしたC++のコードを書くときにCMakeLists.txt
を一から書くのもなんとなく億劫だったので、拡張が容易かつジェネリックなMakefile
を書いてみました。またMakefile
をMakefile
とMakefile.in
の2つに分離したことにより、ソースコードを共有する複数のプロジェクトのビルドも容易にできます。
#使い方
- プロジェクトが存在するディレクトリに、後ほど説明する
Makefile
とMakefile.in
を入れてください。 - ソースコードを
./src
以下に、ライブラリを./include
以下に入れてください。 -
Makefile
を編集して、各プロジェクトに対してコンパイル&リンクするソースコードを指定してください。 - 以上の作業で完了です。あとは自由に
Makefile
のコマンドが使えます。
以下に使用できるコマンドをまとめました([TARGET]
はMakefile
内で指定するターゲット名)。
なお実行ファイルは./bin
以下に、オブジェクトファイルは./obj
以下に自動的に生成されます。
コマンド | 説明 |
---|---|
make [TARGET] |
make [TARGET].release と同じ |
make [TARGET].release |
最適化オプションを適用し[TARGET] をビルドする |
make [TARGET].develop |
デバッグ用に[TARGET] をビルドする |
make [TARGET].all |
[TARGET] を強制的にビルドする |
make [TARGET].run |
生成された[TARGET] の実行ファイルを実行する |
make [TARGET].debug |
生成された[TARGET] の実行ファイルをgdb でデバッグする |
make [TARGET].clear |
生成された[TARGET] の実行ファイルを消去する |
make [TARGET].clean |
[TARGET] の実行ファイルとオブジェクトファイルを消去する |
make all |
すべてのプロジェクトをコンパイルする。 |
make clear |
すべてのプロジェクトの実行ファイルを消去する。 |
make clean |
すべてのプロジェクトの実行ファイルとオブジェクトファイルを消去する。 |
#Sample & Makefileの解説
Sample
実際にやってみましょう(サンプルコードのダウンロードはこちらから)。
簡単のため、以下のような./src
以下にソースコードが、./include
以下にライブラリがあるようなディレクトリ構造のプロジェクトを考えてみます。ここでprog_A
、prog_B
の2つのプロジェクトのソースコードがあり、それぞれutils.hpp
に依存するような状況だとします。
.
├── Makefile
├── Makefile.in
├── include
│ └── utils
│ └── utils.hpp
└── src
├── prog_A
│ ├── hoge.cpp
│ ├── hoge.hpp
│ └── main.cpp
├── prog_B
│ ├── fuga.cpp
│ ├── fuga.hpp
│ └── main.cpp
└── utils
└── utils.cpp
Makefileの設定
まずMakefile
は以下のように設定します。
MAKEFLAGS += --no-print-directory --no-builtin-rules
.DEFAULT_GOAL := all
TARGET := prog_A prog_B
prog_A : ARGS += "BIN_NAME=prog_A"
prog_A : ARGS += "SRC_DIRS=./src/prog_A ./src/utils"
prog_B : ARGS += "BIN_NAME=prog_B"
prog_B : ARGS += "SRC_DIRS=./src/prog_B ./src/utils"
$(addsuffix .release,$(TARGET)) : OPTION += release
%.release : %
@:
$(addsuffix .develop,$(TARGET)) : OPTION += develop
%.develop : %
@:
$(addsuffix .all,$(TARGET)) : OPTION += all
%.all : %
@:
$(addsuffix .run,$(TARGET)) : OPTION += run
%.run : %
@:
$(addsuffix .debug,$(TARGET)) : OPTION += debug
%.debug : %
@:
$(addsuffix .clear,$(TARGET)) : OPTION += clear
%.clear : %
@:
$(addsuffix .clean,$(TARGET)) : OPTION += clean
%.clean : %
@:
all : $(TARGET)
clear : $(addsuffix .clear,$(TARGET))
clean : $(addsuffix .clean,$(TARGET))
$(TARGET) :
@echo "----- make $(OPTION) $@ -----"
@make -f ./Makefile.in $(ARGS) $(OPTION)
ここで各プロジェクトに最低必要なのは以下のコードとなります。
各プロジェクトに対してMakefile
内に以下のコードを記述してください。
[TARGET] : ARGS += "BIN_NAME=[実行ファイルの名前]"
[TARGET] : ARGS += "SRC_DIRS=[依存するソースコードが存在する相対ディレクトリ]"
また変数TARGET
に追加したターゲットを加えれば完成です。
Makefile.inの解説
次にコンパイラに詳細なオプションを与えるMakefile.in
を解説します。
MAKEFLAGS += --no-builtin-rules
CXX := g++
CXXFLAGS := -std=c++17 -Wall -m64 -MMD -MP
CXXFLAGS_DEV := -O0 -g
CXXFLAGS_REL := -O3
DEBUG := gdb
LIBS := -lpthread -lglut -lm
CPPFLAGS := $(addprefix -I, ./include $(wildcard ./include/*))
CPPFLAGS += `pkg-config --cflags opencv`
ifeq "$(shell getconf LONG_BIT)" "64"
LDFLAGS := `pkg-config --libs opencv`
else
LDFLAGS :=
endif
SUFFIX := cpp
BIN_NAME :=
BIN_DIR := ./bin
BINARY := $(BIN_DIR)/$(BIN_NAME)
SRC_DIR := ./src
SOURCES := $(SRC_FILES)
SOURCES += $(foreach dir,$(SRC_DIRS),$(shell find $(dir) -regex ".*\.$(SUFFIX)"))
OBJ_DIR := ./obj
OBJECTS := $(patsubst $(SRC_DIR)/%,$(OBJ_DIR)/%,$(SOURCES:.$(SUFFIX)=.o))
DEPENDS := $(OBJECTS:.o=.d)
.DEFAULT_GOAL := release
release : CXX_FLAGS += $(CXXFLAGS_REL)
release : $(BINARY)
develop : CXX_FLAGS += $(CXXFLAGS_DEV)
develop : $(BINARY)
$(BINARY) : $(OBJECTS) $(LIBS)
mkdir -p $(@D)
$(CXX) -o $@ $^ $(LDFLAGS)
$(OBJ_DIR)/%.o : $(SRC_DIR)/%.$(SUFFIX)
mkdir -p $(@D)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $@ -c $<
all : clean release
debug :
$(DEBUG) $(BINARY)
run:
$(BINARY)
clear :
-rm -rf $(BINARY)
clean :
-rm -rf $(OBJECTS) $(BINARY)
.PHONY : all debug run clean clear
-include $(DEPENDS)
代表的なオプションについて説明します。
option | 説明 |
---|---|
CXX |
C++のコンパイラの種類 |
CXXFLAGS |
オプション |
CXXFLAGS_DEV |
make develop 時に与えるオプション |
CXXFLAGS_REL |
make release 時に与えるオプション |
DEBUG |
デバッガのプログラム |
LIBS |
リンクするライブラリ |
CPPFLAGS |
プリプロセス時に使うオプション |
SUFFIX |
ソースコードの拡張子 |
お好みでこれらのオプションを変えることができます。また、あるプロジェクトのみに変更を適応したい場合は、Makefile
内の変数ARGS
にARGS += "[OPTION]=[VALUE]"
とすれば設定できます。
補足
-
make
のオプションに--no-builtin-rules
を加えることで暗黙のルールを使用しないようにしています。これにより探索範囲が狭まり、さらに高速にコンパイルができるようになります。 - 今回の例では拡張子を
cpp
とhpp
に指定しましたが、Makefile.in
内の変数SUFFIX
を変更することで、別の拡張子を用いることができます。 - 今回の例ではソースコードの場所をディレクトリで指定しましたが、
ARGS += "SRC_FILES=[PATH/TO/FILE]"
でファイルを直接指定することもできます。 -
Makefile
に追記することでツールを拡張することができます。
Download
#参考文献
以下の文献を参考にさせていただきましたm(_ _)m。
http://boysenberrypi.hatenadiary.jp/entry/2014/03/15/113703
http://nantonaku-shiawase.hatenablog.com/entry/20110905/1321356759
http://d.hatena.ne.jp/tanakaBox/20070327/1174958337