Makefile将来自不同目录的源文件构建到同一对象目录

时间:2018-01-08 06:26:22

标签: c makefile gnu-make

我有一个像这样的目录布局的c项目

src1
    -a.c
    -b.c
src2
    -c.c
    -d.c
objects

我正在尝试将/ b / c / d编译成对象文件并将它们保存到对象目录中,这是我的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

任何人都知道为什么会这样做?

2 个答案:

答案 0 :(得分: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中的来源。

答案 1 :(得分:2)

阅读answer of 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)

我在bash上对cygwin进行了测试:

$ 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目录的详细信息 - 只是手动创建它。)