简体   繁体   中英

Makefile builds target every time

I have written a makefile to compile all the sources in different directories and build a target. When I run make even when there is no change in the files, it does not re-compiles the unmodified files. But, it always builds the target. Why is the target alone getting built every time when I run make?

CC = gcc
CFLAGS = $(INCLUDES)
TARGET = FinalBin
OUTDIR := obj

INCLUDES = -Isrc/in
S1 = src/s1
S2 = src/s2

S1_SRC = $(wildcard $(S1)/*.c)
S2_SRC = $(wildcard $(S2)/*.c)
SRCS := $(S1_SRC) \
    $(S2_SRC)

OBJS := $(patsubst %.c,$(OUTDIR)/%.o,$(SRCS))

SRCDIRS := $(S1) $(S2)

all: $(TARGET)

$(TARGET): builddir $(OBJS)
    @echo "Building..." $@
    @$(CC) $(OBJS) $(CFLAGS) -o $@
    @echo "Build Complete!"

$(OUTDIR)/%.o: %.c
    @echo "Compiling.." $(notdir $<)
    @$(CC) $(CFLAGS) -MMD -c $< -o $@

clean:
    -@rm -rf $(OUTDIR) FinalBin
    @echo "Clean complete!"

builddir :
    @$(call create-dir)

define create-dir
    for dir in $(SRCDIRS); \
    do \
        mkdir -p $(OUTDIR)/$$dir; \
    done
endef

-include $(wildcard $(OBJS:.o=.d))

The $(TARGET) gets built from the object files each time. Please guide me where I'm going wrong.

UPDATE:

CC = gcc
CFLAGS = $(INCLUDES)
TARGET = FinalBin
OUTDIR := obj

INCLUDES = -Isrc/in
S1 = src/s1
S2 = src/s2

S1_SRC = $(wildcard $(S1)/*.c)
S2_SRC = $(wildcard $(S2)/*.c)
SRCS := $(S1_SRC) \
    $(S2_SRC)

OBJS := $(patsubst %.c,$(OUTDIR)/%.o,$(SRCS))

SRCDIRS := $(S1) $(S2)
OUTDIRS := $(addprefix $(OUTDIR)/,$(SRCDIRS))

all: $(TARGET)

$(TARGET): $(OBJS)
    @echo "Building..." $@
    @$(CC) $(OBJS) $(CFLAGS) -o $@
    @echo "Build Complete!"

$(OUTDIR)/%.o: $(OUTDIRS) %.c
    @echo "Compiling.." $(notdir $(filter %.c,$^))
    @$(CC) $(CFLAGS) -MMD -c $(filter %.c,$^) -o $@

clean:
    -@rm -rf $(OUTDIR) FinalBin
    @echo "Clean complete!"

$(OUTDIRS):
    mkdir -p $@

builddir :
    @$(call create-dir)

define create-dir
    for dir in $(SRCDIRS); \
    do \
        mkdir -p $(OUTDIR)/$$dir; \
    done
endef

-include $(wildcard $(OBJS:.o=.d))

This builds all the files every time.

Final Solution:

CC = gcc
CFLAGS = $(INCLUDES)
TARGET = FinalBin
OUTDIR := obj

INCLUDES = -Isrc/in
S1 = src/s1
S2 = src/s2

S1_SRC = $(wildcard $(S1)/*.c)
S2_SRC = $(wildcard $(S2)/*.c)
SRCS := $(S1_SRC) \
    $(S2_SRC)

OBJS := $(patsubst %.c,$(OUTDIR)/%.o,$(SRCS))

SRCDIRS := $(S1) $(S2)
OUTDIRS := $(addprefix $(OUTDIR)/,$(SRCDIRS))

all: $(TARGET)

$(TARGET): $(OUTDIRS) $(OBJS)
    @echo "Building..." $@
    @$(CC) $(OBJS) $(CFLAGS) -o $@
    @echo "Build Complete!"

$(OUTDIR)/%.o: %.c
    @echo "Compiling.." $(notdir $<)
    @$(CC) $(CFLAGS) -MMD -c $< -o $@

clean:
    -@rm -rf $(OUTDIR) FinalBin
    @echo "Clean complete!"

$(OUTDIRS):
    @mkdir -p $@

-include $(wildcard $(OBJS:.o=.d))

The final solution works as expected!

You can use the debug output of make to look for what it thinks needs rebuilding:

make -d | grep remake

You'll probably see something like this:

No need to remake target `Makefile'.
    Must remake target `builddir'.
      No need to remake target `src/s1/x.c'.
    No need to remake target `obj/src/s1/x.o'.
  Must remake target `FinalBin'.
Must remake target `all'.

Which shows that it always thinks that the builddir target needs to be remade. Since that is a dependency of $(TARGET) it rebuilds the latter as well.

If you use a rule to create your build directories instead of a function, make will know whether it needs create them or not. For example, adding the variable $(OUTDIRS) , a rule for it, and making this a dependency of compiling:

SRCDIRS := $(S1) $(S2)
OUTDIRS := $(addprefix $(OUTDIR)/, $(SRCDIRS)) # <---------- Add this variable

All: $(TARGET) 

$(TARGET):  $(OBJS)
    @echo "Building..." $@
    @$(CC) $(OBJS) $(CFLAGS) -o $@
    @echo "Build Complete!"

$(OUTDIR)/%.o: $(OUTDIRS) %.c # <--------------------------- Add dependency to $(OUTDIRS)
    @echo "Compiling.." $(notdir $<)
    @$(CC) $(CFLAGS) -MMD -c $< -o $@

clean:
    -@rm -rf $(OUTDIR) FinalBin
    @echo "Clean complete!"

$(OUTDIRS): # <--------------------------------------------- Add rule
    mkdir -p $@

-include $(wildcard $(OBJS:.o=.d))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM