.POSIX:
DATE         = 1970-01-01
VERSION      = 0.1.0
NAME         = remembering
NAME_UC      = $(NAME)
## Installation prefix.  Defaults to "/usr".
PREFIX       = /usr
BINDIR       = $(PREFIX)/bin
LIBDIR       = $(PREFIX)/lib
GOLIBDIR     = $(LIBDIR)/go
SRCDIR       = $(PREFIX)/src/$(NAME)
SHAREDIR     = $(PREFIX)/share
LOCALEDIR    = $(SHAREDIR)/locale
MANDIR       = $(SHAREDIR)/man
EXEC         = ./
## Where to store the installation.  Empty by default.
DESTDIR      =
LDLIBS       = --static
GOCFLAGS     = -I $(GOLIBDIR)
GOLDFLAGS    = -L $(GOLIBDIR)
N            = `nproc`



.SUFFIXES:
.SUFFIXES: .go .a .bin .bin-check .adoc

.go.a:
	go tool compile -I $(@D) $(GOCFLAGS)  -o $@ -p $(*F) \
		`find $< $$(if [ $(*F) != main ]; then \
			echo src/$(NAME).go src/meta.go; fi) | uniq`

.a.bin:
	go tool link    -L $(@D) $(GOLDFLAGS) -extld $(CC) \
		-o $@ --extldflags '$(LDLIBS)' $<

.adoc:
	asciidoctor -b manpage -o $@ $<



all:
include deps.mk


libs.a           = $(libs.go:.go=.a)
mains.a          = $(mains.go:.go=.a)
mains.bin        = $(mains.go:.go=.bin)
functional/lib.a = $(functional/lib.go:.go=.a)
fuzz/lib.a       = $(fuzz/lib.go:.go=.a)
benchmarks/lib.a = $(benchmarks/lib.go:.go=.a)
manpages         = $(manpages.adoc:.adoc=)

sources = \
	src/$(NAME).go                 \
	src/meta.go                    \
	src/main.go                    \


derived-assets = \
	src/meta.go                    \
	$(libs.a)                      \
	$(mains.a)                     \
	$(mains.bin)                   \
	$(NAME).bin                    \
	$(manpages)                    \

side-assets = \
	tests/fuzz/corpus/             \
	tests/benchmarks/*/main.txt    \
	tests/test-profiles/           \



## Default target.  Builds all artifacts required for testing
## and installation.
all: $(derived-assets)


$(libs.a): Makefile deps.mk
$(libs.a): src/$(NAME).go src/meta.go


$(fuzz/lib.a):
	go tool compile $(GOCFLAGS) -o $@ -p $(NAME) -d=libfuzzer \
		$*.go src/$(NAME).go src/meta.go

src/meta.go: Makefile
	echo 'package $(NAME)'                    > $@
	echo 'const Version   = "$(VERSION)"'    >> $@
	echo 'const Name      = "$(NAME)"'       >> $@
	echo 'const Date      = "$(DATE)"'       >> $@

$(NAME).bin: src/main.bin
	ln -fs src/main.bin $@



tests.bin-check = \
	tests/main.bin-check \
	$(functional/main.go:.go=.bin-check) \

$(tests.bin-check):
	$(EXEC)$*.bin

check-unit: $(tests.bin-check)


integration-tests = \
	tests/cli-opts.sh              \
	tests/ranking.sh               \
	tests/signals.sh               \

.PRECIOUS: $(integration-tests)
$(integration-tests): $(NAME).bin
$(integration-tests): ALWAYS
	sh $@

check-integration: $(integration-tests)
check-integration: fuzz


## Run all tests.  Each test suite is isolated, so that a parallel
## build can run tests at the same time.  The required artifacts
## are created if missing.
check: check-unit check-integration



FUZZSEC=1
fuzz/main.bin-check = $(fuzz/main.go:.go=.bin-check)
$(fuzz/main.bin-check):
	$(EXEC)$*.bin --test.fuzztime=$(FUZZSEC)s --test.parallel=$N \
		--test.fuzz='.*' --test.fuzzcachedir=tests/fuzz/corpus

fuzz: $(fuzz/main.bin-check)



benchmarks/main.bin-check = $(benchmarks/main.go:.go=.bin-check)
$(benchmarks/main.bin-check):
	printf '%s\n' '$(EXEC)$*.bin'            > $*.txt
	LANG=POSIX.UTF-8 time -p $(EXEC)$*.bin 2>> $*.txt
	printf '%s\n' '$*.txt'

bench: $(benchmarks/main.bin-check)



## Remove *all* derived artifacts produced during the build.
## A dedicated test asserts that this is always true.
clean:
	rm -rf $(derived-assets) $(side-assets)


## Installs into $(DESTDIR)$(PREFIX).  Its dependency target
## ensures that all installable artifacts are crafted beforehand.
install: all
	mkdir -p \
		'$(DESTDIR)$(BINDIR)'     \
		'$(DESTDIR)$(GOLIBDIR)'   \
		'$(DESTDIR)$(SRCDIR)'     \

	cp $(NAME).bin       '$(DESTDIR)$(BINDIR)'/$(NAME)
	cp src/$(NAME).a     '$(DESTDIR)$(GOLIBDIR)'
	cp $(sources)        '$(DESTDIR)$(SRCDIR)'
	for f in $(manpages); do \
		n=`basename "$$f"`; \
		section=$${n##*.}; \
		mkdir -p '$(DESTDIR)$(MANDIR)'/man$$section; \
		cp "$$f" '$(DESTDIR)$(MANDIR)'/man$$section; \
	done

## Uninstalls from $(DESTDIR)$(PREFIX).  This is a perfect mirror
## of the "install" target, and removes *all* that was installed.
## A dedicated test asserts that this is always true.
uninstall:
	rm -rf \
		'$(DESTDIR)$(BINDIR)'/$(NAME)         \
		'$(DESTDIR)$(GOLIBDIR)'/$(NAME).a     \
		'$(DESTDIR)$(SRCDIR)'                 \

	for f in $(manpages); do \
		n=`basename "$$f"`; \
		section=$${n##*.}; \
		rm -f '$(DESTDIR)$(MANDIR)'/man$$section/$$n; \
	done



ALWAYS:
