DragonDePlatino
DragonDePlatino

Reputation: 159

Makefile not building when updating source

I've recently picked up makefiles and am trying to automate my build process. For this makefile, I want it to find every xxx/src/xxx.c source file and build an equivalent xxx/obj/xxx.o object for each. So every obj folder mirrors the layout of a src folder.

This is working as intended but only if I clean and make. Modifying a source file and running make won't rebuild that file. I think it might have to do with my subst in the dependecy of %.o, but I don't know how to modify that and still have my automated build layout work.

CFLAGS := -std=c11 -pedantic -Wall -Wextra -O3
LIBARIES := -lm -lglut -lGL

INCDIR := include ../plib/include
SRCDIR := src ../plib/src

INC := $(foreach d, $(INCDIR),-I$d)
SRC := $(wildcard $(foreach d, $(SRCDIR),$d/*.c $d/*/*.c))
OBJ := $(subst src/,obj/, $(SRC:.c=.o))
EXE := bin/test

$(EXE): $(OBJ)
    gcc -o $@ $(OBJ) $(LIBARIES)
    $@

%.o: $(subst obj/,src/,$(%.c))
    @mkdir -p $(@D)
    gcc -o $@ -c $(subst obj/,src/,$(@:.o=.c)) $(CFLAGS) $(INC)

.PHONY: clean

clean:
    rm $(EXE)
    rm $(OBJ)

Upvotes: 3

Views: 884

Answers (3)

ensc
ensc

Reputation: 6984

You can solve such a %/xxxx/% pattern replacement by iterating over the SRCDIR:

define genrule
_prefix := $$(subst src,obj,$1/)
$$(filter $${_prefix}%.o,$$(OBJ)):\
$${_prefix}%.o: $1/%.c
endef

$(foreach d,${SRCDIR},$(eval $(call genrule,$d)))

${OBJ}:
          gcc ... -c $< -p $@

Upvotes: 3

user3629249
user3629249

Reputation: 16540

The posted makefile is rather 'iffy' for several different reasons

The following proposed makefile is VERY EASILY modified for other projects BUT does place the object files in the same directory as the source files. You might want to 'tweak' that feature

And now, the proposed makefile

SHELL   :=  /bin/sh
CC      :=  /usr/bin/gcc
RM      :=  /usr/bin/rm
MAKE    :=  /usr/bin/make

CFLAGS := -std=c11 -pedantic -Wall -Wextra -O3
LIBS   := -lm -lglut -lGL

INC :=   -Iinclude/ -I../plib/
SRC :=   $(wildcard src/*.c)  $(wildcard ../plib/src/*.c)
OBJ :=   $(SRC:.c=.o))
DEP :=   $(SRC:.c=.d)
EXE :=   bin/test

.PHONY: all clean

all: $(EXE)

$(EXE): $(OBJ)
    #
    # ======= $(EXE) Link Start =========
    $(CC) $(LDFLAGS) -o $@ $(OBJ) $(LIBS)
    # ======= $(EXE) Link Done ==========
    #


#
# create dependancy files
#
%.d: %.c
    # 
    # ========= START $< TO $@ =========
    $(CC) -M $(CPPFLAGS) $< > $@.$$$$;                      \
    sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@;     \
    (RM) -f $@.$$$$
    # ========= END $< TO $@ =========

#
# compile the .c files into .o files using the compiler flags
#
%.o: %.c %.d 
    # 
    # ========= START $< TO $@ =========
    $(CC) $(CFLAGS) -c $< -o $@ $(INC)
    # ========= END $< TO $@ =========
    # 


clean: 
    # ========== start clean activities ==========
    rm -f *.o
    rm -f $(EXE)
    rm -f *.d
    # ========== end clean activities ==========


# include the contents of all the .d files
# note: the .d files contain:
# <filename>.o:<filename>.c plus all the dependancies for that file 
# I.E. the #include'd header files
# wrap with ifneg... so will not rebuild *.d files when goal is 'clean'
#
ifneq "$(MAKECMDGOALS)" "clean"
-include $(DEP)
endif

Upvotes: 1

Beta
Beta

Reputation: 99094

You can do it with secondary expansion. It's not elegant, but it works:

.SECONDEXPANSION:
%.o: $$(addsuffix .c,$$(basename $$(subst /obj/,/src/,$$@)))
    @echo building $@ from $^
    @mkdir -p $(@D)
    gcc -o $@ -c $< $(CFLAGS) $(INC)

Upvotes: 1

Related Questions