我有一个具有这种玩具结构的项目:
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 /”,但这意味着代码会重复并且更加难看。那么,解决这个问题的最佳方法是什么?
答案 0 :(得分:4)
vpath
和VPATH
并非用于目标,它们是用于源。用它们来告诉目标文件应该放在哪里并不是一个好主意。最简单的解决方案可能是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 $@