########################################################################
#
# The build rules in this file are intended for use by GAP packages that
# want to build a simple GAP kernel extensions. They are based on the
# GAP build system, and require GNU make. To use this in your GAP
# package, `include` this file from your primary GNUmakefile. You must also
# set several variables beforehand:
#
# - GAPPATH must be set to the location of the GAP installation against
#   which to build your package.
# - KEXT_NAME should be the name of your kernel extension (without
#   file extensions like .so or .dll)
# - KEXT_SOURCES must contain a list of .c or .cc files to be linked
#   into your kernel extension
# - optionally, you can set KEXT_CFLAGS, KEXT_CXXFLAGS, KEXT_LDFLAGS
# - if you are using autoconf to produce your configure script, set
#   KEXT_USE_AUTOCONF to 1 to enable dependency rules that enable
#   regenerating the configure script etc. when necessary
#
# The contents of this file are released into the public domain; hence
# you may edit this file as you wish, bundle and distribute it with your
# package, etc.
#
# If you bundle this file with your package, please try not to edit it,
# so that we can keep it identical across all GAP packages. Instead, if
# you find that you must edit it, please submit your changes back to
# the GAP team, so that a future version of this file can be adjusted
# to cover your usecase without modifications, thus ensuring you can
# always easily update to newer version of it.
#
########################################################################

# read GAP's build settings
include $(GAPPATH)/sysinfo.gap

