user3183038
user3183038

Reputation: 57

Makefile individual header dependencies

I have the following Makefile which works fine but is not very elegant.

bin/a.gb: obj/main.o obj/i.o obj/in.o obj/g.o obj/an.o obj/s.o obj/b.o obj/b_m.o obj/b_r.o obj/b_e.o
    /opt/gbdk/bin/lcc -Iinclude -Wa-l -Wl-m -Wl-j -Wl-y -Wl-w -Wf--debug -o bin/a.gb obj/main.o obj/i.o obj/in.o obj/g.o obj/an.o obj/s.o obj/b.o obj/b_m.o obj/b_r.o obj/b_e.o

obj/main.o: src/main.c include/common.h include/i.h include/in.h include/an.h
    /opt/gbdk/bin/lcc -Iinclude -Wa-l -Wl-m -Wl-j -Wl-y -Wl-w -Wf--debug -c -o obj/main.o src/main.c

obj/i.o: src/i.c include/common.h include/i.h include/b_m.h include/b.h
    /opt/gbdk/bin/lcc -Iinclude -Wa-l -Wl-m -Wl-j -Wl-y -Wl-w -Wf--debug -c -o obj/i.o src/i.c

obj/in.o: src/in.c include/common.h include/in.h include/g.h
    /opt/gbdk/bin/lcc -Iinclude -Wa-l -Wl-m -Wl-j -Wl-y -Wl-w -Wf--debug -c -o obj/in.o src/in.c

obj/g.o: src/g.c include/common.h include/g.h
    /opt/gbdk/bin/lcc -Iinclude -Wa-l -Wl-m -Wl-j -Wl-y -Wl-w -Wf--debug -c -o obj/g.o src/g.c

obj/an.o: src/an.c include/common.h
    /opt/gbdk/bin/lcc -Iinclude -Wa-l -Wl-m -Wl-j -Wl-y -Wl-w -Wf--debug -c -o obj/an.o src/an.c

obj/s.o: src/s.c include/s.h
    /opt/gbdk/bin/lcc -Iinclude -Wa-l -Wl-m -Wl-j -Wl-y -Wl-w -Wf--debug -c -o obj/s.o src/s.c

obj/b.o: src/b.c include/b.h
    /opt/gbdk/bin/lcc -Iinclude -Wa-l -Wl-m -Wl-j -Wl-y -Wl-w -Wf--debug -c -o obj/b.o src/b.c

obj/b_m.o: src/b_m.c include/b_m.h
    /opt/gbdk/bin/lcc -Iinclude -Wa-l -Wl-m -Wl-j -Wl-y -Wl-w -Wf--debug -c -o obj/b_m.o src/b_m.c

obj/b_r.o: src/b_r.c include/b_r.h
    /opt/gbdk/bin/lcc -Iinclude -Wa-l -Wl-m -Wl-j -Wl-y -Wl-w -Wf--debug -c -o obj/b_r.o src/b_r.c

obj/b_e.o: src/b_e.c include/b_e.h
    /opt/gbdk/bin/lcc -Iinclude -Wa-l -Wl-m -Wl-j -Wl-y -Wl-w -Wf--debug -c -o obj/b_e.o src/b_e.c

.PHONY: clean

clean:
    find bin obj -type f \( -name '*.gb' -o -name '*.o' -o -name '*.ihx' -o -name '*.cdb' -o -name '*.map' -o -name '*.noi' -o -name '*.adb' -o -name '*.lst' -o -name '*.sym' -o -name '*.asm' \) -exec rm {} +

In order to make it more streamlined and generalized so that I don't have to edit it as much for every new source file, I came up with the following:

IDIR=include
BDIR=bin
ODIR=obj
SDIR=src
CC=/opt/gbdk/bin/lcc
CFLAGS=-I$(IDIR) -Wa-l -Wl-m -Wl-j -Wl-y -Wl-w -Wf--debug

DEPS := $(wildcard $(IDIR)/*)

_OBJ = an.o b_e.o b_m.o b_r.o b.o g.o i.o in.o main.o s.o
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))


$(ODIR)/%.o: $(SDIR)/%.c $(DEPS)
    $(CC) -c -o $@ $< $(CFLAGS)

$(BDIR)/a.gb: $(OBJ)
    $(CC) -o $@ $^ $(CFLAGS)

.PHONY: clean

clean:
    rm -f $(ODIR)/* *~ core $(IDIR)/*~ $(BDIR)/*

This also works. The only drawback so far is that it loses the association of which header files are dependencies for which object files. So with the original Makefile, if I changed the contents of a single header file, only the object files whose sources include that header got rebuilt. But now, if any of the header files are edited, it rebuilds all of the object files. Is there a clever way around this? I'd like for my new, streamlined Makefile to only rebuild the necessary object files if a header file is changed.

I found this solution but I'm having a hard time understanding how to incorporate it into my new Makefile. I don't understand the purpose of the -include $(ODIR)/*.d line, for instance or where that would go.

EDIT: I realize now that the solution that I linked may not work for the lcc compiler, as it does not appear to have the -MMD option (at least as far as I can tell).

Upvotes: 1

Views: 92

Answers (1)

Andreas
Andreas

Reputation: 5301

You can add any number of extra dependencies to a rule next to the declared recipe:

$(ODIR)/%.o: $(SDIR)/%.c
    $(CC) -c -o $@ $< $(CFLAGS)

$(ODIR)/an.o: $(DEPS)/dep1.h $(DEPS)/dep2.h $(DEPS)/dep3.h
$(ODIR)/b_e.o: $(DEPS)/dep1.h $(DEPS)/dep3.h

(Using patsubst to reduce the boiler plate left as student exercise)

There is also the .EXTRA_PREREQS variable in GNU Make 4.3, which is more handy when the prerequisites are not meant to be part of the recipe, https://lwn.net/Articles/810071/ :

New feature: .EXTRA_PREREQS variable

Words in this variable are considered prerequisites of targets but they are not added to any of the automatic variable values when expanding the recipe. This variable can either be global (applies to all targets) or a target-specific variable. To detect this feature search for 'extra-prereqs' in the .FEATURES special variable.

Upvotes: 1

Related Questions