ifneq ($(words $(MAKECMDGOALS)),1) # if no argument was given to make...
.DEFAULT_GOAL = all
%:                   # define a last resort default rule
	@$(MAKE) $@ --no-print-directory -rRf $(firstword $(MAKEFILE_LIST)) # recursive make call, 
else
	ifndef ECHO
	T := $(shell $(MAKE) $(MAKECMDGOALS) --no-print-directory \
		-nrRf $(firstword $(MAKEFILE_LIST)) \
		ECHO="COUNTTHIS" | grep -c "COUNTTHIS")
	L := $(shell echo -n $T | wc -m)
	ifeq ($(NO_COLOR),)
		GREEN := $(shell printf '\033[32m')
		RESET := $(shell printf '\033[0m')
	endif
	ECHO_NOPROG = printf "    $(1)\t$(2)\n"
	ECHO = printf "    %-12s[%$Ld/%$Ld]\t$(2)\n" \
		$(1) \
		$(shell SHELL=$(SHELL) flock $(LOCK) -c 'read n < $(MARK); echo $$n; echo $$((n+1)) > $(MARK)') \
		$T
	endif
	# end for progress block, but not for else in line 5

V := {{VERBOSE}}
ifeq ($V,1)
	Q :=
	ECHO :=
	ECHO_NOPROG := 
else
	Q := @
endif


VERSION := {{VERSION}}
TAG_TIME := {{TAG_TIME}}
ARCH := $(shell uname -m)

TARGET := ceccomp test

SRC_DIR := src
INC_DIR := include
TEST_DIR := test
BUILD_DIR := build
BUILD_UTIL := $(BUILD_DIR)/utils
BUILD_LEXICAL := $(BUILD_DIR)/lexical
BUILD_RESOLVER := $(BUILD_DIR)/resolver
BUILD_DECODER := $(BUILD_DIR)/decoder

LOCK := $(BUILD_DIR)/lock
MARK := $(BUILD_DIR)/progress

C_SRCS := $(shell find $(SRC_DIR) ! -name 'ceccomp.c' -name '*.c' -or -name '*.s' | LC_ALL=C sort)
INC_SRCS := $(shell find $(INC_DIR) -name '*.h' | LC_ALL=C sort)
TEST_SRCS := $(TEST_DIR)/unit_test.c

OBJS := $(patsubst $(SRC_DIR)/%.c,$(BUILD_DIR)/%.c.o,$(C_SRCS))
TEST_OBJS := $(patsubst $(TEST_DIR)/%.c,$(BUILD_DIR)/%.c.o,$(TEST_SRCS))

{{DOC_IF}}
DOC_DIR := docs
IMG_DIR := images
SRC_IMG_DIR := $(DOC_DIR)/$(IMG_DIR)
BUILD_IMG_DIR := $(BUILD_DIR)/$(IMG_DIR)
IMG_SRCS := $(shell find $(SRC_IMG_DIR) -name "*.webp")
{{DOC_ENDIF}}

CECCOMP_MAIN := $(BUILD_DIR)/ceccomp.c.o
CECCOMP_C := $(SRC_DIR)/ceccomp.c

CC := {{CC}}

LOCALE_DIR := {{LOCALEDIR}}
CFLAGS := -fpie -fstack-protector -Wall -Wextra {{SYS_INC_DIR}} {{EXTRA_CFLAGS}}
LDFLAGS := -z now -z noexecstack -fpie -fstack-protector -Wall -Wextra {{SYS_LIB_DIR}} -lseccomp {{LIBARGP}} {{EXTRA_LDFLAGS}}
DEBUG := {{DEBUG_LEVEL}}

ifdef DEBUG
	ifeq ($(DEBUG),1)
		CFLAGS += -g -O2 -fno-omit-frame-pointer {{ARCH_PRESERVE_FP}}
		LDFLAGS += -g -O2
	else ifeq ($(DEBUG),2)
		CFLAGS += -g3 -O0 -DDEBUG # O0 preserve fp by default
		LDFLAGS += -g3 -O0
	endif
else
	CFLAGS += -O2
	LDFLAGS += -O2 -s
endif

STATIC := {{IS_STATIC}}
ifeq ($(STATIC), 1)
	CFLAGS += -static
	LDFLAGS += -static
endif

all: ceccomp {{DOC_IF}}doc{{DOC_ENDIF}} {{I18N_IF}}mo{{I18N_ENDIF}}

{{I18N_IF}}
##### INTERNATIONALIZATION

I18N_DIR := po

PO_ZHCN := $(I18N_DIR)/zh_CN.po
MO_ZHCN := $(patsubst $(I18N_DIR)/%.po,$(BUILD_DIR)/%.mo,$(PO_ZHCN))
update-po:
	$Q$(MAKE) -C $(I18N_DIR) --no-print-directory Q=$Q

$(MO_ZHCN): $(PO_ZHCN) | $(BUILD_DIR) $(MARK)
	$Q$(call ECHO,MSGFMT,$@)
	$Qmsgfmt -o $@ $<

mo: $(MO_ZHCN)
	$Q$(call ECHO_NOPROG,$(GREEN)BUILT,mo$(RESET))

