makefile:从不同的src dir编译为单独的obj dir

makefile:从不同的src dir编译为单独的obj dir,makefile,Makefile,这是一个单元测试生成文件。已建立的目录结构为: srca/ contains sources srcb/ contains sources test/ contains UT sources and Makefile test/Debug is to contain objects 如果我不在乎对象(.o、.gcda等)是在测试中创建的,那么我可以让它工作,如下所示: .PHONY = all build all: build vpath %.c ../srca ../srcb SRC =

这是一个单元测试生成文件。已建立的目录结构为:

srca/ contains sources
srcb/ contains sources
test/ contains UT sources and Makefile
test/Debug is to contain objects
如果我不在乎对象(.o、.gcda等)是在测试中创建的,那么我可以让它工作,如下所示:

.PHONY = all build
all: build
vpath %.c ../srca ../srcb

SRC = \
    ../srca/a.c \
    ../srcb/b.c \
    test.c

OBJDIR=
OBJ = $(addprefix $(OBJDIR),$(notdir $(patsubst %.c, %.o , $(SRC))))

$(OBJ): $(OBJDIR)/%.o : %.c

Debug/UnitTest.exe: $(OBJ)
    gcc $(OBJ) -o ./Debug/UnitTest.exe

build: Debug/UnitTest.exe
test1.mk:16: target `Debug/a.o' doesn't match the target pattern
当我试图通过将OBJDIR设置为Debug/将对象构建到Debug中时,会出现如下错误:

.PHONY = all build
all: build
vpath %.c ../srca ../srcb

SRC = \
    ../srca/a.c \
    ../srcb/b.c \
    test.c

OBJDIR=
OBJ = $(addprefix $(OBJDIR),$(notdir $(patsubst %.c, %.o , $(SRC))))

$(OBJ): $(OBJDIR)/%.o : %.c

Debug/UnitTest.exe: $(OBJ)
    gcc $(OBJ) -o ./Debug/UnitTest.exe

build: Debug/UnitTest.exe
test1.mk:16: target `Debug/a.o' doesn't match the target pattern
设置OBJ的线是从另一个stackoverflow柱上提起的,我承认我没有遵循它,但在上述情况下它是有效的。此外,当OBJDIR为空时,不需要以下行:

$(OBJ): $(OBJDIR)/%.o : %.c
但如果我在OBJDIR为“Debug/”时省略它,我会得到


因此,当OBJDIR不是空的,但还不够时,该规则会有所帮助。

您对
OBJDIR
(空字符串)、
OBJ
patsubst
)和
%.o:%.c
规则的定义是问题的主要原因。在您的示例中,
OBJ
的值为:

a.o b.o test.o
您的
%.o:%.c
规则扩展为:

a.o b.o test.o: /%.o : %.c
实际上,
a.o b.o test.o
/%.o
模式不匹配。您应该将
OBJDIR
OBJ
的定义替换为:

OBJDIR = .
OBJ = $(addprefix $(OBJDIR)/,$(notdir $(patsubst %.c,%.o,$(SRC))))
注意,我还在调用
patsubst
函数时删除了空格:使用
make
时,空格必须小心处理。避免将空格放在不需要的地方,这样可以避免由于变量值中的前导空格或尾随空格而导致的难以理解和修复的细微错误

如果将
OBJDIR
设置为
以外的其他值,例如
Debug
,您将遇到另一个问题:隐式规则不能像这样工作,您必须添加显式配方:

$(OBJ): $(OBJDIR)/%.o : %.c
    gcc -c $< -o $@
$(OBJ):$(OBJDIR)/%.o:%.c
gcc-c$<-o$@

对于记录,以下是工作生成文件:

.PHONY = all build
all: build
vpath %.c ../srca ../srcb

SRC = \
    ../srca/a.c \
    ../srcb/b.c \
    test.c

OBJDIR=Debug/
OBJ = $(addprefix $(OBJDIR),$(notdir $(patsubst %.c,%.o,$(SRC))))

$(OBJ): $(OBJDIR)%.o : %.c
    gcc -c $< -o $@

Debug/UnitTest.exe: $(OBJ)
    gcc $(OBJ) -o ./Debug/UnitTest.exe

build: Debug/UnitTest.exe
.PHONY=所有构建
全部:构建
vpath%.c../srca../srcb
SRC=\
../srca/a.c\
../srcb/b.c\
测试c
OBJDIR=Debug/
OBJ=$(addprefix$(OBJDIR),$(notdir$(patsubst%.c,%.o,$(SRC)))
$(OBJ):$(OBJDIR)%.o:%.c
gcc-c$<-o$@
Debug/UnitTest.exe:$(OBJ)
gcc$(OBJ)-o./Debug/UnitTest.exe
生成:Debug/UnitTest.exe

这与C语言或标准有什么关系?您是否在
OBJDIR
中加了斜杠?@Beta:我使用了空字符串和“/”,两者都有效,而“Debug/”,两者都不起作用(导致关于不匹配模式的错误消息)。当OBJDIR为空(或“/”)时,它会起作用。当OBJDIR为“Debug/”时失败。请解释为什么它在这种情况下失败,这就是我要问的情况。谢谢你关于空格的观点。我不明白它怎么可能与空白的
OBJDIR
一起工作(出于我解释的原因)。在你的问题和你使用的东西之间一定有细微的区别。或者一个我还不知道的版本。In不适用于
OBJDIR=Debug/
,因为您不告诉make,例如,如何从
。/srca/a.c
构建
Debug/a.o
(隐式规则不包括这种情况)。添加一个明确的配方:
gcc-c$<-o$@
,对于
OBJDIR=Debug/
您在我的回答中遇到了相同的问题:规则扩展为:
Debug/a.o Debug/b.o Debug/test.o:Debug//%.o:%.c
由于双斜杠,所以没有匹配项。您可能想知道为什么它与
OBJDIR=./
一起工作,而
/a.o
之间也应该存在匹配错误和
//%.o
。答案可能是:“从文件名中去掉“/”的前导序列,以便将
/file
file
视为同一个文件”。我想任何数量为
///x
/
都被认为与
x
相同。你说得对,有一点不同:当它使用OBJDIR blank时,“$(OBJ):”行被注释掉了。用正确的咒语添加明确的规则,谢谢!