Makefile编译多次相同的源

Yan*_*hon 3 makefile

**问题编辑**

这是一个典型的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!"
Run Code Online (Sandbox Code Playgroud)

问题:为什么线路11(@S(CC) $(TARGET) ...)在呼叫时仍然回响make

答:因为问题在默认规则中,第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)
Run Code Online (Sandbox Code Playgroud)

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

**更新2**

这是解决这个问题的好方法吗(似乎有效......)?

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

obj: $(SOURCES) $(INCLUDES)
    $(CC) $(CFLAGS) $(SOURCES)
Run Code Online (Sandbox Code Playgroud)

Bet*_*eta 5

该命令$(CC) $(CFLAGS) $(SOURCES)执行n次,因为该规则执行了n次,因为要构建n个对象,因为该$(TARGET)规则具有许多对象作为先决条件.如果希望命令仅运行一次,请使用一个PHONY先决条件替换所有这些先决条件,其先决条件的规则将执行命令.

但是没有理由这样做.您可以使命令更具选择性,以便它只构建一个作为实际目标的对象.这样Make不会浪费时间一遍又一遍地重建相同的对象,如果更改了一个或两个源文件,Make将仅重建相关对象,而不是全部:

$(OBJECTS): %.o : %.c $(INCLUDES)
  $(CC) $(CFLAGS) $<
Run Code Online (Sandbox Code Playgroud)

这个规则是保守的 - 它假设每个对象都依赖于每个头,因此它有时会不必要地重建事物.如果您了解真正的依赖关系或使用更高级的技术自动,您可以手动更好.

编辑:

您的"更新2"是一个不错的解决方案,但我建议您添加该行

.PHONY: obj
Run Code Online (Sandbox Code Playgroud)

告诉Make,没有名为"obj"的文件.否则Make会obj每次运行规则,尝试构建该文件.

这仍然存在这样的问题:如果您更改一个源文件,例如foo.c,Make将重建所有对象.

$<上面使用的I是一个自动可变的.它意味着"第一个先决条件".因此,当Make尝试构建时foo.o,它将评估为foo.c.

编辑:

杰克凯利(诅咒他!)已经指出我错误的PHONY目标是如何工作的:obj规则将始终运行,TARGET规则也是如此,无论源文件是否发生了变化.所以"更新2"方法是有效的,但粗糙.