GNU makefile 中过滤器的必要性

Necessity of filter in GNU makefile

我有以下目录结构。

/home/user/
          ├── Makefile
          │ 
          ├── easy/
          │     └── a.cpp
          ├── medium/
          │       └── b.cpp
          └──  build/

我的目标是编译 easymedium 中的所有 .cpp 文件,并在 build 中创建单独的可执行文件。下面的 Makefile 实现了我想要的(省略了与我的问题无关的部分)。我不明白的部分是第 6 行调用 filter 的必要性。

  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))

输出:

# content of SOURCES
easy/a.cpp medium/b.cpp
# content of TARGETS
build/a.out build/b.out

具体来说,根据 patsubst 的手册,我认为对 filter 的调用是多余的。

$(patsubst pattern,replacement,text)

Finds whitespace-separated words in text that match pattern and replaces them with replacement.

source

例如,我希望以下 Makefile 能够实现我的目标,

  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))

虽然TARGETS的内容是

# content of SOURCES
easy/a.cpp medium/b.cpp
# content of TARGETS
build/a.out medium/b.cpp easy/a.cpp build/b.out

我误会了什么?为什么在这种情况下我们需要 filter

patsubst 不删除与模式不匹配的词。

$(patsubst easy/%.cpp,build/%.out,easy/a.cpp medium/b.cpp) 不是 build/a.out,而是 build/a.out medium/b.cpp