Makefile总是在重建

时间:2015-06-26 19:54:31

标签: 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,%.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并尝试再次制作时,它会抛出gcc无法指定-o with -c或-S with Multiple files的错误。基本上命令变成这样的东西gcc -o main.o -IStarterWare_Files -c main.c StarterWare_Files / test.h StarterWare_Files / add.h ..

2 个答案:

答案 0 :(得分:13)

您的默认目标是output,但您的makefile永远不会生成这样的文件,因此每次调用make时,它都会尝试构建output文件。

解决方案是将output目标标记为phony target。以及clean目标:

.PHONY: output clean

您可以利用从.obuilt-in rules汇编.c的{​​{3}}将您的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   

如果您希望自动生成标头依赖关系,请添加:

# 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)

答案 1 :(得分:1)

问题在于:

$(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

已经有一个内置规则,通常就足够了,可以通过更改CCCFLAGS等变量对其进行自定义。

由于内置规则,简单的makefile通常只需要声明可执行对象和目标文件之间的依赖关系。 Make将通过尝试各种可能性自动从目标文件中推导出先决条件。当系统要求您评估foo.o时,它会自动发现存在foo.c文件,该文件必须是foo.o的先决条件。然后,如果foo.o早于foo.c或者不存在,那么Make将搜索其规则数据库并发现此组合符合%.o: %.c模式规则,并且它将运行其配方主体更新foo.o

您应该使用:=样式立即变量赋值而不是延迟=赋值。因为$(wildcard ...)赋值的右侧有=,所以每次替换变量时,都会评估$(wildcard ...)语法,并遍历文件系统以查找文件。 / p>

首先不要使用$(wildcard ...)来收集源文件。除非你以一种精心干净的方式工作,否则会引入不需要的文件,例如你碰巧创建的一些随机test.c,因此test.o会链接到你的程序(可能成功)。明确列出所有目标文件并不需要花费太多精力:

OBJS := foo.o bar.o ...

对于子目录中的对象,您可以使用$(addprefix ...)来缩短它:

OBJS := foo.o bar.o ... $(addprefix subdir/,stack.o parser.o ...)