#### Configuration #### {{{1

name       = test
cpu        = lpc1756

srcdirs    = .
incdirs    = .
haldir     =
objdir     = build
depdir     = build
targetdir  = .

src_c      = test.c commandline.c version.c
src_asm    =
libs       =

cflags_in := $(CFLAGS)
CFLAGS     = -Wall

#### Build Variables #### {{{1

CC        = gcc
depflags  = -MMD -MP -MF $(depdir)/$*.d

#### Functions #### {{{1

tr      = $(shell echo $(1) | tr $(2) $(3))
toupper = $(call tr,$(1),'[:lower:]','[:upper:]')
tolower = $(call tr,$(1),'[:upper:]','[:lower:]')

define rmdir =
	if [ -d '$(1)' ]; then \
		rmdir -p --ignore-fail-on-non-empty '$(abspath $(1))'; \
	fi

endef

#### Calculated Variables #### {{{1

# Prerequisites
cpu_lower     := $(call tolower,$(cpu))

# Files
target         = $(targetdir)/$(name)
src            = $(src_c) $(src_asm)
obj_c          = $(src_c:%.c=%.o)
obj_asm        = $(src_asm:%.S=%.o)
obj            = $(obj_c) $(obj_asm)
deps           = $(obj:%.o=%.d)
objects_c      = $(addprefix $(objdir)/, $(obj_c))
objects_asm    = $(addprefix $(objdir)/, $(obj_asm))
objects        = $(objects_c) $(objects_asm)
dependencies   = $(addprefix $(depdir)/, $(deps))

# HAL
ifneq ($(strip $(haldir)),) # This check is necessary to avoid matching root
                            # when $(haldir) is empty
  hal_cpudir  = $(haldir)/$(cpu_lower)
  ifeq ($(wildcard $(hal_cpudir)/.),)
    $(warning warning: HAL directory '$(hal_cpudir)' does not exist)
  else
    hal_srcdir  = $(hal_cpudir)/src
    hal_incdir  = $(hal_cpudir)/include
    ifneq ($(wildcard $(hal_srcdir)/.),)
      srcdirs += $(hal_srcdir)
    endif
    ifneq ($(wildcard $(hal_incdir)/.),)
      incdirs += $(hal_incdir)
    endif
  endif
endif

# Directories
indirs        := $(sort $(srcdirs) $(incdirs) $(haldir) $(hal_cpudir))
outdirs       := $(sort $(objdir) $(depdir) $(targetdir))
dirs          := $(sort $(indirs) $(outdirs))

# Flags
incflags       = $(addprefix -I, $(incdirs))
libflags       = $(addprefix -l, $(libs))
cflags_a       = $(depflags) $(incflags)
cflags_l       =
CFLAGS        += $(cflags_in)

# Special Variables
.DEFAULT_GOAL  = $(target)

vpath %.c $(srcdirs)
vpath %.S $(srcdirs)
vpath %.h $(incdirs)
vpath %.o $(objdir)
vpath %.d $(depdir)

#### Build Recipes #### {{{1

$(target): $(objects) | $(targetdir)
	$(CC) $(cflags_l) $(CFLAGS) $^ $(libflags) -o $@

$(objects_c):   $(objdir)/%.o: %.c
$(objects_asm): $(objdir)/%.o: %.S
$(objects):     $(objdir)/%.o: %.d | $(objdir) $(depdir)
$(objects):
	$(CC) -c $(cflags_a) $(CFLAGS) $< -o $@

$(outdirs):
	mkdir -p $@

$(dependencies): ;

-include $(dependencies)

#### Phony Commands #### {{{1

.PHONY: clean cleanint cleanall autoclean cleanobj cleandeps cleantarget \
        cleandirs run rebuild

clean:     cleanint cleandirs
cleanint:  cleanobj cleandeps
cleanall:  cleanint cleantarget cleandirs
autoclean: $(target) clean

cleanobj:
	@printf "Cleaning object files...\n"
	$(RM) $(objects)

cleandeps:
	@printf "Cleaning dependency files...\n"
	$(RM) $(dependencies)

cleantarget:
	@printf "Cleaning target file...\n"
	$(RM) $(target)

cleandirs:
	@printf "Cleaning directories...\n"
	$(foreach dir,$(outdirs),$(call rmdir,$(dir)))

run: $(target)
	@printf "\nCompilation was successful. Running program...\n\n"
	@$(target)

rebuild: cleanall $(target)

# vim: fdm=marker
