Makefile 总是重建
Makefile always rebuilding
我正在使用以下简单的 Makefile 来构建一些简单的文件。我真的是制作 Makefile 的新手。我不知道为什么它一直在重建,即使文件是在第一次 make 之后构建的,而且我没有编辑任何文件。
EXE = nextgenrsm
CC = gcc
LIBS = StarterWare_Files/
CFLAGS = -c
INCLUDE_PATH = StarterWare_Files/
MAIN_SRC = $(wildcard *.c)
MAIN_OBS = $(patsubst %.c,%.o,$(MAIN_SRC))
LIB_SRC = $(wildcard StarterWare_Files/*.c)
LIB_OBS = $(patsubst StarterWare_Files/%.c,%.o,$(LIB_SRC))
output: $(EXE)
$(EXE): $(MAIN_OBS) $(LIB_OBS)
$(CC) $(MAIN_OBS) $(LIBS)$(LIB_OBS) -o $(EXE)
$(MAIN_OBS): $(MAIN_SRC)
$(CC) $(CFLAGS) *.c -I$(INCLUDE_PATH)
$(LIB_OBS): $(LIB_SRC)
cd $(LIBS); \
$(CC) $(CFLAGS) *.c -I../
clean:
rm -rf $(LIBS)*.o $(EXE) *.o
新编辑的 MAKEFILE
EXE = nextgenrsm
CC = gcc
LIBS = StarterWare_Files/
CPPFLAGS = _IStarterWare_Files/
MAIN_OBS = $(patsubst %.c,%.o,$(wildcard *.c))
LIB_OBS = $(patsubst %.c,%.o,$(wildcard StarterWare_Files/*.c))
all: $(EXE)
$(EXE): $(MAIN_OBS) $(LIB_OBS)
$(CC) -o $@ $(LDFLAGS) $(MAIN_OBS) $(LIB_OBS) $(LDLIBS)
%.o: %.c
$(CC) -o $@ -MD -MP $(CPPFLAGS) $(CFLAGS) -c $^
ALL_DEPS = $(patsubst %.o,%.d,$(MAIN_OBS), $(LIB_OBS))
-include $(ALL_DEPS)
clean:
rm -f $(LIB_OBS) $(EXE) $(MAIN_OBS) $(ALL_DEPS)
.PHONY: all clean
每当我触摸 StarterWare_Files/example.h 并尝试再次 make 时,它会抛出错误,即 gcc 无法指定 -o 与 -c 或 -S 与多个文件。基本上命令变成这样 gcc -o main.o -IStarterWare_Files -c main.c StarterWare_Files/test.h StarterWare_Files/add.h..
您的默认目标是 output
但您的 makefile 永远不会生成这样的文件,因此每次您调用 make
它都会尝试构建 output
文件。
解决方案是将 output
目标标记为 phony target。以及 clean
目标:
.PHONY: output clean
您可以利用 built-in rules that compile .o
from .c
and automatic variables 将您的 makefile 缩减为:
EXE := nextgenrsm
CC := gcc
LIBS := StarterWare_Files/
CPPFLAGS := -IStarterWare_Files
MAIN_OBS := $(patsubst %.c,%.o,$(wildcard *.c))
LIB_OBS := $(patsubst %.c,%.o,$(wildcard StarterWare_Files/*.c))
all: $(EXE)
$(EXE) : $(MAIN_OBS) $(LIB_OBS)
$(CC) -o $@ $(LDFLAGS) $^ $(LDLIBS)
clean:
rm -f $(MAIN_OBS) $(LIB_OBS) $(EXE)
.PHONY: all clean
如果您想要自动 header 依赖生成,请添加:
# This rule produces .o and also .d (-MD -MP) from .c.
%.o : %.c
$(CC) -o $@ -MD -MP $(CPPFLAGS) $(CFLAGS) -c $<
# This includes all .d files produced along when building .o.
# On the first build there are not going to be any .d files.
# Hence, ignore include errors with -.
ALL_DEPS := $(patsubst %.o,%.d,$(MAIN_OBS) $(LIB_OBS))
-include $(ALL_DEPS)
clean:
rm -f $(MAIN_OBS) $(LIB_OBS) $(EXE) $(ALL_DEPS)
问题是这样的:
$(MAIN_OBS): $(MAIN_SRC)
您已声明每个目标文件都依赖于每个源文件。图书馆的也一样。上述规则扩展为:
foo.o bar.o xyzzy.o .... : foo.c bar.c xyzzy.c ...
因此,如果任何源文件的时间戳发生变化,每个目标文件都将被重建。
你所要做的就是拥有独立的依赖关系:
# foo.o depends only on foo.c, not on bar.c
foo.o: foo.c
# bar.o depends only on bar.c, not on foo.c
bar.o: bar.c
等等。通常,这不会完成。相反,我们使用 GNU Make 的模式规则编写一个通用规则:
%.o: %c
# build commands to make .o from .c
已经有一个内置规则通常就足够了,并且可以通过更改 CC
和 CFLAGS
等变量来自定义它。
由于内置规则,简单的 makefile 通常只需要声明可执行对象和目标文件之间的依赖关系。 Make 将通过尝试各种可能性自动从目标文件中推断出先决条件。当要求评估foo.o
时,它会自动发现存在foo.c
文件,这必须是foo.o
的先决条件。然后如果 foo.o
比 foo.c
旧或者不存在,Make 将搜索其规则数据库并发现此组合匹配 %.o: %.c
模式规则,并且它将 运行其配方正文更新 foo.o
。
您应该使用 :=
风格的立即变量赋值,而不是延迟的 =
赋值。因为在 =
赋值的右侧有 $(wildcard ...)
,所以每次替换变量时,都会评估 $(wildcard ...)
语法,并遍历文件系统以查找文件。
首先不要使用$(wildcard ...)
来收集源文件。除非您以一种非常干净的方式工作,否则这将引入不需要的文件,例如您碰巧创建的一些随机 test.c
,因此 test.o
会链接到您的程序(可能成功)。显式列出所有目标文件并不需要太多努力:
OBJS := foo.o bar.o ...
对于子目录中的对象,您可以使用$(addprefix ...)
来缩短它:
OBJS := foo.o bar.o ... $(addprefix subdir/,stack.o parser.o ...)
我正在使用以下简单的 Makefile 来构建一些简单的文件。我真的是制作 Makefile 的新手。我不知道为什么它一直在重建,即使文件是在第一次 make 之后构建的,而且我没有编辑任何文件。
EXE = nextgenrsm
CC = gcc
LIBS = StarterWare_Files/
CFLAGS = -c
INCLUDE_PATH = StarterWare_Files/
MAIN_SRC = $(wildcard *.c)
MAIN_OBS = $(patsubst %.c,%.o,$(MAIN_SRC))
LIB_SRC = $(wildcard StarterWare_Files/*.c)
LIB_OBS = $(patsubst StarterWare_Files/%.c,%.o,$(LIB_SRC))
output: $(EXE)
$(EXE): $(MAIN_OBS) $(LIB_OBS)
$(CC) $(MAIN_OBS) $(LIBS)$(LIB_OBS) -o $(EXE)
$(MAIN_OBS): $(MAIN_SRC)
$(CC) $(CFLAGS) *.c -I$(INCLUDE_PATH)
$(LIB_OBS): $(LIB_SRC)
cd $(LIBS); \
$(CC) $(CFLAGS) *.c -I../
clean:
rm -rf $(LIBS)*.o $(EXE) *.o
新编辑的 MAKEFILE
EXE = nextgenrsm
CC = gcc
LIBS = StarterWare_Files/
CPPFLAGS = _IStarterWare_Files/
MAIN_OBS = $(patsubst %.c,%.o,$(wildcard *.c))
LIB_OBS = $(patsubst %.c,%.o,$(wildcard StarterWare_Files/*.c))
all: $(EXE)
$(EXE): $(MAIN_OBS) $(LIB_OBS)
$(CC) -o $@ $(LDFLAGS) $(MAIN_OBS) $(LIB_OBS) $(LDLIBS)
%.o: %.c
$(CC) -o $@ -MD -MP $(CPPFLAGS) $(CFLAGS) -c $^
ALL_DEPS = $(patsubst %.o,%.d,$(MAIN_OBS), $(LIB_OBS))
-include $(ALL_DEPS)
clean:
rm -f $(LIB_OBS) $(EXE) $(MAIN_OBS) $(ALL_DEPS)
.PHONY: all clean
每当我触摸 StarterWare_Files/example.h 并尝试再次 make 时,它会抛出错误,即 gcc 无法指定 -o 与 -c 或 -S 与多个文件。基本上命令变成这样 gcc -o main.o -IStarterWare_Files -c main.c StarterWare_Files/test.h StarterWare_Files/add.h..
您的默认目标是 output
但您的 makefile 永远不会生成这样的文件,因此每次您调用 make
它都会尝试构建 output
文件。
解决方案是将 output
目标标记为 phony target。以及 clean
目标:
.PHONY: output clean
您可以利用 built-in rules that compile .o
from .c
and automatic variables 将您的 makefile 缩减为:
EXE := nextgenrsm
CC := gcc
LIBS := StarterWare_Files/
CPPFLAGS := -IStarterWare_Files
MAIN_OBS := $(patsubst %.c,%.o,$(wildcard *.c))
LIB_OBS := $(patsubst %.c,%.o,$(wildcard StarterWare_Files/*.c))
all: $(EXE)
$(EXE) : $(MAIN_OBS) $(LIB_OBS)
$(CC) -o $@ $(LDFLAGS) $^ $(LDLIBS)
clean:
rm -f $(MAIN_OBS) $(LIB_OBS) $(EXE)
.PHONY: all clean
如果您想要自动 header 依赖生成,请添加:
# This rule produces .o and also .d (-MD -MP) from .c.
%.o : %.c
$(CC) -o $@ -MD -MP $(CPPFLAGS) $(CFLAGS) -c $<
# This includes all .d files produced along when building .o.
# On the first build there are not going to be any .d files.
# Hence, ignore include errors with -.
ALL_DEPS := $(patsubst %.o,%.d,$(MAIN_OBS) $(LIB_OBS))
-include $(ALL_DEPS)
clean:
rm -f $(MAIN_OBS) $(LIB_OBS) $(EXE) $(ALL_DEPS)
问题是这样的:
$(MAIN_OBS): $(MAIN_SRC)
您已声明每个目标文件都依赖于每个源文件。图书馆的也一样。上述规则扩展为:
foo.o bar.o xyzzy.o .... : foo.c bar.c xyzzy.c ...
因此,如果任何源文件的时间戳发生变化,每个目标文件都将被重建。
你所要做的就是拥有独立的依赖关系:
# foo.o depends only on foo.c, not on bar.c
foo.o: foo.c
# bar.o depends only on bar.c, not on foo.c
bar.o: bar.c
等等。通常,这不会完成。相反,我们使用 GNU Make 的模式规则编写一个通用规则:
%.o: %c
# build commands to make .o from .c
已经有一个内置规则通常就足够了,并且可以通过更改 CC
和 CFLAGS
等变量来自定义它。
由于内置规则,简单的 makefile 通常只需要声明可执行对象和目标文件之间的依赖关系。 Make 将通过尝试各种可能性自动从目标文件中推断出先决条件。当要求评估foo.o
时,它会自动发现存在foo.c
文件,这必须是foo.o
的先决条件。然后如果 foo.o
比 foo.c
旧或者不存在,Make 将搜索其规则数据库并发现此组合匹配 %.o: %.c
模式规则,并且它将 运行其配方正文更新 foo.o
。
您应该使用 :=
风格的立即变量赋值,而不是延迟的 =
赋值。因为在 =
赋值的右侧有 $(wildcard ...)
,所以每次替换变量时,都会评估 $(wildcard ...)
语法,并遍历文件系统以查找文件。
首先不要使用$(wildcard ...)
来收集源文件。除非您以一种非常干净的方式工作,否则这将引入不需要的文件,例如您碰巧创建的一些随机 test.c
,因此 test.o
会链接到您的程序(可能成功)。显式列出所有目标文件并不需要太多努力:
OBJS := foo.o bar.o ...
对于子目录中的对象,您可以使用$(addprefix ...)
来缩短它:
OBJS := foo.o bar.o ... $(addprefix subdir/,stack.o parser.o ...)