# SPDX-License-Identifier: MIT


CXX ?= c++
CC ?= cc
CPP ?= cpp
MANDOC ?= mandoc
AWK ?= awk
CARGO ?= cargo
LTO ?= y
FEBUG_VERSION ?= "$(patsubst v%,%,$(shell git describe))"
FEBUG_DATE ?= $(shell date $(shell date --version > /dev/null 2>&1 && echo "--date @" || echo "-r ")$(shell git log -1 --no-show-signature --format=%at) +"%B %d, %Y")
EXTRACCAR ?=
EXTRALDAR ?=

SYSTEM := $(shell uname -s)
ifeq "$(SYSTEM)" "NetBSD"
	FUSE_ARGS ?= -lrefuse
else ifeq "$(SYSTEM)" "OpenBSD"
	FUSE_ARGS ?= -lfuse
else
	FUSE_ARGS ?= $(shell pkg-config --libs --cflags fuse3)
endif

CXXVER := $(shell $(CXX) --version | head -1)
ifneq "$(findstring clang,$(CXXVER))" ""
	# GCC doesn't have this granularity
	CXXSPECIFICCC := -Wpedantic -Wno-c++20-designator -Wno-c99-extensions -Wno-unknown-warning-option
	ifeq "$(LTO)" "y"
		CXXSPECIFICLD := -flto=full  # Clang produces .o files with LLVM bitcode, which cannot be linked to if put in .as
	else
		CXXSPECIFICLD :=
	endif
else
	CXXSPECIFICCC := -Wno-missing-field-initializers -fno-common
	ifeq "$(LTO)" "y"
		CXXSPECIFICCC += -flto
	endif
	CXXSPECIFICLD :=
endif


