在 makefile 中进行模式匹配时获取错误的文件名

Getting wrong file name while pattern matching in makefile

我项目的目录结构是这样的:

|-build
|-src
   |-lib
      |-libfile1.hpp
      |-libfile1.cpp
      |-libfile2.hpp
      |-libfile2.cpp
      |-libfile3.hpp 
      |-Makefile(lib)
   |-examples
      |-pingpong
          |-main.cpp
          |-ping.cpp
          |-ping.hpp
          |-Makefile(ping)

我的目标是在示例文件夹中有许多示例,它们都使用 libfiles 但彼此独立。因此,我想在每个示例文件夹中使用单独的 makefile 到 link 到 libfiles 的对象。

为了实现这个目标,这里是 makefile(lib):

SRC = .
BLD = ../../build

SOURCE = $(wildcard $(SRC)/*.cpp)
INCLUDE = $(wildcard $(SRC)/*.hpp)
OBJECT = $(patsubst %,$(BLD)/%, $(notdir $(SOURCE:.cpp=.o)))

CC = g++

#flags went here, removed for brevity

all: $(OBJECT)

$(BLD)/%.o: $(SRC)/%.cpp $(SRC)/%.hpp
    mkdir -p $(dir $@)
    $(CC) -c $< -o $@

.PHONY: clean

clean:
    $(RM) -r $(BLD)

这是 makefile(ping),我在其中尝试构建本地对象并将库对象构建模式传递给 makefile(lib):

TARGET = mainpingpong.out

SRC = ../../actorlib
BLD = ../../../build

LIBSOURCE = $(wildcard $(SRC)/*.cpp)
LIBINCLUDE = $(wildcard $(SRC)/*.hpp)
LIBOBJECT = $(patsubst %,$(BLD)/%, $(notdir $(LIBSOURCE:.cpp=.o)))
LOCSOURCE =  $(wildcard *.cpp)
LOCINCLUDE = $(wildcard *.hpp)
LOCOBJECT = $(patsubst %,$(BLD)/%, $(notdir $(LOCSOURCE:.cpp=.o)))

CC = g++
$(TARGET) : $(LIBOBJECT) $(LOCOBJECT)
    $(CC)-o $@ $^

$(LOCOBJECT): $(LOCSOURCE) $(LOCINCLUDE)
    mkdir -p $(dir $@)
    $(CC) -c $< -o $@

$(LIBOBJECT): $(LIBSOURCE) $(LIBINCLUDE)
    cd $(SRC) && $(MAKE)

.PHONY: clean

clean :
    cd $(SRC) && $(MAKE) clean

错误发生在我的本地文件匹配中,它将 main.o 和 ping.o 与 main.cpp 相关联(其他一切正常):

mkdir -p ../../../build/
g++ -c main.cpp -o ../../../build/main.o

mkdir -p ../../../build/
g++ -c main.cpp -o ../../../build/ping.o

我如何正确地做我想做的事?我应该有不同的规则或目标吗?或者是否有从变量中获取文件名的正确方法?

我希望 .o 文件最终位于同一个位置,但可执行文件保留在示例目录中。

问题出在这里:

$(LOCOBJECT): $(LOCSOURCE) $(LOCINCLUDE)
    mkdir -p $(dir $@)
    $(CC) -c $< -o $@

LOCSOURCE 包含 main.cpp ping.cpp,因此此规则使 both 个源文件成为 each 目标的先决条件。无论 Make 正在尝试构建 main.o 还是 ping.o,先决条件列表都是相同的:main.cpp ping.cpp ping.hpp。所以自动变量 $< 总是扩展为 main.cpp (因为这是列表中的第一个文件名)。

解决这个问题的一种方法是 static pattern rule:

$(LOCOBJECT): $(BLD)/%.o: %.cpp $(LOCINCLUDE)
    mkdir -p $(dir $@)
    $(CC) -c $< -o $@

这仍然不完善,因为所有本地头文件都是来自本地源的每个对象的先决条件。如果你有一个 paddle.cpp 并且你修改了 ping.hpp,Make 将重建 paddle.o,即使 paddle.cpp 不以任何方式依赖于 ping.hpp。这不是一个严重的问题,它只是意味着 Make 会做一些额外的工作,在没有理由的时候重建东西。如果你想解决它,你可以手动将依赖项写入makefile,或者使用更复杂的方法,如automatic dependency generation