告诉 make 目标将在子文件夹中

Telling make that targets will be in a subfolder

我有一个这个玩具结构的项目:

src:
    obj1.cpp
    obj2.cpp
obj: 
    (empty folder)

我想使用 make 编译成一个库。我想在我的 makefile 中写的是:

mylib.a: obj1.o obj2.o
    ar $@ $^

这可行,但它会使文件夹变得混乱,因为它会导致以下结构:

obj1.o
obj2.o
mylib.a
src:
    obj1.cpp
    obj2.cpp
obj: 
    (empty folder)

我希望调用的结果是这样的:

mylib.a
src:
    obj1.cpp
    obj2.cpp
obj: 
    obj1.o
    obj2.o

其中两个 obj 源都被编译成 obj 中的 .o 个对象。我尝试在我的 makefile 中这样做:

vpath %.o obj
mylib.a: obj1.o obj2.o

但这与上面的结果相同。所以,我想,很确定,obj1.o 的隐式规则不知道输出到哪里,对吧?好的,所以我添加了这条规则:

%.o: %.cpp
    g++ $^ -o obj/$@

以确保我正在编译成 obj,但是,现在 make 命令失败了,我明白为什么会失败。它失败是因为 mylib 找到了 obj1.o,因为它找到了它的规则,它执行了规则,但是规则并没有导致 obj1.o 的存在,而是 [=22] 的存在=],所以当 mylib 被组合时,它的规则是 ar obj1.o obj2.o 并且它失败了。


所以,我的问题是:有没有一种简单而优雅的方法可以避免这个问题?

我看到的一个解决方案是总是有一些文件,如果需要的话是空的,在 obj 中命名为 obj1.o,但这对我来说似乎很难看。另一个是添加 "obj/" 到 mylib.a 的每个对象,但这意味着重复代码,甚至更丑陋。那么,解决这个问题的最佳方法是什么?

vpathVPATH 不适用于目标,它们适用于源。使用它们来告诉 make 目标文件应该去哪里不是一个好主意。最简单的解决方案可能是 pattern rule:

obj/%.o: src/%.c
    <your compilation rule>

在此基础上再细化一下:

SRCDIR := src
OBJDIR := obj
SRCS   := $(wildcard $(SRCDIR)/*.c)
OBJS   := $(patsubst $(SRCDIR)/%.c,$(OBJDIR)/%.o,$(SRCS))

mylib.a: $(OBJS)
    <your library building recipe>

$(OBJDIR)/%.o: $(SRCDIR)/%.c
    <your compilation recipe>

clean:
    rm -f $(OBJS) mylib.a

当然,在您的食谱中,请毫不犹豫地使用 automatic variables 和您自己声明的变量,例如 OBJS。示例:

mylib.a: $(OBJS)
    $(AR) $@ $^

$(OBJDIR)/%.o: $(SRCDIR)/%.c
    $(CC) $(CFLAGS) -c $< -o $@