Makefile始终在重建
我使用以下简单的Makefile来构建一些简单的文件。我对制作Makefile真的很陌生。我不知道为什么它一直在重建,即使文件是在第一次制作后生成的,我没有编辑任何文件Makefile始终在重建,makefile,gnu-make,Makefile,Gnu Make,我使用以下简单的Makefile来构建一些简单的文件。我对制作Makefile真的很陌生。我不知道为什么它一直在重建,即使文件是在第一次制作后生成的,我没有编辑任何文件 EXE = nextgenrsm CC = gcc LIBS = StarterWare_Files/ CFLAGS = -c INCLUDE_PATH = StarterWare_Files/ MAIN_SRC = $(wildcard *.c) MAIN_OBS = $(patsubst %.c,%
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不能用-c指定-o,或用多个文件指定-S。基本上,该命令类似于gcc-o main.o-IStarterWare_Files-c main.c StarterWare_Files/test.h StarterWare_Files/add.h..您的默认目标是
output
,但您的makefile从不生成这样的文件,因此每次调用make
时,它都会尝试构建output
文件
解决方案是将输出
目标标记为。以及clean
目标:
.PHONY: output clean
您可以利用该功能从
.c
编译.o
,并将生成文件缩减为:
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
如果您希望自动生成标题依赖项,请添加:
# 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)
#此规则从.c生成.o和.d(-MD-MP)。
%.o:%.c
$(CC)-o$@-MD-MP$(CPPFLAGS)$(CFLAGS)-c$<
#这包括生成.o时生成的所有.d文件。
#在第一次构建时,不会有任何.d文件。
#因此,忽略包含带有-的错误。
所有部门:=$(patsubst%.o、%.d、$(主对象)$(库对象))
-包括$(所有部门)
清洁:
rm-f$(主对象)$(库对象)$(EXE)$(所有部门)
问题在于:
$(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
您应该使用:=
样式的立即变量赋值,而不是延迟的=
赋值。因为在=
赋值的右侧有$(通配符…
),所以每次替换变量时,都会计算$(通配符…
语法,并遍历文件系统以查找文件
不要首先使用$(通配符…
来收集源文件。除非您以一种非常干净的方式工作,否则这将引入不需要的文件,例如您碰巧创建的一些随机的test.c
,因此test.o
将链接到您的程序(可能成功)。显式列出所有对象文件不需要花费太多精力:
OBJS := foo.o bar.o ...
对于子目录中的对象,可以使用$(addprefix…
缩短它:
OBJS := foo.o bar.o ... $(addprefix subdir/,stack.o parser.o ...)
正在重建
$(主对象)
<代码>$(LIB_OBS)<代码>$(EXE)?都是吗?运行make-d
并查看输出,它将告诉您它认为需要重建的内容以及原因。您的makefile也不正确。它告诉make,每个.o
文件都将每个.c
文件作为先决条件,而不仅仅是其匹配文件。因此,更改任何.c
文件都将重新编译该集中的每个.o
文件。@EtanReisner是的,它正在构建所有这些文件。如何做出改变?它只引用自己的C文件。它可能只是再次构建$(LIB_OBS)
文件。这是因为当您设置$(LIB_OBS)
的值时,您从.c
文件中删除了目录前缀,但随后您让目标生成目录中的.o
文件,因此make无法匹配这些文件(因为foo.o
与StarterWare\u文件/foo.o
不同)@EtanReisner谢谢你指出这一点out@EtanReisner$^的意义是什么?如果为true,则不会导致它重新编译任何内容,前提是其他目标正确创建了其目标文件(它们似乎是这样做的)。哦,不,$(LIB_OBS)
的名字里没有目录。$是的,我得自己定期查一下。我相信BSD使用命名变量来避免这种混淆。%.o
目标中的$^
不正确。它必须是$@EtanReisner,我的$助记符这是个问题,但不是问题。问题在于LIB_OBS
变量值。