.PHONY: update-po mo
{{I18N_ENDIF}}

##### DOCUMENTATION PART #####
{{DOC_IF}}
MAN_OBJ := $(BUILD_DIR)/ceccomp.1
MAN_CHN := $(BUILD_DIR)/cn/ceccomp.1
HTML_OBJ := $(BUILD_DIR)/ceccomp.html
HTML_CHN := $(BUILD_DIR)/ceccomp-cn.html
ASCIIDOC := {{ASCIIDOC}}

doc: doc_html doc_man

doc_man: $(MAN_OBJ) $(MAN_CHN)
	$Q$(call ECHO_NOPROG,$(GREEN)BUILT,man doc$(RESET))

doc_html: $(HTML_OBJ) $(HTML_CHN)
	$Q$(call ECHO_NOPROG,$(GREEN)BUILT,html doc$(RESET))

$(MAN_OBJ): $(DOC_DIR)/ceccomp.adoc | $(BUILD_DIR) $(MARK)
	$Q$(call ECHO,ADOC,$@)
	$Q$(ASCIIDOC) -b manpage $< -a VERSION=$(VERSION) -a ARCH=$(ARCH) -a TAG_TIME=$(TAG_TIME) -o $@

$(MAN_CHN): $(DOC_DIR)/ceccomp.zh_CN.adoc | $(BUILD_DIR) $(MARK)
	$Q$(call ECHO,ADOC,$@)
	$Q$(ASCIIDOC) -b manpage $< -a VERSION=$(VERSION) -a ARCH=$(ARCH) -a TAG_TIME=$(TAG_TIME) -o $@

$(HTML_OBJ): $(DOC_DIR)/ceccomp.adoc | $(BUILD_DIR) $(MARK)
	$Q$(call ECHO,ADOC,$@)
	$Q$(ASCIIDOC) -b html5 $< -a VERSION=$(VERSION) -a ARCH=$(ARCH) -a TAG_TIME=$(TAG_TIME) -o $@

$(HTML_CHN): $(DOC_DIR)/ceccomp.zh_CN.adoc | $(BUILD_DIR) $(MARK)
	$Q$(call ECHO,ADOC,$@)
	$Q$(ASCIIDOC) -b html5 $< -a VERSION=$(VERSION) -a ARCH=$(ARCH) -a TAG_TIME=$(TAG_TIME) -o $@

.PHONY: doc doc_man doc_html
{{DOC_ENDIF}}


##### INSTALL CECCOMP #####

DESTDIR := {{DESTDIR}}
PREFIX := {{PREFIX}}
BIN_DIR := {{BINDIR}}
ZSH_FPATH := {{ZSH_FPATH}}
ZSH_SRC := completions

install: bin_install zsh_cmp_install {{DOC_IF}}doc_install{{DOC_ENDIF}} {{I18N_IF}}mo_install{{I18N_ENDIF}}

bin_install: ceccomp $(BUILD_DIR)/ceccomp
	$Q$(call ECHO_NOPROG,INSTALL,$< $(BIN_DIR))
	$Qinstall -Dt $(DESTDIR)$(BIN_DIR) $(BUILD_DIR)/ceccomp

zsh_cmp_install: $(ZSH_SRC)/_ceccomp
	$Q$(call ECHO_NOPROG,INSTALL,$< $(ZSH_FPATH))
	$Qinstall -Dm 0644 -t $(DESTDIR)$(ZSH_FPATH) $<

.PHONY: bin_install zsh_cmp_install install

{{DOC_IF}}
MAN_DIR := {{MANDIR}}
MAN_DST := $(MAN_DIR)/man1
MAN_CHN_DST := $(MAN_DIR)/zh_CN/man1
DOC_INSTALL_DIR := {{DOCDIR}}
HTML_DST := $(DOC_INSTALL_DIR)/html

doc_install: doc doc_man_install doc_html_install {{I18N_IF}}doc_man_cn_install{{I18N_ENDIF}} doc_images_install
	$Q$(call ECHO_NOPROG,INSTALL,README.md $(DOC_INSTALL_DIR))
	$Qinstall -Dm 0644 -t $(DESTDIR)$(DOC_INSTALL_DIR) README.md

doc_man_install: $(MAN_OBJ)
	$Q$(call ECHO_NOPROG,INSTALL,$< $(MAN_DST))
	$Qinstall -Dm 0644 -t $(DESTDIR)$(MAN_DST) $<

doc_man_cn_install: $(MAN_CHN)
	$Q$(call ECHO_NOPROG,INSTALL,$< $(MAN_CHN_DST))
	$Qinstall -Dm 0644 -t $(DESTDIR)$(MAN_CHN_DST) $<

doc_html_install: $(HTML_OBJ) $(HTML_CHN)
	$Q$(call ECHO_NOPROG,INSTALL,$< $(HTML_DST))
	$Qinstall -Dm 0644 -t $(DESTDIR)$(HTML_DST) $^

doc_images_install: $(IMG_SRCS)
	$Q$(call ECHO_NOPROG,INSTALL,images $(HTML_DST))
	$Qinstall -Dm 0644 -t $(DESTDIR)$(HTML_DST)/images $^

.PHONY: doc_man_install doc_html_install doc_man_cn_install doc_images_install doc_install 
{{DOC_ENDIF}}

{{I18N_IF}}
mo_install: $(MO_ZHCN)
	$Q$(call ECHO_NOPROG,INSTALL,$< $(LOCALE_DIR))
	$Qinstall -Dm 0644 $< $(patsubst $(BUILD_DIR)/%.mo,$(DESTDIR)$(LOCALE_DIR)/%/LC_MESSAGES/ceccomp.mo,$<)

.PHONY: mo_install
{{I18N_ENDIF}}

UNINSTALL = test -f $(1) && rm -f $(1) || :
UNINSTALL_RECURSIVE = test -d $(1) && rm -rf $(1) || :
uninstall:
	$Q$(call ECHO_NOPROG,UNINSTALL,$(BIN_DIR)/ceccomp)
	$Q$(call UNINSTALL,$(DESTDIR)$(BIN_DIR)/ceccomp)
	$Q$(call ECHO_NOPROG,UNINSTALL,$(ZSH_FPATH)/_ceccomp)
	$Q$(call UNINSTALL,$(DESTDIR)$(ZSH_FPATH)/_ceccomp)
	{{DOC_IF}}
	$Q$(call ECHO_NOPROG,UNINSTALL,$(MAN_DIR)/man1/ceccomp.1)
	$Q$(call UNINSTALL,$(DESTDIR)$(MAN_DIR)/man1/ceccomp.1)
	$Q$(call ECHO_NOPROG,UNINSTALL,$(MAN_DIR)/zh_CN/man1/ceccomp.1)
	$Q$(call UNINSTALL,$(DESTDIR)$(MAN_DIR)/zh_CN/man1/ceccomp.1)
	$Q$(call ECHO_NOPROG,UNINSTALL,$(DOC_INSTALL_DIR))
	$Q$(call UNINSTALL_RECURSIVE,$(DESTDIR)$(DOC_INSTALL_DIR)/../ceccomp) # in case DOC_INSTALL_DIR is not set...
	{{DOC_ENDIF}}

.PHONY: uninstall


#### C OBJECTS ###

CONFIG_HEADER := $(INC_DIR)/config.h
$(CONFIG_HEADER): Makefile | $(MARK)
	$Q$(call ECHO,SED,$@)
	$Qsed 's/@@VERSION@@/$(VERSION)/;s/@@TAG_TIME@@/$(TAG_TIME)/;s/@@BUILDER@@/{{BUILDER}}/;{{LOCALE_SED}}' \
		$(CONFIG_HEADER).in > $(CONFIG_HEADER)

ceccomp: $(BUILD_DIR)/ceccomp
	$Q$(call ECHO_NOPROG,$(GREEN)BUILT,$@$(RESET))

$(BUILD_DIR)/ceccomp: $(OBJS) $(CECCOMP_MAIN) | $(MARK)
	$Q$(call ECHO,LD,$@)
	$Q$(CC) $^ -o $@ $(LDFLAGS)

test: $(BUILD_DIR)/test
	$Q$(call ECHO_NOPROG,$(GREEN)BUILT,$@$(RESET))

$(BUILD_DIR)/test: $(TEST_OBJS) | $(MARK)
	$Q$(call ECHO,LD,$@)
	$Q$(CC) $^ -o $@ $(LDFLAGS)

$(BUILD_DIR)/ceccomp.c.o: $(SRC_DIR)/ceccomp.c $(CONFIG_HEADER) | $(BUILD_DIR) $(MARK)
	$Q$(call ECHO,CC,$@)
	$Q$(CC) -I$(INC_DIR) $(CFLAGS) $< -c -o $@

$(BUILD_DIR)/%.c.o: $(SRC_DIR)/%.c | $(BUILD_DIR) $(MARK) $(CONFIG_HEADER)
	$Q$(call ECHO,CC,$@)
	$Q$(CC) -I$(INC_DIR) $(CFLAGS) $< -c -o $@
$(BUILD_DIR)/%.c.o: $(TEST_DIR)/%.c | $(BUILD_DIR) $(MARK)
	$Q$(call ECHO,CC,$@)
	$Q$(CC) -I$(INC_DIR) $(CFLAGS) $< -c -o $@

$(BUILD_DIR):
	$Q$(call ECHO_NOPROG,MKDIR,$(BUILD_DIR))
	$Qmkdir -p $(BUILD_DIR) $(BUILD_UTIL) $(BUILD_LEXICAL) $(BUILD_RESOLVER) $(BUILD_TEST) $(BUILD_IMG_DIR) $(BUILD_DECODER)

FORCE:

$(MARK): FORCE | $(BUILD_DIR)
	$Qecho 1 > $(MARK)

.PHONY: clean all ceccomp test
clean:
	$Q$(call ECHO_NOPROG,RM,$(BUILD_DIR))
	$Qrm -rf $(BUILD_DIR)
	$Q$(call ECHO_NOPROG,RM,$(CONFIG_HEADER))
	$Qrm $(CONFIG_HEADER)

endif
