# Nathan's generic Makefile		-*- mode:Makefile -*-
# Copyright (C) 2019-2020 Nathan Sidwell, nathan@acm.org
# License: Apache v2.0

ifeq (0,$(MAKELEVEL))
ifneq (,@tools@)
$(info Prepending @tools@/bin to PATH)
PATH := @tools@/bin:$(PATH)
export PATH
endif
ifeq (,$(SERIAL))
# Figure out if we should set parallelism
ifeq (,$(filter clean%,$(MAKECMDGOALS)))
PARALLELISM := @NUM_CPUS@
endif
endif
endif

ifeq (00,$(MAKELEVEL)$(if $(PARALLELISM),0,1))
# Although Make 4.3 documentation suggests I can set parallelism just
# by appending to MAKEFLAGS, it doesn't seem to work.  It's also not
# possible to figure out the current Make invocation's parallelism,
# the -j option doesn't appear in MAKEFLAGS and is magically inserted
# when that is expanded in a rule.  I can't figure how to get a rule
# expansion into a variable to test.  Fortunately, Make propagates an
# incoming -j option rather than the one you attempted to append
$(info Parallelizing $(PARALLELISM) ways)
MAKEFLAGS += -j$(PARALLELISM)
ifneq (,$(MAKECMDGOALS))
$(MAKECMDGOALS): recurse
endif
recurse:
	$(MAKE) -r$(MAKEFLAGS) $(MAKECMDGOALS)
.PHONY: recurse
else

srcdir := @srcdir@
prefix := @prefix@
exec_prefix := @exec_prefix@
bindir := @bindir@
libdir := @libdir@
includedir := @includedir@
SUBDIRS := @SUBDIRS@
# autoconf doesn't seem to like setting SHELL
SHELL := $(shell which zsh 2>/dev/null >/dev/null && echo zsh \
  || (echo "No ZSH, maybe flakey" >&2 && echo sh))

# We have to place the -I paths last, so that building will see -I paths to us
CXX := $(filter-out -I%,@CXX@)
AR := @AR@
INSTALL := $(srcdir)/build-aux/install-sh

# C++ compiler options
CXXFLAGS := @CXXFLAGS@
CXXINC := $(filter -I%,@CXX@)
CXXOPTS := $(CXXFLAGS)
ifeq ($(notdir $(firstword $(CXX))),g++)
# It's GCC, or pretending to be it -- so it better smell like it!
# Code generation
CXXOPTS += -fno-enforce-eh-specs
CXXOPTS += -fno-stack-protector -fno-threadsafe-statics
ifneq (@EXCEPTIONS@,yes)
CXXOPTS += -fno-exceptions -fno-rtti
endif
ifeq ($(filter -fdebug-prefix-map=%,$(CXXOPTS)),)
CXXOPTS += -fdebug-prefix-map=${srcdir}/=
endif
# Warning options
CXXOPTS += -W -Wall
ifeq (no,)
# just turn off for now
CXXOPTS += -Woverloaded-virtual -Wshadow
CXXOPTS += -Wno-invalid-offsetof -Wno-unused-variable
CXXOPTS += -Wno-missing-field-initializers
# Diagnostic options, look at controlling terminal so that piping
# through more works
MLEN := $(shell stty size </dev/tty 2>/dev/null | cut -d' ' -f2)
ifneq (,$(MLEN))
CXXOPTS += -fmessage-length=$(MLEN)
endif
CXXOPTS += -fdiagnostics-color=always -fno-diagnostics-show-option
endif
else
ifeq ($(notdir $(firstword $(CXX))),clang++)
CXXOPTS += -fno-stack-protector -fno-threadsafe-statics
ifneq (@EXCEPTIONS@,yes)
CXXOPTS += -fno-exceptions -fno-rtti
endif
# Warning options
CXXOPTS += -W -Wall -Woverloaded-virtual -Wshadow
CXXOPTS += -Wno-invalid-offsetof -Wno-unused-variable
CXXOPTS += -Wno-missing-field-initializers
else
# Add different compiler's options here
endif
endif

# Config
CXXOPTS += $(filter-out -DHAVE_CONFIG_H,@DEFS@) -include config.h

# Linker options
LDFLAGS := -L. @LDFLAGS@
LIBS := @LIBS@

# Per-source & per-directory compile flags (warning: recursive)
SRC_CXXFLAGS = $(CXXFLAGS$(patsubst $(srcdir)%,%,$1)) \
	$(if $(filter-out $(srcdir)/,$1),\
	  $(call $0,$(dir $(patsubst %/,%,$1))))

ifneq ($(MAINTAINER),)
override MAINTAINER += $1
endif
ifeq (@MAINTAINER@,yes)
MAINTAINER = $2
else
MAINTAINER = \# --enable-maintainer-mode to rebuild $1, or make MAINTAINER=touch
endif

vpath %.in $(srcdir)
vpath %.cc $(srcdir)

.SUFFIXES: .o .cc

%.o: %.cc
	@mkdir -p $(dir $@)
	$(CXX) $(strip $(CXXOPTS) $(call SRC_CXXFLAGS,$<) $(CXXINC)) \
	  -MMD -MP -MF ${@:.o=.d} -c -o $@ $<

all:: Makefile $(addprefix all.,$(SUBDIRS))

check:: Makefile $(addprefix check.,$(SUBDIRS))

clean:: Makefile $(addprefix clean.,$(SUBDIRS))

revision.stamp: $(addprefix $(srcdir)/,. $(SUBDIRS))
	@revision=$$(git -C $(srcdir) rev-parse HEAD 2>/dev/null) ;\
	if test -n "$$revision" ;\
	then revision=git-$$revision ;\
	  if git -C $(srcdir) status --porcelain 2>/dev/null | grep -vq '^  ' ;\
	  then revision+=M ;\
	  fi ;\
	else revision=unknown ;\
	fi ;\
	echo $$revision > $@

revision: revision.stamp
	@cmp -s $< $@ || cp -f $< $@

clean::
	rm -f revision.stamp revision

distclean:: clean
	rm -f config.log config.status
	rm -rf $(SUBDIRS)

$(srcdir)/configure: $(srcdir)/configure.ac \
	  $(patsubst %,$(srcdir)/%/config.m4,. $(SUBDIRS))
	$(call MAINTAINER,$@,cd $(@D) && autoconf -W all,error)

$(srcdir)/config.h.in: $(srcdir)/configure.ac \
	  $(patsubst %,$(srcdir)/%/config.m4,. $(SUBDIRS))
	$(call MAINTAINER,$@,cd $(@D) && autoheader -f -W all,error)

config.h: config.status config.h.in
	./$< --header=$@
	touch $@

ifeq ($(filter %clean,$(MAKECMDGOALS)),)
@CONFIG_FILES@: %: config.status %.in
	./$< --file=$@
	touch $@
endif

config.status: $(srcdir)/configure $(srcdir)/config.h.in
	if test -x $@; then ./$@ -recheck; else $< @configure_args@; fi

distclean:: clean
	rm -f config.h

maintainer-clean:: distclean
	rm -f $(srcdir)/config.h.in

clean::
	rm -f $(shell find $(srcdir) -name '*~')

.PHONY: all check clean distclean maintainer-clean

-include $(addsuffix /Makesub,. $(SUBDIRS))
-include $(addsuffix /tests/Makesub,. $(SUBDIRS))

endif