Makefile可以将来自不同目录的源文件构建到同一个目标目录中。

3
我有一个C项目,目录结构如下:
src1
    -a.c
    -b.c
src2
    -c.c
    -d.c
objects

我正在尝试将a/b/c/d编译为目标文件并保存到objects目录中,以下是我的Makefile的一部分。
src1 = src1/
src1 = src2/
obj = objects/
src1_files = a.c b.c
src2_files = c.c d.c
source_files = $(addprefix $(src1), $(src1_files)) $(addprefix $(src1), $(src2_files)) 
objects := $(addprefix $(obj), $(src1_files:.c=.o)) $(addprefix $(obj), $(src2_files:.c=.o))

$(obj)%.o: $(source_files)
    $(CC) $(CFLAGS) -c $< -o $@

all: $(objects)

然而,当我尝试运行make时,我得到了以下结果。
gcc -Wall -c src1/a.c -o objects/a.o
gcc -Wall -c src1/a.c -o objects/b.o
gcc -Wall -c src1/a.c -o objects/c.o
gcc -Wall -c src1/a.c -o objects/d.o

有人知道为什么会这样吗?


1
$(addprefix $(src1), $(src2_files) --> $(addprefix $(src2), $(src2_files) - Gaurav Pathak
@Gaurav 这还不够。 - user2371524
这是我在阅读 Makefile 时遇到的问题。我必须执行 Makefile 来捕获任何其他问题。! :-| - Gaurav Pathak
还有一个错别字:src1 = src2/(在第二行)。 - Scheff's Cat
@Gaurav 当然是正确的,但是除了错别字之外,这个Makefile还存在一个概念上的错误,它永远不会像这样工作 ;) - user2371524
@FelixPalmen,是的,我看了你的回答!很好的解释。 - Gaurav Pathak
2个回答

3

阅读了Felix Palmen的答案,特别是最后一句话之后。

如果你确实想要将对象直接放在你的对象目录中,那么你需要两个模式规则,一个匹配src1中的源文件,一个匹配src2中的源文件。

出于好奇,我相应地修改了Makefile

src1 = src1/
src2 = src2/
obj = objects/
src1_files = a.c b.c
src2_files = c.c d.c
source_files = $(addprefix $(src1), $(src1_files)) $(addprefix $(src2), $(src2_files)) 
objects := $(addprefix $(obj), $(src1_files:.c=.o)) $(addprefix $(obj), $(src2_files:.c=.o))

$(obj)%.o: src1/%.c
    $(CC) $(CFLAGS) -c $< -o $@

$(obj)%.o: src2/%.c
    $(CC) $(CFLAGS) -c $< -o $@

all: $(objects)

我在cygwin上的bash中进行了测试:

$ mkdir src1 src2 objects

$ touch src1/a.c src1/b.c src2/c.c src2/d.c

$ make
cc  -c src1/a.c -o objects/a.o
cc  -c src1/b.c -o objects/b.o
cc  -c src2/c.c -o objects/c.o
cc  -c src2/d.c -o objects/d.o

$ 

...然后它就起作用了。

(我省略了有关构建objects目录的细节 - 只是手动创建了它。)


没错,这就是我在上一个段落中简要描述的内容。不过我不建议这种方法,至少如果源目录数量以后会增加的话,但它确实可行 :) (因此回答了直接的问题)。 - user2371524
这是我的意图,以展示您所建议的内容。也许,我应该更清楚地陈述我的答案作为补充说明。 - Scheff's Cat
我明白了,只是想确认这就是我的意思!(并且对于这是否是“正确的做法”存在疑虑,但这当然取决于具体情况);) - user2371524

2
这不是模式规则的工作方式。在尝试使用您的规则构建对象文件时,make会尝试将先决条件中的%替换为与目标中的%匹配的任何内容,但是您的先决条件中没有包含%,因此它只是按字面意义解释。在您的配方中,您只需从先决条件列表中取出第一个($<),这始终是相同的。
最简单的方法是在对象目录下复制目录结构,这正是大多数Makefile实际执行的操作。类似于这样:
objects := $(addprefix $(obj), $(source_files:.c=.o))

$(obj)%.o: %.c
    $(CC) $(CFLAGS) -c $< -o $@

您需要确保目录存在,例如像这样(未经测试):

objdirs := $(obj)$(src1) $(obj)$(src2)

$(objdirs):
    mkdir -p $@

$(obj)%.o: %.c | $(objdirs)
    $(CC) $(CFLAGS) -c $< -o $@

如果你真的想让对象直接放在你的objects目录中,你需要两个模式规则,一个匹配src1中的源文件,另一个匹配src2中的源文件。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接