diff --git a/Makefile b/Makefile index 9a47560..31d2d05 100644 --- a/Makefile +++ b/Makefile @@ -4,34 +4,125 @@ # Makefile # Written by Leon Krieg +# ============================================================================== +# GENERAL SETTINGS +# ============================================================================== + +SRCDIR := src +BINDIR := bin +TMPDIR := $(BINDIR)/build +TARGET := $(BINDIR)/core.hex +ELFFILE := $(BINDIR)/core.elf +LOGFILE := $(BINDIR)/core.log + +VERBOSE := false ARCH := m32 FREQ := 8000000UL MCU := atmega32a ASP := usbasp -GCC := avr-gcc +CC := avr-gcc +LD := $(CC) +OBJCOPY := avr-objcopy AVD := avrdude -RMF := rm -f -BINDIR := bin -ELFILE := $(BINDIR)/out.elf -TARGET := $(BINDIR)/core.hex -CFLAGS := -Os -std=c99 -Wall -Wextra -Werror +MKDIR := mkdir -p +RMR := rm -rf + CPPFLAGS := -DF_CPU=$(FREQ) +CFLAGS := -mmcu=$(MCU) -Os -std=c99 -Wall -Wextra -Werror +OCFLAGS := -j .text -j .data -O ihex +LDFLAGS := -mmcu=$(MCU) +LDLIBS := + +# ============================================================================== +# TARGET FILE LISTS (DERIVED FROM SOURCE TREE) +# ============================================================================== + +PATHS := $(shell find "$(SRCDIR)" -type d -printf '%P ' 2>/dev/null) +FILES := $(shell find "$(SRCDIR)" -type f -name "*.c" -printf '%P ' 2>/dev/null) +TMPDIRS := $(BINDIR) $(TMPDIR) $(PATHS:%=$(TMPDIR)/%) +OBJECTS := $(FILES:%.c=$(TMPDIR)/%.o) +DEPENDS := $(FILES:%.c=$(TMPDIR)/%.d) + +# ============================================================================== +# AUXILIARY TARGETS (AND FUSE SETTINGS) +# ============================================================================== .PHONY: all all: flash .PHONY: flash flash: $(TARGET) - $(AVD) -c $(ASP) -p $(ARCH) \ - -U lfuse:w:0xff:m \ - -U hfuse:w:0x99:m \ + $(E) "[AVD] Flashing..." + $(Q) $(AVD) -l $(LOGFILE) \ + -c $(ASP) -p $(ARCH) \ + -U lfuse:w:0xff:m \ + -U hfuse:w:0x99:m \ -U flash:w:$(TARGET) -$(TARGET): src/main.c - $(GCC) -o $(ELFILE) $(CFLAGS) $(CPPFLAGS) $^ -mmcu=$(MCU) - avr-objcopy -j .text -j .data -O ihex $(ELFILE) $@ - avr-size --format=avr --mcu=$(MCU) $@ - +.PHONY: clean clean: - $(RMF) $(TARGET) - $(RMF) $(ELFILE) + $(E) "[REM] $(TARGET)" + $(Q) $(RMR) $(TARGET) + $(E) "[REM] $(ELFFILE)" + $(Q) $(RMR) $(ELFFILE) + $(E) "[REM] $(LOGFILE)" + $(Q) $(RMR) $(LOGFILE) + $(E) "[REM] $(TMPDIR)" + $(Q) $(RMR) $(TMPDIR) + +.PHONY: distclean +distclean: clean + $(E) "[REM] $(BINDIR)" + $(Q) $(RMR) $(BINDIR) + +$(TMPDIRS): + $(E) "[DIR] $@" + $(Q) $(MKDIR) $@ + +# ============================================================================== +# PRIMARY BUILD TARGET AND PATTERN RULES +# ============================================================================== + +# We must expand the prerequisite lists a second time to resolve path variable +# $(@D). This means folders can be set as explicit dependencies and created in +# the $TMPDIRS rule. This is better than relying on Make to honor the order of +# prerequisites for the primary target and we will not have to call mkdir for +# each build step preemptively. + +.SECONDEXPANSION: + +$(TARGET): $(ELFFILE) | $$(@D) + $(E) "[HEX] $@" + $(Q) $(OBJCOPY) $(OCFLAGS) $< $@ + +$(ELFFILE): $(OBJECTS) $(DEPENDS) | $$(@D) + $(E) "[ELF] $@" + $(Q) $(LD) -o $@ $(LDFLAGS) $(OBJECTS) $(LDLIBS) + +$(TMPDIR)/%.o: $(SRCDIR)/%.c | $$(@D) + $(E) "[OBJ] $@" + $(Q) $(CC) -c -o $@ $(CFLAGS) $(CPPFLAGS) $< + +$(TMPDIR)/%.d: $(SRCDIR)/%.c | $$(@D) + $(E) "[DEP] $@" + $(Q) $(CC) -c -o $@ $(CFLAGS) $(CPPFLAGS) -MM -MT $(@:.d=.o) $< + +# ============================================================================== +# MAKE PREPROCESSOR INCLUDES AND CONDITIONALS +# ============================================================================== + +# Load header dependency rules +include $(wildcard $(DEPENDS)) + +# Sanity check +ifeq ($(strip $(OBJECTS)),) +$(error No sources found in '$(SRCDIR)/') +endif + +# Handle verbosity setting +ifneq ($(VERBOSE), false) +E = @true +else +E = @echo +Q = @ +endif