# Partial -*- Makefile -*-

# We have a help system.
# Basically, if you ask for help, it'll not rebuild stuff (it forgets those rules).
# Instead, it prints out helpful things. Sometimes even specifically about
# what it is you're trying to do - "make help config" is an example.
ifeq ($(findstring help,$(MAKECMDGOALS)),)

ifeq ($(filter %clean,$(MAKECMDGOALS)),)
# If we're cleaning, we don't want to rebuild the definitions - which might otherwise
# involve rebuilding configure and running it.
-include $(BUILDDIR)/definitions
endif
# Target definitions appear in little submake files.
# I've heavily commented acapd-real.submake to help you here.
-include $(TARGETS:%=src/build-sys/%.submake)

# Default compiler and linker flags.
#ANYFLAGS-basic:=-pipe -g -pg -Wall
ANYFLAGS-basic:=-pipe -O3 -Wall
CFLAGS-basic:=#-fno-inline
LDFLAGS-basic:=
CFLAGS-single:=$(ANYFLAGS-basic) $(CFLAGS-basic) $(CFLAGS)
CXXFLAGS-single:=$(ANYFLAGS-basic) $(CFLAGS-basic) $(CXXFLAGS)
CFLAGS-multi:=$(ANYFLAGS-basic) $(CFLAGS-basic) -pthread $(CFLAGS)
CXXFLAGS-multi:=$(ANYFLAGS-basic) $(CFLAGS-basic) -pthread $(CXXFLAGS)
LIBS-multi:=$(LIBS)
LIBS-single:=$(LIBS)
LDFLAGS-multi:=$(ANYFLAGS-basic) $(LDFLAGS-basic) -pthread $(LDFLAGS)
LDFLAGS-single:=$(ANYFLAGS-basic) $(LDFLAGS-basic) $(LDFLAGS)

# Cleaning - that is, forcing a complete rebuild of compiled files,
# is easy. We just wipe the build directory.
clean:
	rm -rf $(BUILDDIR)
.PHONY: clean

# To clean for a distribution, we also wipe the output, and stuff generated
# by autoconf.
distclean: clean
	rm -rf $(OUTPUTDIR)
	rm -rf *.cache
	rm -f config.*
	rm -f $(BUILDDIR)/include/infotrope/config.h
.PHONY: distclean

