# Makefile
#
# Build scripts.
#
# Copyright (C) 2003, 2004
# Andy Goth     <unununium@openverse.com>
#
# Adapted from the Makefile in xpyre <URL:http://ioioio.net/devel/xpyre/>, and
# distantly related to Peter Miller <millerp@canb.auug.org.au>'s Makefiles at
# <URL:http://www.pcug.org.au/~millerp/rmch/recu-make-cons-harm.html>.
#
# Caution: reading this file will give you scary nightmares.
#
# This code is available under the GNU General Public License; see COPYING.

include global.mk

SHELL := /bin/sh
SUFFIXES :=

all: all-targets

# TODO: figure out how to have different INCPATH, CFLAGS, etc. for source files
# in different modules.

INCPATH += $(patsubst %,-I%,$(MODULES))
MODFILES := $(patsubst %,%/module.mk,$(MODULES))
PROGRAMS :=
ARLIBS :=
SHLIBS :=
TARGETS :=
CLEANTARGETS := clean

RANLIB := ranlib

# This is here for the sake of the dependency include, below.
ifeq ($(MAKECMDGOALS),)
MAKECMDGOALS := all
endif

# Hide commands?
ifeq ($(HUSH),1)
override HUSH := @
else
override HUSH :=
endif

# Use debugging flags and libraries?
ifeq ($(DEBUG),1)
CFLAGS += -g3 -ggdb
LIBS += -lefence
else
override DEBUG :=
endif

# Include module descriptions.
include.mk: Makefile global.mk $(MODFILES)
	@echo "* GEN $@"
	$(HUSH)(echo '# This file is automatically generated by make.';\
	echo '# Do not edit; changes will be lost, and you will be sorry.';\
	for mod in $(MODULES); do\
		echo;\
		echo "DIR := $$mod";\
		echo "include $$mod/module.mk";\
	done;\
	echo;\
	echo "-include auto.mk") > $@
-include include.mk

# This must be done after including module definitions.
all-programs: $(PROGRAMS)
all-arlibs: $(ARLIBS)
all-shlibs: $(SHLIBS)
all-targets: all-programs all-arlibs all-shlibs $(TARGETS)

