make
https://www.gnu.org/software/make/manual/make.html
あらかじめコンパイルの命令を Makefile
に書いておくことで、
ターミナルに長いコマンドを何度も打ち込むのを避けられる。
クロスプラットフォームで依存関係を解決しつつビルドするような
Makefile
を自分で書くのは難しいので、
CMake や autotools
を使って自動生成する。
Makefile
C++ソースコードと同じディレクトリに入れるだけでとりあえず使える例:
## Options
PROGRAM := a.out
CXX := clang++
CC := clang
CXXFLAGS := -Wall -Wextra -O3 -std=c++14
CPPFLAGS := -I/usr/local/include -I${HOME}/local/include
LDFLAGS := -L/usr/local/lib -L${HOME}/local/lib
#LDLIBS := -lboost_program_options
TARGET_ARCH := -march=native
## Dependencies
SRCS := $(wildcard *.cpp)
OBJS := $(SRCS:.cpp=.o)
-include Dependfile
Dependfile:
${CXX} -MM ${CPPFLAGS} ${CXXFLAGS} ${TARGET_ARCH} ${SRCS} > Dependfile
## Targets
.DEFAULT_GOAL := all
.PHONY: all clean
all: ${PROGRAM}
@:
${PROGRAM}: ${OBJS}
${LINK.cpp} ${OUTPUT_OPTION} $^ ${LDLIBS}
clean:
${RM} ${OBJS} ${PROGRAM}
Rule
https://www.gnu.org/software/make/manual/make.html#Rules
コロンとタブを使って以下のような形式でルールを書くのが基本。
このMakefile
があるところでターミナルから make TARGET
と打つと、
ターゲットよりもソースファイルが新しい場合にコマンドが実行される。
TARGET : SOURCE1 SOURCE2
COMMAND
a.out : main.cpp sub.cpp
g++ -O2 main.cpp sub.cpp
下記のようなパターンルールが予め定義されている。 (see Pattern Rule)
%.o : %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
%.o : %.cpp
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
以下に紹介するように、ほかにも様々な変数や関数が用意されていて、 個別のファイル名などをいちいち入力しなくても済むようになっている。
ファイル名が明示的に書かれずルールのみで生成された中間ファイルは自動的に削除される。
.PRECIOUS
ターゲットにその名を加えておくとそれを防げる。
逆に、名前は出すけど中間ファイルとして扱いたい場合は .SECONDARY
ターゲットに加える。
Implicit Variables
- https://www.gnu.org/software/make/manual/make.html#Implicit-Variables
- https://www.gnu.org/software/make/manual/make.html#Name-Index
CC
- Cコンパイラ
cc
CXX
- C++コンパイラ
g++
COMPILE.cpp
$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
LINK.cpp
$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
LINK.o
$(CC) $(LDFLAGS) $(TARGET_ARCH)
OUTPUT_OPTION
-o $@
RM
rm -f
CPPFLAGS
- プリプロセッサ用オプション。
e.g.,
-DNDEBUG -I${HOME}/local/include
CXXFLAGS
- C++コンパイラ用オプション。 e.g.,
-Wall -Wextra -O3 -std=c++14
LDFLAGS
- ライブラリパスを指定する。 e.g.,
-L/usr/local/lib -L{HOME}/local/lib
LDLIBS
- リンクするライブラリを指定する。
昔は
LOADLIBES
も同じ機能だったが非推奨。 e.g.,-lboost_program_options -lz
TARGET_ARCH
- マシン依存なオプションを指定する。
e.g.,
-march=native -m64 -msse -msse2 -msse3 -mfpmath=sse
Automatic Variables
https://www.gnu.org/software/make/manual/make.html#Automatic-Variables
$@
- ターゲット
$<
- 必須項目の先頭
$^
- 必須項目のスペース区切り
- 重複してても削らずそのまま欲しい場合は
$+
- 新しく更新があったファイルだけ欲しい場合は
$?
Functions
https://www.gnu.org/software/make/manual/make.html#Functions
- 文字列関連
$(subst FROM,TO,TEXT)
$(findstring FIND,IN)
$(filter PATTERN...,TEXT)
- ファイル名
$(dir NAMES...)
$(notdir NAMES...)
$(basename NAMES...)
$(addprefix PREFIX,NAMES...)
$(wildcard PATTERN)
$(abspath NAMES...)
- 条件分岐
$(if CONDITION,THEN,ELSE)
関数じゃない条件分岐 (
ifeq
,ifneq
,ifdef
,ifndef
,else
,endif
) もある。- その他
$(foreach VAR,LIST,TEXT)
:LIST
の中身をそれぞれVAR
に入れてTEXT
を実行$(file op FILENAME,TEXT)
:text
の結果をファイルに書き出す$(call VARIABLE,PARAMS...)
:$(1) $(2)
などを使って定義しておいたVARIABLE
を関数のように呼び出す$(origin VARIABLE)
: 変数がどう定義されたかを知れる$(error TEXT...)
,$(warning TEXT...)
,$(info TEXT...)
: エラーや警告をプリントする$(shell COMMAND...)
: シェルを呼び出す
Targets
https://www.gnu.org/software/make/manual/make.html#Standard-Targets
all
- ディレクトリ内のcppソースをコンパイル
clean
- コンパイル済みオブジェクトを一掃
_
- v3.81以降であれば
.DEFAULT_GOAL
が効くのでmake all
と同じ
make clean
make
Options
https://www.gnu.org/software/make/manual/make.html#Options-Summary
-f file
Makefile
じゃない名前のファイルを指定したければ-j jobs
- 並列コンパイル。コア数+1くらいがちょうどいいらしい
-C directory
- そのディレクトリに行って
make
-p
- 自動的に作られるものも含めてすべての変数を表示