I have the following directory structure.
/home/user/
├── Makefile
│
├── easy/
│ └── a.cpp
├── medium/
│ └── b.cpp
└── build/
My goal is to compile all .cpp
files in easy
and medium
and create separate executables in build
. The Makefile below achieves what I want (omitting the parts that are not relevant to my question). The part I do not understand is the necessity of the call to filter
in line 6.
1 SOURCEDIRS = easy medium
2 TARGETDIR = build
3
4 SOURCES = $(foreach dir,$(SOURCEDIRS),$(wildcard $(dir)/*.cpp))
5 $(info $(SOURCES))
6 TARGETS = $(foreach dir,$(SOURCEDIRS),$(patsubst $(dir)/%.cpp,$(TARGETDIR)/%.out,$(filter $(dir)/%,$(SOURCES))))
7 $(info $(TARGETS))
Output:
# content of SOURCES
easy/a.cpp medium/b.cpp
# content of TARGETS
build/a.out build/b.out
Specifically, based on the the manual for patsubst
, I would expect the call to filter
to be redundant.
$(patsubst pattern,replacement,text)
Finds whitespace-separated words in text that match pattern and replaces them with replacement.
E.g., I would expect the following Makefile to achieve my goal,
1 SOURCEDIRS = easy medium
2 TARGETDIR = build
3
4 SOURCES = $(foreach dir,$(SOURCEDIRS),$(wildcard $(dir)/*.cpp))
5 $(info $(SOURCES))
6 TARGETS = $(foreach dir,$(SOURCEDIRS),$(patsubst $(dir)/%.cpp,$(TARGETDIR)/%.out,$(SOURCES)))
7 $(info $(TARGETS))
though the contents of TARGETS
are
# content of SOURCES
easy/a.cpp medium/b.cpp
# content of TARGETS
build/a.out medium/b.cpp easy/a.cpp build/b.out
What am I misunderstanding? Why do we need filter
in this case?
patsubst
doesn't delete the words that don't match the pattern.
$(patsubst easy/%.cpp,build/%.out,easy/a.cpp medium/b.cpp)
is not build/a.out
, it's build/a.out medium/b.cpp