前記事
前記事の続きという位置付けですが, 単独で読めると思います.
はじめに
複数ファイルで使うアルゴリズムやデータ構造は, 共通のソースファイルとヘッダファイルに切り出すと良い.
例えば union-find.(cpp|hpp)
が code_11_%.cpp
と solution_11_%.cpp
から使われるときの Makefile
は以下のように書ける.
しかし, code_11_%
と solution_11_%
で同じようなルールを定義している部分が冗長である.
CXX := g++
CXX_BASE_FLAGS := -Wall -Wextra -std=c++20
CXXFLAGS := $(CXX_BASE_FLAGS) -lgtest_main -lgtest -lpthread
UNION_FIND_SRC := union-find.cpp
UNION_FIND_OBJ := $(UNION_FIND_SRC:.cpp=.o)
UNION_FIND_HDR := $(UNION_FIND_SRC:.cpp=.hpp)
TARGETS := $(basename $(wildcard *_[1-9]*_[1-9]*.cpp)) # ワイルドカードは適宜変更
.PHONY: clean
all: $(TARGETS)
# ↓ union-findを使うためのルールここから ↓
code_11_%: code_11_%.o $(UNION_FIND_OBJ)
$(CXX) $(CXXFLAGS) $^ -o $@
solution_11_%: solution_11_%.o $(UNION_FIND_OBJ)
$(CXX) $(CXXFLAGS) $^ -o $@
code_11_%.o: code_11_%.cpp $(UNION_FIND_HDR)
solution_11_%.o: solution_11_%.cpp $(UNION_FIND_HDR)
# ↑ union-findを使うためのルールここまで ↑
$(UNION_FIND_OBJ): $(UNION_FIND_SRC) $(UNION_FIND_HDR)
.cpp.o:
$(CXX) $(CXX_BASE_FLAGS) -c $<
clean:
$(RM) $(TARGETS) $(UNION_FIND_OBJ)
冗長さを減らす
そこで, 以下のようにdefine
, call
, eval
, foreach
を使いマクロで冗長さを減らせる. 1 2
CXX := g++
CXX_BASE_FLAGS := -Wall -Wextra -std=c++20
CXXFLAGS := $(CXX_BASE_FLAGS) -lgtest_main -lgtest -lpthread
UNION_FIND_SRC := union-find.cpp
UNION_FIND_OBJ := $(UNION_FIND_SRC:.cpp=.o)
UNION_FIND_HDR := $(UNION_FIND_SRC:.cpp=.hpp)
TARGETS := $(basename $(wildcard *_[1-9]*_[1-9]*.cpp)) # ワイルドカードは適宜変更
TARGETS_WITH_UNION_FIND := code_11_% solution_11_% # ← ★追加
.PHONY: clean
all: $(TARGETS)
# ↓★書き換えココから↓
define CXX_WITH_UNION_FIND
$(1): $(1).o $(UNION_FIND_OBJ)
$$(CXX) $$(CXXFLAGS) $$^ -o $$@
$(1).o: $(1).cpp $(UNION_FIND_HDR)
endef
$(foreach T, $(TARGETS_WITH_UNION_FIND), $(eval $(call CXX_WITH_UNION_FIND, $(T))))
# ↑★書き換えココまで↑
$(UNION_FIND_OBJ): $(UNION_FIND_SRC) $(UNION_FIND_HDR)
.cpp.o:
$(CXX) $(CXX_BASE_FLAGS) -c $<
clean:
$(RM) $(TARGETS) $(UNION_FIND_OBJ)
確認
make -np
すると, 以下のように期待どおりにルールが展開されている.
抜粋
$ make -np
.
.
.
code_11_%: code_11_%.o union-find.o
# commands to execute (from `Makefile', line 22):
$(CXX) $(CXXFLAGS) $^ -o $@
code_11_%.o: code_11_%.cpp union-find.hpp
solution_11_%: solution_11_%.o union-find.o
# commands to execute (from `Makefile', line 22):
$(CXX) $(CXXFLAGS) $^ -o $@
solution_11_%.o: solution_11_%.cpp union-find.hpp
.
.
.
make
すると, 以下のように期待どおりにコンパイルされる.
出力例
$ make
g++ -Wall -Wextra -std=c++20 -c union-find.cpp
g++ -Wall -Wextra -std=c++20 -c code_11_03.cpp
g++ -Wall -Wextra -std=c++20 -lgtest_main -lgtest -lpthread code_11_03.o union-find.o -o code_11_03
g++ -Wall -Wextra -std=c++20 -c solution_11_01.cpp
g++ -Wall -Wextra -std=c++20 -lgtest_main -lgtest -lpthread solution_11_01.o union-find.o -o solution_11_01
rm code_11_03.o solution_11_01.o