OUTDIR ?= out/
OBJDIR ?= $(OUTDIR)obj/
CCAR := -g -O3 -pipe -Wall -Wextra -isysteminclude/ $(CXXSPECIFICCC) $(EXTRACCAR)
LDAR := -Wl,--as-needed -L$(OUTDIR) $(CXXSPECIFICLD) $(EXTRALDAR)
HEADERS := $(wildcard include/*.h include/*.hpp)
EXAMPLES := $(wildcard examples/*.c examples/*.cpp)
EXAMPLES_RS := $(wildcard examples/*.rs)
MANPAGES := $(wildcard man/*.[0123456789])
FEBUG_VERSION := $(FEBUG_VERSION)
FEBUG_DATE := $(FEBUG_DATE)
FUSE_ARGS := $(FUSE_ARGS)


.PHONY : main libfebug++ libfebug examples manpages rust-build rust-doc

all : main libfebug++ libfebug examples manpages how.png
clean:
	rm -rf $(OUTDIR) $(OBJDIR) how.png

main : $(OUTDIR)febug
libfebug++ : $(OUTDIR)libfebug++.a
libfebug : $(OUTDIR)libfebug.a $(OUTDIR)libfebug.so
examples : $(foreach l,$(patsubst %.c,$(OUTDIR)%,$(patsubst %pp,%,$(EXAMPLES))),$(l) $(l)-dont)
manpages : $(patsubst %,$(OUTDIR)%,$(MANPAGES)) $(OBJDIR)man/aliases
rust-build : $(OUTDIR)febug.rs/target/libfebug.rlib
rust-doc : $(OUTDIR)febug.rs/doc/febug/index.html


$(OUTDIR)febug : main.cpp $(HEADERS)
	@mkdir -p $(dir $@)
	$(CXX) $< -o$@ -DFEBUG_VERSION='$(FEBUG_VERSION)' -std=c++17 -fno-exceptions -fPIE $(CCAR) $(LDAR) $(FUSE_ARGS)


$(OBJDIR)febug++.o : febug.cpp $(HEADERS)
	@mkdir -p $(dir $@)
	$(CXX) -c $< -o$@ -std=c++17 -fPIC $(CCAR)

$(OUTDIR)libfebug++.a : $(OBJDIR)febug++.o
	@mkdir -p $(dir $@)
	ar crs $@ $^


$(OBJDIR)febug.o : febug.c $(HEADERS)
	@mkdir -p $(dir $@)
	$(CC) -c $< -o$@ -std=c11 -fPIC $(CCAR)

$(OUTDIR)libfebug.a : $(OBJDIR)febug.o
	@mkdir -p $(dir $@)
	ar crs $@ $^

$(OUTDIR)libfebug.so : $(OBJDIR)febug.o
	@mkdir -p $(dir $@)
	$(CC) -shared $< -o$(OUTDIR)libfebug.so.0 -std=c11 -fPIC $(CCAR) $(LDAR) -Wl,-soname,libfebug.so.0
	ln -fs libfebug.so.0 $@


$(OUTDIR)examples/% : examples/%.cpp $(OUTDIR)libfebug++.a $(HEADERS)
	@mkdir -p $(dir $@)
	$(CXX) $< -o$@              -std=c++17 -fPIE $(CCAR) $(LDAR) -lfebug++

$(OUTDIR)examples/%-dont : examples/%.cpp $(OUTDIR)libfebug++.a $(HEADERS)
	@mkdir -p $(dir $@)
	$(CXX) $< -o$@ -DFEBUG_DONT -std=c++17 -fPIE $(CCAR) $(LDAR) -lfebug++

$(OUTDIR)examples/% : examples/%.c $(OUTDIR)libfebug.a $(HEADERS)
	@mkdir -p $(dir $@)
	$(CC) $< -o$@              -std=c11 -fPIE $(CCAR) $(LDAR) -lfebug

$(OUTDIR)examples/%-dont : examples/%.c $(OUTDIR)libfebug.a $(HEADERS)
	@mkdir -p $(dir $@)
	$(CC) $< -o$@ -DFEBUG_DONT -std=c11 -fPIE $(CCAR) $(LDAR) -lfebug


$(OBJDIR)man/aliases : man/aliases
	@mkdir -p $(dir $@)
	@touch $@
	$(AWK) '!/^$$/ {print "ln -fs " $$1 " $(OUTDIR)man/" $$2}' man/aliases | sh -x

LP := (
RP := )
$(OUTDIR)man/% : man/% man/style.css $(wildcard man/*.h)
	@mkdir -p $(dir $@) $(dir $(OBJDIR)$<)
	(cd $(dir $<); $(CPP) -nostdinc -Wno-trigraphs -Wno-invalid-pp-token -CC -P -DFEBUG_DATE="$(FEBUG_DATE)" -DFEBUG_VERSION='$(FEBUG_VERSION)' - < $(notdir $<)) | \
		grep -v '^$$' | \
		(cd $(dir $<); $(AWK) '$$1 == "$$include" {gsub(/"/, "", $$2); while((getline line < $$2) > 0) {gsub(/\\/, "\\\\", line); print line}; next}  {print}') \
		> $(OBJDIR)$<
	$(MANDOC) -Tman $(OBJDIR)$< > $@
	$(MANDOC) -Thtml -Oincludes="https://git.sr.ht/~nabijaczleweli/febug/tree/trunk/item/include/%I" $(OBJDIR)$< | \
		$(AWK) '/<\/style>/ {print "<style>"; while(getline < "man/style.css") print; $$0 = "</style>"; print} /<style>/,/<\/style>/ {next}  {print}' | \
		sed -re 's/ title=".."//g' $(foreach l,$(subst man/,,$(MANPAGES)), -e 's;(<a class="Xr")>($(subst +,\+,$(subst \$(LP)rs,.rs,$(subst .,\$(LP),$(l))\$(RP))))</a>;\1 href="$(l).html">\2</a>;') > $@.html
# $(MANDOC) -Tlint $(OBJDIR)$<


$(OUTDIR)febug.rs/README.md : README.md
	@mkdir -p $(dir $@)
	ln -f $^ $@ 2>/dev/null || cp $^ $@

$(OUTDIR)febug.rs/%.rs : febug.rs/%.rs
	@mkdir -p $(dir $@)
	ln -f $^ $@ 2>/dev/null || cp $^ $@

$(OUTDIR)febug.rs/examples/%.rs : examples/%.rs
	@mkdir -p $(dir $@)
	ln -f $^ $@ 2>/dev/null || cp $^ $@

$(OUTDIR)febug.rs/target/libfebug.rlib : $(OUTDIR)febug.rs/Cargo.toml $(OUTDIR)febug.rs/lib.rs $(OUTDIR)febug.rs/build.rs $(OUTDIR)febug.rs/README.md $(patsubst %,$(OUTDIR)febug.rs/%,$(EXAMPLES_RS))
	@mkdir -p $(OUTDIR)examples/
	cd $(dir $<); FEBUG_DONT=1 $(CARGO) build --release --examples
	$(foreach l,$(patsubst %.rs,%,$(EXAMPLES_RS)),mv $(OUTDIR)febug.rs/target/release/$(l) $(OUTDIR)$(l)-dont; )
	cd $(dir $<); $(CARGO) build --release --examples
	$(foreach l,$(patsubst %.rs,%,$(EXAMPLES_RS)),mv $(OUTDIR)febug.rs/target/release/$(l) $(OUTDIR)$(l); )

$(OUTDIR)febug.rs/doc/febug/index.html : $(OUTDIR)febug.rs/target/libfebug.rlib
	cd $(dir $<); $(CARGO) doc --release

$(OUTDIR)febug.rs/Cargo.toml : febug.rs/Cargo.toml
	@mkdir -p $(dir $@)
	sed -e 's;FEBUG_VERSION;$(FEBUG_VERSION);' $< > $@


how.png : how.dot
	dot -Tpng $^ -o $@
