# Based largely on:  <http://scottmcpeak.com/autodepend/autodepend.html>

# Compiler and linker.
CC        := gcc

# Target binary program.
TARGET    := xptr

# Directories, source, includes, objects, binary, and resources.
# `$(PWD)` uses the directory where the makefile resides; alternatively a
# certain directory, such as `src`, can be specified.
SRCDIR    := $(PWD)

INCDIR    := inc
RESDIR    := res

SRCEXT    := c
DEPEXT    := d
OBJEXT    := o

# Flags, libraries, and includes.
CFLAGS    := -Wall -pedantic
LIB       :=# -lm
INC       := -I$(INCDIR) -I/usr/local/include
INCDEP    := -I$(INCDIR)

# Directories.
BUILDDIR_BASE     := obj
TARGETDIR_BASE    := bin

DEBUGDIR_SUFFIX   := Debug
RELEASEDIR_SUFFIX := Release

DEBUG_BUILDDIR    := $(BUILDDIR_BASE)/$(DEBUGDIR_SUFFIX)
DEBUG_TARGETDIR   := $(TARGETDIR_BASE)/$(DEBUGDIR_SUFFIX)

RELEASE_BUILDDIR  := $(BUILDDIR_BASE)/$(RELEASEDIR_SUFFIX)
RELEASE_TARGETDIR := $(TARGETDIR_BASE)/$(RELEASEDIR_SUFFIX)

SOURCES           := $(shell find $(SRCDIR) -type f -name "*.$(SRCEXT)")

DEBUG_OBJECTS     := $(patsubst $(SRCDIR)/%,$(DEBUG_BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.$(OBJEXT)))
RELEASE_OBJECTS   := $(patsubst $(SRCDIR)/%,$(RELEASE_BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.$(OBJEXT)))

debug:   CFLAGS += -g -ggdb -O0 -DDEBUG

release: CFLAGS += -O3 -DNDEBUG

# Default build is a debug build.
all: debug

# Debug make.
debug: debug_directories debug_resources debug_target

# Remake debug build.
remake: cleaner all

# Release make.
release: release_directories release_resources release_target

# Create directories
debug_directories:
	@mkdir -p $(DEBUG_TARGETDIR)
	@mkdir -p $(DEBUG_BUILDDIR)

release_directories:
	@mkdir -p $(RELEASE_TARGETDIR)
	@mkdir -p $(RELEASE_BUILDDIR)

# Copy resources from resources directory to target directory.
debug_resources:
	@if [ -d $(RESDIR) ]; then cp -r $(RESDIR)/. $(DEBUG_TARGETDIR)/; fi

release_resources:
	@if [ -d $(RESDIR) ]; then cp -r $(RESDIR)/. $(RELEASE_TARGETDIR)/; fi

# Clean only objects.
clean:
	@$(RM) -rf $(BUILDDIR_BASE)

# Full clean, objects and binaries.
cleaner: clean
	@$(RM) -rf $(TARGETDIR_BASE)

# Pull in dependency info for existing object files.
# Alternative and better approach:  <https://stackoverflow.com/questions/13432127/how-to-use-the-include-directive-in-a-makefile-for-a-specific-target>
ifeq ($(MAKECMDGOALS),debug)
-include $(DEBUG_OBJECTS:.$(OBJEXT)=.$(DEPEXT))
endif
ifeq ($(MAKECMDGOALS),release)
-include $(RELEASE_OBJECTS:.$(OBJEXT)=.$(DEPEXT))
endif

# Compile debug.
$(DEBUG_BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT)
	@mkdir -p $(dir $@)
	$(CC) $(CFLAGS) $(INC) -c -o $@ $<
	@$(CC) $(CFLAGS) $(INCDEP) -MM $(SRCDIR)/$*.$(SRCEXT) > $(DEBUG_BUILDDIR)/$*.$(DEPEXT)
	@cp -f $(DEBUG_BUILDDIR)/$*.$(DEPEXT) $(DEBUG_BUILDDIR)/$*.$(DEPEXT).tmp
	@sed -e 's|.*:|$(DEBUG_BUILDDIR)/$*.$(OBJEXT):|' < $(DEBUG_BUILDDIR)/$*.$(DEPEXT).tmp > $(DEBUG_BUILDDIR)/$*.$(DEPEXT)
	@sed -e 's/.*://' -e 's/\\$$//' < $(DEBUG_BUILDDIR)/$*.$(DEPEXT).tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $(DEBUG_BUILDDIR)/$*.$(DEPEXT)
	@rm -f $(DEBUG_BUILDDIR)/$*.$(DEPEXT).tmp

# Compile release.
$(RELEASE_BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT)
	@mkdir -p $(dir $@)
	$(CC) $(CFLAGS) $(INC) -c -o $@ $<
	@$(CC) $(CFLAGS) $(INCDEP) -MM $(SRCDIR)/$*.$(SRCEXT) > $(RELEASE_BUILDDIR)/$*.$(DEPEXT)
	@cp -f $(RELEASE_BUILDDIR)/$*.$(DEPEXT) $(RELEASE_BUILDDIR)/$*.$(DEPEXT).tmp
	@sed -e 's|.*:|$(RELEASE_BUILDDIR)/$*.$(OBJEXT):|' < $(RELEASE_BUILDDIR)/$*.$(DEPEXT).tmp > $(RELEASE_BUILDDIR)/$*.$(DEPEXT)
	@sed -e 's/.*://' -e 's/\\$$//' < $(RELEASE_BUILDDIR)/$*.$(DEPEXT).tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $(RELEASE_BUILDDIR)/$*.$(DEPEXT)
	@rm -f $(RELEASE_BUILDDIR)/$*.$(DEPEXT).tmp

# Link debug.
debug_target: $(DEBUG_OBJECTS)
	$(CC) $(CFLAGS) -o $(DEBUG_TARGETDIR)/$(TARGET) $^ $(LIB)

# Link release.
release_target: $(RELEASE_OBJECTS)
	$(CC) $(CFLAGS) -o $(RELEASE_TARGETDIR)/$(TARGET) $^ $(LIB)

# Non-file targets.
.PHONY: all remake clean cleaner debug release debug_target release_target debug_resources release_resources
