Makefile编译多次相同的源文件

3

这是一个典型的Makefile模板:

TARGET   = my_prog               # project name

CC       = gcc -o
CFLAGS   = -Wall
SOURCES  := $(wildcard *.c)
INCLUDES := $(wildcard *.h)
OBJECTS  := $(SOURCES:.c=*.o)
rm       = rm -f

$(TARGET): $(OBJECTS)
    @$(CC) $(TARGET) $(CFLAGS) $(SOURCES)
    @echo "Compilation complete!"

clean:
    @$(rm) $(TARGET) $(OBJECTS)
    @echo "Cleanup complete!"

问题: 为什么在调用make时,第11行(@S(CC) $(TARGET) ...)仍然会回显?

答案: 因为问题出现在默认规则中,而第11行没有问题。

** 更新 **

我现在有这个Makefile

# project name
TARGET   = my_prog

CC       = gcc -c
CFLAGS   = -Wall -I.
LINKER   = gcc -o
LFLAGS   = -Wall
SOURCES  := $(wildcard *.c)
INCLUDES := $(wildcard *.h)
OBJECTS  := $(SOURCES:.c=*.o)
rm       = rm -f

$(TARGET): $(OBJECTS)
    $(LINKER) $(TARGET) $(LFLAGS) $(OBJECTS)

$(OBJECTS): $(SOURCES) $(INCLUDES)
    $(CC) $(CFLAGS) $(SOURCES)

clean:
    $(rm) $(TARGET) $(OBJECTS)

问题:为什么$(CC) $(CFLAGS) $(SOURCES)会被执行n次,其中n是源文件的数量?

** 更新2 **

这种方法是否可行(似乎可以解决问题...)?

$(TARGET): obj
    $(LINKER) $(TARGET) $(LFLAGS) $(OBJECTS)

obj: $(SOURCES) $(INCLUDES)
    $(CC) $(CFLAGS) $(SOURCES)

@Beta,GNU。我正在运行Linux。 - Yanick Rochon
2个回答

5
命令$(CC) $(CFLAGS) $(SOURCES)会执行n次,因为规则被执行了n次,因为有n个对象需要构建,因为$(TARGET)规则有这么多对象作为前提条件。如果您希望该命令仅运行一次,请用单个PHONY前提条件替换所有这些前提条件,其规则执行该命令。
但没有理由这样做。您可以使命令更具选择性,以便仅构建实际目标的一个对象。这样,Make不会浪费时间反复重建相同的对象,如果更改了一两个源文件,Make将仅重新构建相关对象,而不是全部对象:
$(OBJECTS): %.o : %.c $(INCLUDES)
  $(CC) $(CFLAGS) $<

这个规则是保守的--它假设每个对象都依赖于每个头文件,所以有时会不必要地重新构建东西。如果您知道真正的依赖关系,可以手动改进它,或者使用更先进的技术自动改进它。
编辑:您的“更新2”是一个不错的解决方案,但我建议您添加以下行:
.PHONY: obj

告诉Make不会有名为“obj”的文件。否则,每次Make都会运行obj规则,试图构建该文件。
这仍然存在一个问题,即如果更改一个源文件(例如foo.c),则Make将重建所有对象。
我上面使用的$<是一个自动变量。它表示“第一个先决条件”。因此,当Make尝试构建foo.o时,它将计算为foo.c编辑:
Jack Kelly(诅咒他!)指出我对PHONY目标的工作方式是错误的:无论是否更改了任何源文件,obj规则和TARGET规则始终会运行。因此,“更新2”方法是有效的,但粗糙。

是的,我看到问题了(请参见我的“更新2”)。顺便问一下,命令末尾的$<是什么意思? - Yanick Rochon
1
你现在正式成为我的劲敌了。你总是第一个出现并给出几乎无法攻击的答案 :-)。我不太愿意用“更新2”风格来处理事情,因为一旦你把 obj 搞虚假了,它每次运行 make 时都会重新链接。make 设计得很擅长跟踪文件,所以只需让它跟踪这些文件即可! - Jack Kelly

1

我认为输出来自生成 .o 文件,而不是生成 my_prog。

看起来你没有创建 .o 文件的规则,所以 make 正在使用默认规则。

尝试将以下内容放入:

@echo "starting compilation"

在你的第11行构建命令之前的那一行

你可以看到,在gcc命令之后输出了“开始编译”。

也许第10行应该写成:

$(TARGET): $(SOURCES)

?


+1 我觉得很有趣的是,你可以用一个简单的工具实现许多不同的结果...它现在正常工作了!但它不再创建任何.o文件。我也不太介意... - Yanick Rochon
如果你想要制作目标文件,那是可以的。只是如果你想要无声地制作它们,你就必须创建一个构建规则。 - JasonWoof

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