告诉 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 的每个对象,但这意味着重复代码,甚至更丑陋。那么,解决这个问题的最佳方法是什么?
vpath
和 VPATH
不适用于目标,它们适用于源。使用它们来告诉 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 $@
我有一个这个玩具结构的项目:
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 的每个对象,但这意味着重复代码,甚至更丑陋。那么,解决这个问题的最佳方法是什么?
vpath
和 VPATH
不适用于目标,它们适用于源。使用它们来告诉 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 $@