Search code examples
c++makefilegnu-makegnu

Necessity of filter in GNU makefile


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.

source

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?


Solution

  • 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