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,%

我使用以下简单的Makefile来构建一些简单的文件。我对制作Makefile真的很陌生。我不知道为什么它一直在重建,即使文件是在第一次制作后生成的,我没有编辑任何文件

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
变量值。