问题 - 具有多个目标的规则
你的规则
$(OBJECTS): $(SOURCES)
$(CC) $(CFLAGS) -c $< -o $@
有多个目标。我认为这在这里不合适。请参阅here 讨论,了解多目标规则的用处。
此外,此规则指定了多个先决条件 - 但$<仅代表第一个先决条件。您可以使用$+ 来捕获所有先决条件 - 但随后您将无法使用-o 选项。如果您想使用多个先决条件,请参阅下文。
$(OBJECTS): $(SOURCES)具体是什么意思
例如,假设您的src/ 目录包含firstsource.c 和secondsource.c。那么你的变量就变成了
$(SOURCES) -> src/firstsource.c src/secondsource.c
$(OBJECTS) -> obj/firstsource.o obj/secondsource.o
(实际上 - 并且有点不直观 - firstsource 将放置在 secondsource 之后,但为了简单起见,我们忽略它。)
所以规则
$(OBJECTS): $(SOURCES)
$(CC) $(CFLAGS) -c $< -o $@
等价于
obj/firstsource.o obj/secondsource.o: src/firstsource.c src/secondsource.c
$(CC) $(CFLAGS) -c $< -o $@
反过来,这条规则相当于两条规则(因为它有多个目标)——每条规则都有相同的先决条件:
obj/firstsource.o: src/firstsource.c src/secondsource.c
$(CC) $(CFLAGS) -c $< -o $@
obj/secondsource.o: src/firstsource.c src/secondsource.c
$(CC) $(CFLAGS) -c $< -o $@
你能看出这里的问题吗?
由于$<仅代表第一个先决条件,因此第一个规则的配方变为
gcc -Isrc -c src/firstsource.c -o obj/firstsource.o
第一个规则没问题,第二个规则就不行了
gcc -Isrc -c src/firstsource.c -o obj/secondsource.o
因为你使用了错误的输入文件。
顺便说一句……你提到了
不幸的是 [i.e. make] 只对第一个检测到的文件执行命令并停在那里。
这是因为 - 当您在不带任何参数的情况下调用 make 时 - 它会调用文件中的第一条规则,仅此而已。
选项 1:使用多个规则
这里更适合的是多个规则——每个规则只有一个单个目标。因此,请尝试将上面的内容替换为以下内容。
$(OBJ)/%.o: $(SRC)/%.c
$(CC) $(CFLAGS) -c $< -o $@
compile-only: $(OBJECTS)
您可以在此修改后的 Makefile 上调用 make
make -B compile-only
选项 2:具有多个先决条件的单一目标
如果您的目标中有多个先决条件,您可以使用特殊变量 $+ 在配方中引用它们。但是,在这种情况下,您不能使用 -o 选项 - 因此将无法指定目标文件的输出目录。 (要解决这个问题,您可以在编译之前将cd 转到obj 目录 - 但随后您需要调整SOURCES 变量。)
CC := gcc
CFLAGS := -Isrc
SRC := src
SOURCES := $(wildcard $(SRC)/*.c)
myobjs: $(SOURCES)
$(CC) $(CFLAGS) -c $+
这会将所有目标文件放在顶级目录中。如前所述,如果您必须将目标文件放在单独的目录中,您可以调整SOURCES 和cd 的obj 目录。
除此之外 - 模式规则的预定义配方
我理解将构建输出放在单独目录中的理由,但是 - 如果您愿意将构建输出与源文件放在同一目录中 - 您可以使用make 的predefined pattern rules 简化您的Makefile。
SOURCES := $(wildcard $(SRC)/*.c)
OBJECTS := $(SOURCES:.c=.o)
compile: $(OBJECTS)