# To clean for maintainer purposes, we wipe anything which can be rebuilt.
# Note that this leaves us with even less than is in svn.
maintclean: distclean
	rm -f $(MAINTDIR)/*
	rm -f configure
	find -name '*~' -exec rm '{}' \;
.PHONY: maintclean

# 'config' just generates config.status.
config: config.status
.PHONY: config

# The rules files are the real per-target makefiles.
# They'll be included later.
$(BUILDDIR)/%.rules: $(BUILDDIR)/emptyfile src/build-sys/%.submake src/build-sys/main Makefile $(BUILDDIR)/definitions
	@echo 'Creating rules for $*'
	@rm -f $@
	@echo '$(OUTPUTDIR)/$*: $$(BUILDDIR)/$*.rules' >>$@
	@echo '$(OUTPUTDIR)/$*: TLIBS:=$$($*-LIBS) $$(LIBS-$($*-THREADING))' >>$@
	@echo '$(OUTPUTDIR)/$*: TLDFLAGS:=$$($*-LDFLAGS) $$(LDFLAGS-$($*-THREADING))' >>$@
	@echo '$(OUTPUTDIR)/$*: TCXXFLAGS:=$$($*-CXXFLAGS) $$(CXXFLAGS-$($*-THREADING))' >>$@
	@echo '$(OUTPUTDIR)/$*: TCFLAGS:=$$($*-CFLAGS) $$(CFLAGS-$($*-THREADING))' >>$@
	@echo 'ifneq ($$($*-BUILDTARGET),)' >>$@
	@echo '$(OUTPUTDIR)/$*: $$(BUILDDIR)/$$($*-BUILDTARGET)' >>$@
	@echo -e '\t@echo "[COPY] $$@"' >>$@
	@echo -e '\t@cp $$< $$@' >>$@
	@echo 'else' >>$@
	@echo '$(OUTPUTDIR)/$*: $$(patsubst %.cc,$$(BUILDDIR)/c++/$$($*-THREADING)/%.o,$$(filter %.cc,$$($*-SOURCES)))' >>$@
	@echo -e '\t@echo "[LINK] $$@"' >>$@
	@echo -e '\t@$$(CXX) -o $$@ $$(TLIBS) $$(TLDFLAGS) $$(filter %.o,$$^)' >>$@
	@echo '$($*-TYPE): $(OUTPUTDIR)/$*' >>$@
	@echo '' >>$@
	@echo 'endif' >>$@
	@echo 'ifneq ($$($*-INSTALL),)' >>$@
	@echo '$*-installer: $(OUTPUTDIR)/$*' >>$@
	@echo -e '\t@echo "Installing $$($*-NAME) to $$($*-INSTALL), mode=$$($*-MODE)"' >>$@
	@echo -e '\t@install -D --group=root --owner=root --mode=$$($*-MODE) $$($*-INSTALLOPTS) $(OUTPUTDIR)/$* $$(DESTDIR)$$($*-INSTALL)' >>$@
	@echo 'install-$($*-TYPE): $*-installer' >>$@
	@echo 'endif' >>$@

# Compilation rules.
# Note that we compile into a different directory, using compiler flags generated by the rules.
$(BUILDDIR)/c++/single/%.o: src/impl/%.cc $(BUILDDIR)/include/infotrope/config.h
	@mkdir -p $(dir $@)
	@echo "[CXX] [ST] $<"
	@$(CXX) -pipe -MD -MF $(@:%.o=%.dep) -o $@ -I$(BUILDDIR)/include/ -Isrc/include/ $(TCXXFLAGS) -c $<

$(BUILDDIR)/c++/multi/%.o: src/impl/%.cc $(BUILDDIR)/include/infotrope/config.h
	@mkdir -p $(dir $@)
	@echo "[CXX] [MT] $<"
	@$(CXX) -pipe -MD -MF $(@:%.o=%.dep) -o $@ -I$(BUILDDIR)/include/ -Isrc/include/ $(TCXXFLAGS) -c $<


# Yeah, annoying.
# Lots of rules use this to create output directories.
%/emptyfile:
	@mkdir -p $*
	@touch $@

# I can't stand the way autoconf creates config.h files.
# Way too much maintainence, plus it doesn't namespace the macros.
$(BUILDDIR)/include/infotrope/config.h: $(BUILDDIR)/definitions
	@mkdir -p $(BUILDDIR)/include/infotrope/
	@echo "/* This is the config.h file, and is autogenerated. */" >$@.f
	@echo "/* It is automatically built during the build process. */" >>$@.f
	@echo "/* Do NOT redistribute this file, it'll break other folks' builds. */" >>$@.f
	@echo "/* This file was NOT generated by autoconf or configure. */" >>$@.f
	@echo "/* Instead, it was built by the Makefile, on the directions of configure. */" >>$@.f
	@for DEF in $(DEFS); do \
		echo $$DEF | sed -e 's/^-D/#define INFOTROPE_/' -e 's/=/ /' >>$@.f; \
	done
	@rm -f $@
	@mv $@.f $@

# Makefile magic...
# What this does, in effect, is automagically cause the rules files to be built, the target directory to be created,
# and the dependency files to get used.
targets: $(OUTPUTDIR)/emptyfile
ALLSOURCE:=$(foreach target,$(TARGETS),$($(target)-SOURCES))
ALLDEPS-single:=$(patsubst %.cc,build/c++/single/%.dep,$(filter %.cc,$(ALLSOURCE)))
ALLDEPS-multi:=$(patsubst %.cc,build/c++/multi/%.dep,$(filter %.cc,$(ALLSOURCE)))
ifeq ($(filter %clean,$(MAKECMDGOALS)),)
-include $(ALLDEPS-single) $(ALLDEPS-multi) $(TARGETS:%=$(BUILDDIR)/%.rules)
endif

# Real configuration.
config.status: $(BUILDDIR)/emptyfile configure
	@echo "Automatic configuration using options:" $(CONFIGURE_OPTIONS)
	@./configure $(CONFIGURE_OPTIONS)

# Rebuild configure if we need to.
# Note that this needs a bit of work - currently, configure always gets recreated
# if you checkout from subversion.
configure: $(MAINTDIR)/configure.ac
	@cd $(MAINTDIR) && aclocal -I ../build-sys/autoconf/
	@autoconf -I $(MAINTDIR) $(MAINTDIR)/configure.ac >$@
	@chmod 0700 $@

