Reputation: 57
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
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