告知目标将放在子文件夹中

时间:2019-07-12 11:36:08

标签: makefile gnu-make

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

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源都被编译成.o中的obj个对象。我尝试在我的Makefile中执行此操作:

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

,但是结果与上面相同。因此,我很确定,obj1.o的隐式规则不知道向何处输出,对吗?好的,所以我添加了以下规则:

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

以确保我编译到obj中,但是,现在make命令失败了,我知道为什么会失败。它失败是因为mylib找到obj1.o,因为它找到了它的规则,然后执行了该规则,但是该规则并没有导致obj1.o的存在,而是导致了obj/obj1.o的存在,因此在组成mylib时,其规则显示为ar obj1.o obj2.o,但失败。


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

我看到的一个解决方案是始终有一些文件,如果需要的话可以为空,在obj中命名为obj1.o,但这对我来说似乎很丑。另一个是要添加 每个要访问mylib.a的对象都使用“ obj /”,但这意味着代码会重复并且更加难看。那么,解决这个问题的最佳方法是什么?

1 个答案:

答案 0 :(得分:4)

vpathVPATH并非用于目标,它们是用于源。用它们来告诉目标文件应该放在哪里并不是一个好主意。最简单的解决方案可能是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 $@