# Rebuild definitions file.
# The definitions file actually contains the autoconf stuff that normally is the sole reason why
# you get Makefile.in instead of Makefile.
$(BUILDDIR)/definitions: src/build-sys/definitions.in config.status
	@./config.status

# Again, this always rebuilds when you checkout from svn.
# This is most annoying. I should fix this.
$(MAINTDIR)/configure.ac: Makefile $(MAINTDIR)/emptyfile src/build-sys/autoconf/header.ac $(patsubst %,src/build-sys/autoconf/%.ac,$(sort $(foreach target,$(TARGETS),$($(target)-CONFIG)))) src/build-sys/autoconf/footer.ac
	@echo "Regenerating configure.ac due to $?"
	@rm -f $@
	@echo 'AC_INIT('$(PACKAGE_NAME)','$(PACKAGE_VERSION)','$(PACKAGE_MAINTAINER)')' >$@
	@set $^; shift; shift; cat $$* >>$@;

# Installation magic.
# install-targets is generated by the rules files.
DESTDIR=''
install: install-targets
.PHONY: install

deb: DEBVERSION:=$(shell ( dpkg-parsechangelog || echo 'Version: no_version' ) 2>&1 | grep '^Version:' | sed 's/^.*: //')
deb: update
	@if [ -d .svn ]; then \
		if svn st -q | grep -v 'debian/changelog' | grep '.'; then \
			echo 'Error: Unsynched changes.' 1>&2; \
			exit 2; \
		fi; \
		if [ $(DEBVERSION)'' != $(PACKAGE_VERSION)'-1' ]; then \
			echo 'Error: Debian changelog is out of sync: $(DEBVERSION) != $(PACKAGE_VERSION)' 1>&2; \
			exit 1; \
		fi; \
		svn export . ../$(PACKAGE_NAME)-$(DEBVERSION); \
		$(MAKE) -C ../$(PACKAGE_NAME)-$(DEBVERSION) deb; \
		rm -rf ../$(PACKAGE_NAME)-$(DEBVERSION); \
		lintian ../$(PACKAGE_NAME)_$(DEBVERSION).dsc; \
		lintian ../$(PACKAGE_NAME)_$(DEBVERSION)*.deb; \
		linda ../$(PACKAGE_NAME)_$(DEBVERSION)*; \
	else \
		dpkg-buildpackage -rfakeroot; \
	fi

SVNREV:
	@if [ -d .svn ]; then \
		echo 'PACKAGE_VERSION:='$(PACKAGE_VERSION)'.$$(shell svn info | grep '\''^Revision:'\'' | sed '\''s/^Revision: *//'\'')' >$@; \
	else \
		echo 'PACKAGE_VERSION:='$(PACKAGE_VERSION)'.0' >$@; \
	fi

update:
	@if [ -d .svn ]; then \
		rm -f SVNREV; \
		svn update; \
	else \
		echo 'Not a subversion WC.'; \
	fi

# End of if-we-didn't-want-help mode.
endif

# Help.
help:
	@echo 'Possible make options:'
	@echo '   all: [default] Make all normal targets, run ./configure if needed.'
	@echo '   clean: Clean, forcing complete rebuild.'
	@echo '   distclean: Clean, including cleaning ./configure output.'
	@echo '   maintclean: Clean, including cleaning stuff normally distributed.'
	@echo '   config: Run ./configure if needed, using default or last used arguments.'
	@echo '   tests: Build tests.'
	@echo '   everything: Build everything.'
	@echo '   install: Install targets.'
	@echo '   deb: Create Debian package.'
	@echo '   help: Don'\''t do anything, but print help. Print help for other'
	@echo '         targets if available.'
	@echo ''

ifneq ($(findstring help,$(MAKECMDGOALS)),)

# 'supported' direct targets get help entries.

config.status:
	@echo '[Configuration skipped.]'
all:
	@echo 'Target all skipped due to help'
clean:
	@echo 'Target clean not built due to help'
distclean:
	@echo 'Target distclean not built due to help'
maintclean:
	@echo 'Target maintclean not built due to help'
config:
	@if [ -x ./configure ]; then ./configure --help; else echo 'Target config not built due to help'; fi
tests:
	@echo 'Target tests not built due to help'
everything:
	@echo 'Target everything not built due to help'
install:
	@echo 'You can alter the destination of the installation'
	@echo 'by using DESTDIR, useful for packaging.'

deb:
	@echo 'Target deb not built due to help'
endif