# Remove quotation marks from some variable
GAC_LDFLAGS := $(subst $\",,$(GAC_LDFLAGS))
GAP_LDFLAGS := $(subst $\",,$(GAP_LDFLAGS))
GAP_CXX := $(subst $\",,$(GAP_CXX))

# hack to support GAP <= 4.9
ifndef GAP_KERNEL_MAJOR_VERSION
  KEXT_CFLAGS += -I$(GAP_LIB_DIR)/src
  KEXT_CXXFLAGS += -I$(GAP_LIB_DIR)/src
endif

# honor user supplied flags
KEXT_CFLAGS += $(CPPFLAGS)
KEXT_CFLAGS += $(CFLAGS)
KEXT_CXXFLAGS += $(CPPFLAGS)
KEXT_CXXFLAGS += $(CXXFLAGS)
KEXT_LDFLAGS += $(LDFLAGS)

# various derived settings
KEXT_BINARCHDIR = bin/$(GAParch)
KEXT_SO = $(KEXT_BINARCHDIR)/$(KEXT_NAME).so

# the following settings are provided by sysinfo.gap in GAP >= 4.12;
# for compatibility with older GAP version (at least 4.9, 4.10, 4.11)
# we try to "guess" suitable values here
GAP ?= $(GAPPATH)/gap
GAC ?= $(GAPPATH)/gac
GAP_OBJEXT ?= lo

# override KEXT_RECONF if your package needs a different invocation
# for reconfiguring (e.g. `./config.status --recheck` for autoconf)
ifdef KEXT_USE_AUTOCONF
KEXT_RECONF ?= ./config.status GNUmakefile
else
KEXT_RECONF ?= ./configure "$(GAPPATH)"
endif

# default target
all: $(KEXT_SO)
.PHONY: all

########################################################################
# Object files
# For each file FOO.c in SOURCES, add gen/FOO.$(GAP_OBJEXT) to KEXT_OBJS
# and similar for .cc files
########################################################################
KEXT_OBJS = $(patsubst %.s,gen/%.$(GAP_OBJEXT), \
            $(patsubst %.cpp,gen/%.$(GAP_OBJEXT), \
            $(patsubst %.c,gen/%.$(GAP_OBJEXT), \
                $(KEXT_SOURCES))))

########################################################################
# Quiet rules.
#
# Replace regular output with quiet messages, unless V is set,
# e.g. "make V=1"
########################################################################
ifneq ($(findstring $(MAKEFLAGS),s),s)
ifndef V
QUIET_GAC     = @echo "   GAC     $< => $@";>/dev/null # keep the trailing space!
endif
endif

########################################################################
# Rules for automatic header dependency tracking.
# This is based on the GAP build system.
########################################################################

# List of all (potential) dependency files, derived from KEXT_OBJS
KEXT_DEPFILES = $(patsubst %.$(GAP_OBJEXT),%.d,$(KEXT_OBJS))

# Include the dependency tracking files
-include $(KEXT_DEPFILES)

# Mark *.d files as PHONY. This stops make from trying to recreate them
# (which it can't), and in particular from looking for potential source
# files. This can save quite a bit of disk access time.
.PHONY: $(KEXT_DEPFILES)

# The following flags instruct the compiler to enable advanced
# dependency tracking. Supported by GCC 3 and newer; clang; Intel C
# compiler; and more.
KEXT_DEPFLAGS = -MQ "$@" -MMD -MP -MF $(@D)/$(*F).d

# build rule for C code
# The dependency on GNUmakefile ensures that re-running configure recompiles everything
gen/%.$(GAP_OBJEXT): %.c GNUmakefile
	@mkdir -p $(@D)
	$(QUIET_GAC)$(GAC) -d -p "$(KEXT_DEPFLAGS)" -p "$(KEXT_CFLAGS)" -c $< -o $@

# build rule for C++ code
# The dependency on GNUmakefile ensures that re-running configure recompiles everything
gen/%.$(GAP_OBJEXT): %.cpp GNUmakefile
	@mkdir -p $(@D)
	$(QUIET_GAC)$(GAC) -d -p "$(KEXT_DEPFLAGS)" -p "$(KEXT_CXXFLAGS)" -c $< -o $@

# build rule for assembler code
# The dependency on GNUmakefile ensures that re-running configure recompiles everything
gen/%.$(GAP_OBJEXT): %.s GNUmakefile
	@mkdir -p $(@D)
	$(QUIET_GAC)$(GAC) -d -p "$(KEXT_DEPFLAGS)" -p "$(KEXT_CFLAGS)" -c $< -o $@

# build rule for linking all object files together into a kernel extension
$(KEXT_SO): $(KEXT_OBJS)
	@mkdir -p $(@D)
	$(QUIET_GAC)$(GAP_CXX) -o $@ $(GAP_LDFLAGS) $(GAC_LDFLAGS) $(KEXT_OBJS) $(KEXT_LDFLAGS)

# hook into `make clean`
clean: clean-kext
clean-kext:
	rm -rf $(KEXT_BINARCHDIR) gen

# hook into `make distclean`
distclean: distclean-kext
distclean-kext:
	rm -rf bin gen GNUmakefile
	rm -rf doc/_*.xml
	rm -rf doc/*.aux doc/*.bbl doc/*.blg doc/*.brf doc/*.idx doc/*.idx
	rm -rf doc/*.ilg doc/*.ind doc/*.log doc/*.out doc/*.pnr doc/*.toc

# hook into `make doc`
doc: doc-kext
doc-kext:
	$(GAP) --quitonbreak -b -q < makedoc.g

# hook into `make check`
check: check-kext
check-kext:
	$(GAP) tst/testall.g

# re-run configure if configure, GNUmakefile.in or GAP itself changed
GNUmakefile: configure GNUmakefile.in $(GAPPATH)/sysinfo.gap
	$(KEXT_RECONF)

ifdef KEXT_USE_AUTOCONF

# react to modifications of the build system
configure_deps = configure.ac $(wildcard m4/*.m4)

ifneq ($(MAINTAINER_MODE),no)
configure: $(configure_deps)
	@if command -v autoconf >/dev/null 2>&1 ; then \
	   echo "running autoconf" ; \
	   autoconf ; \
	 else \
	   echo "autoconf not available, proceeding with stale configure" ; \
	 fi
endif # MAINTAINER_MODE

# re-run configure if configure, GNUmakefile.in or GAP itself changed
config.status: configure $(GAPPATH)/sysinfo.gap
	./config.status --recheck

# update GNUmakefile if config.status changed
GNUmakefile: config.status

gen/pkgconfig.h: gen/pkgconfig.h.stamp
	@if test ! -f $@; then rm -f $<; else :; fi
	@if test ! -f $@; then $(MAKE) $<; else :; fi

gen/pkgconfig.h.stamp: src/pkgconfig.h.in config.status
	@rm -f $@
	@mkdir -p $(@D)
	./config.status gen/pkgconfig.h
	echo > $@

ifneq ($(MAINTAINER_MODE),no)
src/pkgconfig.h.in: $(configure_deps)
	@if command -v autoheader >/dev/null 2>&1 ; then \
	   mkdir -p $(@D) ; \
	   echo "running autoheader" ; \
	   autoheader ; \
	   rm -f gen/pkgconfig.h.stamp ; \
	 else \
	   echo "autoheader not available, proceeding with stale config.h" ; \
	 fi
	touch $@
endif # MAINTAINER_MODE

endif # KEXT_USE_AUTOCONF

.PHONY: check clean distclean doc
.PHONY: check-kext clean-kext distclean-kext doc-kext

########################################################################
# GNUmakefile debugging trick:
# call print-VARIABLE to see the runtime value of any variable
########################################################################
print-%:
	@echo '$*=$($*)'