# Generate nifty automatic stuff.
auto.mk: Makefile global.mk $(MODFILES)
	@echo "* GEN $@"
	$(HUSH)(echo '# This file is automatically generated by make.';\
	echo '# Do not edit; changes will be lost, and you will be sorry.') > $@
	$(if $(PROGRAMS),$(HUSH)(for prog in $(PROGRAMS); do\
		echo;\
		echo "# Program: $$prog.";\
		echo 'OBJ-'$$prog' := $$(foreach sfx,c s,$$(patsubst\
				%.$$(sfx),%.o,$$(filter %.$$(sfx),$$(SRC-'$$prog'))))';\
		echo 'DEP-'$$prog' := $$(patsubst %.c,%.d,$$(filter\
				%.c,$$(SRC-'$$prog')))';\
		echo 'SRC += $$(SRC-'$$prog')';\
		echo 'OBJ += $$(OBJ-'$$prog')';\
		echo 'DEP += $$(DEP-'$$prog')';\
		echo $$prog': $$(OBJ-'$$prog') $$(LLIBS-'$$prog')';\
		echo -e '\t@echo "* LD  $$@"';\
		echo -e '\t$$(HUSH)$$(CC) $$(LDFLAGS) $$(LIBPATH) -o $$@ $$(LIBS)'\
				'$$(OBJ-'$$prog') $$(LLIBS-'$$prog') $$(LIBS-'$$prog')';\
	done) >> $@)
	$(if $(ARLIBS),$(HUSH)(for arlib in $(ARLIBS); do\
		echo;\
		echo "# Static library: $$arlib.";\
		echo 'OBJ-'$$arlib' := $$(foreach sfx,c s,$$(patsubst\
				%.$$(sfx),%.o,$$(filter %.$$(sfx),$$(SRC-'$$arlib'))))';\
		echo 'DEP-'$$arlib' := $$(patsubst %.c,%.d,$$(filter\
				%.c,$$(SRC-'$$arlib')))';\
		echo 'SRC += $$(SRC-'$$arlib')';\
		echo 'OBJ += $$(OBJ-'$$arlib')';\
		echo 'DEP += $$(DEP-'$$arlib')';\
		echo $$arlib': $$(OBJ-'$$arlib') $$(LLIBS-'$$arlib')';\
		echo -e '\t@echo "* AR  $$@"';\
		echo -e '\t$$(HUSH)$$(AR) cr $$@ $$^ $$(LIBS-'$$arlib')'\
				'$$(LLIBS-'$$arlib')';\
		echo -e '\t$$(HUSH)$$(RANLIB) $$@';\
	done) >> $@)
	$(if $(SHLIBS),$(HUSH)(for shlib in $(SHLIBS); do\
		echo;\
		echo "# Shared library: $$shlib.";\
		echo 'OBJ-'$$shlib' := $$(foreach sfx,c s,$$(patsubst\
				%.$$(sfx),%.o,$$(filter %.$$(sfx),$$(SRC-'$$shlib'))))';\
		echo 'DEP-'$$shlib' := $$(patsubst %.c,%.d,$$(filter\
				%.c,$$(SRC-'$$shlib')))';\
		echo 'SRC += $$(SRC-'$$shlib')';\
		echo 'OBJ += $$(OBJ-'$$shlib')';\
		echo 'DEP += $$(DEP-'$$shlib')';\
		echo $$shlib': $$(OBJ-'$$shlib') $$(LLIBS-'$$shlib')';\
		echo -e '\t@echo "* LD  $$@"';\
		echo -e '\t$$(HUSH)$$(CC) $$(LDFLAGS) -shared -fPIC $$(LIBPATH)'\
				'-o $$@ $$^ $$(LIBS-'$$shlib') $$(LLIBS-'$$shlib') $$(LIBS)';\
	done) >> $@)
	$(HUSH)(echo;\
	echo '# Include dependencies.';\
	echo 'ifneq ($$(filter-out $$(CLEANTARGETS),$$(MAKECMDGOALS)),)';\
	echo '-include $$(DEP)';\
	echo 'endif';\
	echo;\
	echo '# Installation.';\
	echo -n 'install:';\
	for module in $(MODULES); do\
		echo -n ' install-'$$module;\
	done;\
	echo) >> $@

# Generate dependency files from source.
%.d: %.c Makefile global.mk $(MODFILES)
	@echo "* DEP $<"
	$(HUSH)(dir=$$(echo "$(dir $@)" | sed 's+^\./++');\
	for dep in $$(echo -n "$@ $$dir";\
	$(CC) $(CFLAGS) $(CPPFLAGS) $(INCPATH) -MM -MG -o - $<); do\
		if test "$$dep" == \\; then\
			continue;\
		elif test ! -f "$$dep" -a ! "$${dep:0:$${#dir}}" == "$$dir"; then\
			echo -n "$$dir";\
		fi;\
		echo -n "$$dep ";\
	done;\
	echo) > $@

# Generate object files from source.
%.o: %.c %.d
	@echo "* CC  $<"
	$(HUSH)$(CC) $(CFLAGS) $(CPPFLAGS) $(INCPATH) -c -o $@ $<

%.o: %.s %.d
	@echo "* AS  $<"
	$(HUSH)$(AS) -o $@ $<

# Remove generated files.
GENERATED += $(TARGETS) $(PROGRAMS) $(ARLIBS) $(SHLIBS)\
		$(OBJ) include.mk auto.mk
clean-obj:
	@echo "* RM  compiled files"
	$(HUSH)-$(RM) -f $(GENERATED)

# Remove generated dependency files.
clean: clean-obj
	@echo "* RM  dependency files"
	$(HUSH)-$(RM) -f $(DEP)

# Dummy target for generating dependencies.
depend: $(DEP)
	@true

# Tell make about special (non-file) targets.
.PHONY: all all-programs all-arlibs all-shlibs clean depend install

# vim: set ts=4 sw=4 tw=80 noet:
