ifneq (1,$(MAKING_CLEAN))
all: libf
endif
$(call ShakeNMake.CALL.CLEAN-SET,libf)

CPPFLAGS += -DBUILD_libfossil -DSQLITE_CORE
LIBF.EXTRA_LIBS := -lz
LIBF.EXTRA_LIBS += $(LDFLAGS_MODULE_LOADER)
LIBF.MAKEFILE := $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
# libfossil*.* are "public" names for use with deps in subdir sources.
LIBF_AMAL_D := @srcdir@
libfossil.c := $(LIBF_AMAL_D)/libfossil.c
libfossil.o := $(LIBF_AMAL_D)/libfossil.o
libfossil.h := $(LIBF_AMAL_D)/libfossil.h
libfossil-config.h := $(LIBF_AMAL_D)/libfossil-config.h
CLEAN.libf += $(libfossil.o) $(libfossil.h) $(libfossil.c) $(libfossil-config.h)

# Flags for clients of the shared/static library:
LIBF_CLIENT_LDFLAGS := -L$(DIR.top) -lfossil -lz
SQLITE3.OBJ := $(DIR.src)/sqlite3.o
SQLITE3.C := $(wildcard $(DIR.src)/sqlite3.c)
ifneq (,$(SQLITE3.C))
  HAVE_OWN_SQLITE := 1
else
  HAVE_OWN_SQLITE := 0
  LIBF_CLIENT_LDFLAGS := -lsqlite3
endif
# $(libfossil.o) client .o files should have these as deps:
LIBF_STATIC_CLIENT_OBJ_DEPS := $(libfossil.o)
ifeq (1,$(HAVE_OWN_SQLITE))
  LIBF_STATIC_CLIENT_OBJ_DEPS += $(SQLITE3.OBJ)
endif
# $(libfossil.o) client .o files should link with:
LIBF_STATIC_CLIENT_LDFLAGS := $(LIBF_STATIC_CLIENT_OBJ_DEPS) -lz -lm
# ^^^ fixme: add -lpthread when using external sqlite3.


# FSL.SRC.BASE = all sources which can go in the amalgamation build
# FSL.SRC = FSL.SRC.BASE + generated/added sources
FSL.SRC.BASE := $(patsubst %,$(DIR.src)/%, \
	fsl.c \
	annotate.c \
	appendf.c \
	auth.c \
	bag.c \
	buffer.c \
	cache.c \
	checkin.c \
	checkout.c \
	cli.c \
	content.c \
	config.c \
	cx.c \
  db.c \
	deck.c \
	delta.c \
	diff.c \
	diff2.c \
	encode.c \
	event.c \
	fs.c \
	forum.c \
	glob.c \
	io.c \
	leaf.c \
	list.c \
	lookslike.c \
	md5.c \
	merge.c \
	merge3.c \
	popen.c \
	pq.c \
	repo.c \
	schema.c \
	search.c \
	sha1.c \
	sha3.c \
	strftime.c \
	tag.c \
	ticket.c \
	udf.c \
	utf8.c \
	vfile.c \
	vpath.c \
	wiki.c \
	zip.c)

FSL_ENABLE_SQLITE_REGEXP := 0
ifeq (1,$(FSL_ENABLE_SQLITE_REGEXP))
  FSL.SRC.BASE += ext_regexp.c
endif

FSL.SRC := $(FSL.SRC.BASE)
ifeq (1,$(HAVE_OWN_SQLITE))
  FSL.SRC += $(SQLITE3.C)
endif

FSL.OBJ := $(patsubst %.c,%.o,$(FSL.SRC))
$(FSL.OBJ): $(LIBF.MAKEFILE)
CLEAN.libf += $(FSL.OBJ)

########################################################################
# Transform schema SQL files into source form. We don't use fossil(1)'s
# approach because it relies on unspecified length limits on C string
# literals. Yeah, it works, but i'm funny about the C Standard.
#include $(TOP_SRCDIR_REL)/tools.make
BIN.TEXT2C := $(DIR.tools)/text2c
$(BIN.TEXT2C): $(DIR.tools)/text2c.c
	cc $< -o $@
DISTCLEAN.libf += $(BIN.TEXT2C)

define SQL2C
$(2):
$(1).c: $(2) $$(BIN.TEXT2C)
ifneq (1,$(MAKING_CLEAN))
	@echo "Creating $$@ from $(2)..."; \
	{ \
		echo '/* Binary form of file $(2) */'; \
		echo '/** @page page_$$(notdir $1) Schema: $$(notdir $(2))'; \
		echo '@code'; \
		cat "$(2)"; \
		echo ' @endcode'; \
		echo ' @see $$(subst _cstr,,$$(notdir $1))()'; \
		echo '*/'; \
		$$(BIN.TEXT2C) fsl_$$(notdir $1) < $(2); \
		echo '/* end of $(2) */'; \
	} > $$@;
endif
FSL.SRC += $(1).c
FSL.SRC.BASE += $(1).c
FSL.OBJ += $(1).o
DISTCLEAN.libf += $(1).c
sql: $(1).c
endef

SQL.DIR := @srcdir@/sql
$(eval $(call SQL2C,$(DIR.src)/schema_config_cstr,$(SQL.DIR)/config.sql))
$(eval $(call SQL2C,$(DIR.src)/schema_repo1_cstr,$(SQL.DIR)/repo-static.sql))
$(eval $(call SQL2C,$(DIR.src)/schema_repo2_cstr,$(SQL.DIR)/repo-transient.sql))
$(eval $(call SQL2C,$(DIR.src)/schema_ckout_cstr,$(SQL.DIR)/checkout.sql))
$(eval $(call SQL2C,$(DIR.src)/schema_ticket_cstr,$(SQL.DIR)/ticket.sql))
$(eval $(call SQL2C,$(DIR.src)/schema_ticket_reports_cstr,$(SQL.DIR)/ticket-reports.sql))
$(eval $(call SQL2C,$(DIR.src)/schema_forum_cstr,$(SQL.DIR)/forum.sql))
# end SQL transformation bits
########################################################################

# These are the flags used by fossil's embedded sqlite3:
$(SQLITE3.OBJ): CPPFLAGS+=-DNDEBUG=1 \
                 -DSQLITE_DQS=0 \
                 -DSQLITE_THREADSAFE=0 \
                 -DSQLITE_DEFAULT_MEMSTATUS=0 \
                 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 \
                 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS \
                 -DSQLITE_OMIT_DECLTYPE \
                 -DSQLITE_OMIT_PROGRESS_CALLBACK \
                 -DSQLITE_OMIT_SHARED_CACHE \
                 -DSQLITE_OMIT_LOAD_EXTENSION \
                 -DSQLITE_MAX_EXPR_DEPTH=0 \
                 -DSQLITE_USE_ALLOCA \
                 -DSQLITE_ENABLE_LOCKING_STYLE=0 \
                 -DSQLITE_DEFAULT_FILE_FORMAT=4 \
                 -DSQLITE_ENABLE_EXPLAIN_COMMENTS \
                 -DSQLITE_ENABLE_FTS4 \
                 -DSQLITE_ENABLE_DBSTAT_VTAB \
                 -DSQLITE_ENABLE_JSON1 \
                 -DSQLITE_ENABLE_FTS5 \
                 -DSQLITE_ENABLE_STMTVTAB \
                 -DSQLITE_HAVE_ZLIB \
                 -DSQLITE_INTROSPECTION_PRAGMAS \
                 -DSQLITE_ENABLE_DBPAGE_VTAB \
                 -DSQLITE_TRUSTED_SCHEMA=0

# FIXME: update libf sql tracing: -DSQLITE_OMIT_DEPRECATED

$(SQLITE3.OBJ): CFLAGS+=-Wno-sign-compare
ifneq (,$(CC_PROFILE_FLAG))
$(SQLITE3.OBJ): CFLAGS:=$(filter-out $(CC_PROFILE_FLAG),$(CFLAGS))
# ^^^ gprof data into sqlite3 is just noise for us, so strip the
# profiling flag from this file.
endif
ifneq (,$(filter clang,$(CC)))
# Workaround for clang
$(SQLITE3.OBJ): CFLAGS+=-Wno-unused-const-variable
endif

CLEAN.libf += $(FSL.OBJ)
ifeq (1,$(HAVE_OWN_SQLITE))
# in-tree sqlite3
# -lm: one of the sqlite build opts (FTS?) requires log(3).
  LIBF.EXTRA_LIBS += -lm
else
# system/external sqlite3
  LIBF.EXTRA_LIBS += -lpthread
endif

libfossil.DLL.OBJECTS := $(FSL.OBJ)
libfossil.DLL.LDFLAGS := @SH_LDFLAGS@ $(LIBF.EXTRA_LIBS)
libfossil.LIB.OBJECTS := $(libfossil.DLL.OBJECTS)
########################################################################
# Shared lib
ifeq (1,@LIBFOSSIL_SHARED@)
$(eval $(call ShakeNMake.CALL.RULES.DLLS,libfossil))
CLEAN.libf += $(libfossil.DLL)
libf: $(libfossil.DLL)
$(libfossil.DLL): $(libfossil.DLL.OBJECTS)
ShakeNMake.install.dlls += $(libfossil.DLL)
endif

# Static lib
ifeq (1,@LIBFOSSIL_STATIC@)
$(eval $(call ShakeNMake.CALL.RULES.LIBS,libfossil))
libf: $(libfossil.LIB)
$(libfossil.LIB): $(libfossil.LIB.OBJECTS)
CLEAN.libf += $(libfossil.LIB)
ShakeNMake.install.libs += $(libfossil.LIB)
endif

########################################################################
# $(libfossil.library) is intended to be used as a dependency for
# clients which link to -lfossil. It will be either the DLL or LIB file
# for the library. Reminder: we cannot use $(wildcard) here because
# this string is, on the first build, eval'd before libfossil is
# compiled.
libfossil.library := $(word 1,$(libfossil.DLL) $(libfossil.LIB))
#$(info libfossil.library=$(libfossil.library))

########################################################################
# A quick-n-dirty amalgamation build...
DIR.inc-fossil := $(DIR.include)/fossil-scm

############################################################
# libfossil.c.SRC = the list of source files (.c and private .h) to include
# in $(libfossil.c).
#libfossil.c.SRC :=	fossil-ext_regexp.h
libfossil.c.SRC += \
	$(FSL.SRC.BASE)

ifeq (0,1)
# the tcl bits currently break the amalgamation
libfossil.c.SRC += \
	$(COMPAT_DIR)/javavm/export/jni_md.h \
	$(COMPAT_DIR)/javavm/export/jni.h \
	$(COMPAT_DIR)/tcl-8.6/generic/tcl.h \
	$(COMPAT_DIR)/tcl-8.6/generic/tclDecls.h \
	$(COMPAT_DIR)/tcl-8.6/generic/tclPlatDecls.h
endif

############################################################
# libfossil.h.SRC = the list of public header files to include
# in $(libfossil.h).
libfossil.h.SRC := \
	$(DIR.inc-fossil)/fossil-config.h \
	$(DIR.inc-fossil)/fossil-util.h \
	$(DIR.inc-fossil)/fossil-core.h \
	$(DIR.inc-fossil)/fossil-db.h \
	$(DIR.inc-fossil)/fossil-hash.h \
	$(DIR.inc-fossil)/fossil-repo.h \
	$(DIR.inc-fossil)/fossil-checkout.h \
	$(DIR.inc-fossil)/fossil-confdb.h \
	$(DIR.inc-fossil)/fossil-vpath.h \
	$(DIR.inc-fossil)/fossil-internal.h \
	$(DIR.inc-fossil)/fossil-auth.h \
	$(DIR.inc-fossil)/fossil-forum.h \
	$(DIR.inc-fossil)/fossil-pages.h \
	$(DIR.inc-fossil)/fossil-cli.h
$(libfossil.h.SRC):
$(libfossil.c.SRC):
libfossil.h_MAKEFILES := $(filter-out $(ShakeNMake.CISH_DEPS_FILE),$(MAKEFILE_LIST))
$(libfossil.h): $(libfossil.h_MAKEFILES) $(libfossil.h.SRC) $(libfossil-config.h)
$(libfossil.c): $(libfossil.h_MAKEFILES) $(libfossil.h) $(libfossil.c.SRC)
$(libfossil-config.h): $(libfossil.h_MAKEFILES)
	@echo "Generating $@ ..."
	cd $(TOP_SRCDIR_REL) && sh configure --amal

$(libfossil.h): 
	@echo "Creating $@..."
	@{ \
		echo '#if !defined(FSL_AMALGAMATION_BUILD)'; \
		echo '#define FSL_AMALGAMATION_BUILD 1'; \
		echo '#endif'; \
		echo '#if defined(HAVE_CONFIG_H)'; \
		echo '#  include "config.h"'; \
		echo '#endif'; \
		echo '#include "$(notdir $(libfossil-config.h))"'; \
	} > $@
	@{ \
		for i in $(libfossil.h.SRC); do \
			echo "/* start of file $$i */"; \
			cat $$i; \
			echo "/* end of file $$i */"; \
		done; \
	} | sed  \
		 -e '/[ ]*#[ ]*include[ ]*.*fossil.*\.h[>"]/d' \
		 -e '/[ ]*#[ ]*include[ ]*.*".*config\.h"/d' \
		>> $@

$(libfossil.c): $(libfossil.h)
	@echo "Creating $@..."
	@echo '#include "$(notdir $(libfossil.h))"' > $@
	@{ \
		for i in $(libfossil.c.SRC); do \
			echo "/* start of file $$i */"; \
			cat $$i; \
			echo "/* end of file $$i */"; \
		done; \
	} | sed \
		 -e '/[ ]*#[ ]*include[ ]*.*fossil.*\.h[>"]/d' \
		>> $@

$(libfossil.o): $(FSL.OBJ)# avoids mixed build output
# We need to ensure that compiling the amalgamation does not pick up
# $(DIR.include)/libfossil.h...
$(libfossil.o): CPPFLAGS:=$(patsubst -I%,,$(CPPFLAGS)) -I$(DIR.top) -I$(DIR.src)
amal: $(libfossil.c)
# /amalgamation
########################################################################

########################################################################
# amalgamation "unversioned" files for hosting in the main fossil repo
amal-dist.zip := libfossil-amalgamation.zip
amal-dist.html := amalgamation.html
FDB := $(wildcard .fslckout _FOSSIL_)
LIBF_AMAL_CPP_FLAGS := -I$(DIR.top)
LIBF_AMAL_CPP_FLAGS += -I$(DIR.src)# for local sqlite3.h and sqlite3ext.h
$(libfossil.o): $(libfossil.c) $(libfossil.h) $(libfossil-config.h) $(FSL.SRC)
	@echo "Amalgamation files:"; \
	ls -la $(libfossil.c) $(libfossil.h) $(libfossil-config.h)
	$(CC) $(CPPFLAGS) $(LIBF_AMAL_CPP_FLAGS) $(CFLAGS) -c "$<" -o "$@"
	@echo "Reminder: it will need these sqlite3 files to build:"; \
	echo "sqlite3.h, sqlite3ext.h, and optionally a local copy of sqlite3.c"
	@echo "Reminder: run 'amal-push' from the top dir to push a build to the main server."
amal: $(libfossil.o)
.PHONY: amal $(amal-dist.zip) $(amal-dist.html) $(FDB)
$(FDB):
	@test -f $@ || { echo "Missing fossil checkout db."; exit 1; }
$(amal-dist.zip): $(libfossil.o) $(FDB)
	zip $@ $(libfossil.c) $(libfossil.h) $(libfossil-config.h)
SQL_VINFO := select e.mtime,b.uuid from event e, blob b where b.rid=e.objid and e.type='ci' order by e.mtime desc limit 1;
# ^^^^^^^ ==> 12345.6789,'hash'
$(amal-dist.html): $(FDB)
	@{ \
	echo "<div class='fossil-doc' data-title='Downloads'>"; \
	echo "<style>#download-list{ line-height: 1.5; font-size: 125%; white-space: pre-wrap; }</style>"; \
	echo "<p>This page hosts builds of the libfossil "; \
	echo "<a href='../wiki/AmalgamationBuild'>AmalgamationBuild</a>. "; \
	echo "It only hosts the \"latest\" build and is updated periodically by a "; \
	echo "project contributor."; \
	echo "</p>"; \
	echo "<pre id='download-list'>"; \
	echo "<a href='$(amal-dist.zip)'>$(amal-dist.zip)</a>"; \
	echo "Size: $$(ls -la $(amal-dist.zip) | awk '{print $$5}') bytes"; \
	vinfo=$$(echo "$(SQL_VINFO)" | fossil sql); \
	echo "Last updated (YYYY-MM-DD):" $$(echo "select strftime('%Y-%m-%d %H:%M',$${vinfo%%,*})" | fossil sql | cut -d\' -f2) UTC; \
	version=$$(echo $${vinfo} | cut -d\' -f2); \
	echo "Source code version: <a href='../info/$${version:0:16}'>$${version:0:16}</a>"; \
	echo "Zip file SHA3-256 hash:" $$(fossil sha3sum $(amal-dist.zip) | cut -d' ' -f1); \
	echo "</pre>"; \
	} > $@
	@echo "Created $@"
amal-dist: $(amal-dist.zip) $(amal-dist.html)
	vinfo=$$(echo "$(SQL_VINFO)" | fossil sql); \
	fossil uv add $(amal-dist.zip) $(amal-dist.html) --mtime $${vinfo%%,*}
	fossil uv list
amal-push: amal-dist
	fossil uv sync

DISTCLEAN.libf += $(amal-dist.zip) $(amal-dist.html)
CLEAN.libf += \
	$(wildcard $(DIR.src)/*~ \
	  $(DIR.include)/*~ \
	  $(DIR.include)/fossil-scm/*~ \
   )
