# Open JTalk Elixir – Makefile
#
# Why this layout:
# - Keep extracted vendor trees under _build so switching host/target is clean.
#   Autotools writes host-specific junk in source trees; confining them to _build
#   lets `mix clean`/`rm -rf _build` give a true fresh start.
# - Delegate extraction + triplet guarding to the build script for simplicity.
#
ifeq ($(MIX_COMPILE_PATH),)
  $(error MIX_COMPILE_PATH should be set by elixir_make)
endif

PRIV_DIR   := $(abspath $(MIX_COMPILE_PATH)/../priv)
OBJ_DIR    := $(abspath $(MIX_COMPILE_PATH)/../obj)
OBJ_VENDOR := $(abspath $(OBJ_DIR)/vendor)
SCRIPT_DIR := $(abspath $(CURDIR)/scripts)

# Pinned source archives committed in the repo (reproducible builds)
MECAB_TGZ := vendor/mecab-0.996.tar.gz
HTS_TGZ   := vendor/hts_engine_API-1.10.tar.gz
OJT_TGZ   := vendor/open_jtalk-1.11.tar.gz

# Fixed extracted source locations (we assume the top-level dir names)
MECAB_SRC := $(OBJ_VENDOR)/mecab/mecab-0.996
HTS_SRC   := $(OBJ_VENDOR)/hts_engine/hts_engine_API-1.10
OJT_SRC   := $(OBJ_VENDOR)/open_jtalk/open_jtalk-1.11

# Assets (dictionary + one voice for out-of-the-box usage)
DIC_TGZ := vendor/open_jtalk_dic_utf_8-1.11.tar.gz
MEI_ZIP := vendor/MMDAgent_Example-1.8.zip

# Toolchain (honor CROSSCOMPILE if provided)
CROSSCOMPILE ?=
CC     ?= $(if $(CROSSCOMPILE),$(CROSSCOMPILE)-gcc,gcc)
CXX    ?= $(if $(CROSSCOMPILE),$(CROSSCOMPILE)-g++,g++)
AR     ?= $(if $(CROSSCOMPILE),$(CROSSCOMPILE)-ar,ar)
RANLIB ?= $(if $(CROSSCOMPILE),$(CROSSCOMPILE)-ranlib,ranlib)
STRIP  ?= $(if $(CROSSCOMPILE),$(CROSSCOMPILE)-strip,strip)

# Convenience: derive CROSSCOMPILE from CC when users pass e.g. aarch64-linux-gnu-gcc
CC_BASENAME := $(notdir $(CC))
CC_PREFIX   := $(patsubst %-gcc,%,$(CC_BASENAME))
ifeq ($(strip $(CROSSCOMPILE)),)
  ifneq ($(CC_PREFIX),$(CC_BASENAME))
    CROSSCOMPILE := $(CC_PREFIX)
  endif
endif

# Host triplet (normalize *-nerves-* -> *-unknown-* for older config.sub)
HOST_RAW  := $(shell $(CC) -dumpmachine 2>/dev/null)
HOST_NORM := $(shell printf '%s' '$(HOST_RAW)' | sed -E 's/-nerves-/-unknown-/')

# Per-triplet output roots
OJT_DEPS_PREFIX := $(abspath $(OBJ_DIR)/deps-$(HOST_NORM))
OJT_PREFIX      := $(abspath $(OBJ_DIR)/open_jtalk-$(HOST_NORM))

# Include/lib flags; EXTRA_* are passthrough so users can customize.
DEFAULT_CPPFLAGS := -I$(OJT_DEPS_PREFIX)/include
EXTRA_CPPFLAGS ?= $(DEFAULT_CPPFLAGS)

UNAME_S := $(shell uname -s)

# Nerves default: static on target, dynamic on host/CI
OPENJTALK_FULL_STATIC ?= $(if $(strip $(MIX_TARGET)),1,0)

# Darwin can’t fully static-link these deps—fail early if asked to.
ifneq (,$(findstring darwin,$(HOST_NORM)))
  ifeq ($(OPENJTALK_FULL_STATIC),1)
    $(error OPENJTALK_FULL_STATIC=1 is not supported for darwin targets)
  endif
endif

# rpath so the CLI finds our priv/lib at runtime without LD_LIBRARY_PATH
ifeq ($(UNAME_S),Darwin)
  RPATH_FLAGS = -Wl,-rpath,@loader_path/../lib
else
  RPATH_FLAGS = -Wl,-rpath,'$$ORIGIN/../lib' -Wl,-z,origin
endif

# Linkage mode (static vs dynamic)
ifeq ($(OPENJTALK_FULL_STATIC),1)
  DEFAULT_LDFLAGS := -L$(OJT_DEPS_PREFIX)/lib -static -static-libgcc -static-libstdc++
else
  DEFAULT_LDFLAGS := -L$(OJT_DEPS_PREFIX)/lib $(RPATH_FLAGS)
endif
EXTRA_LDFLAGS ?= $(DEFAULT_LDFLAGS)

# Bundle dictionary/voice into priv by default so tests & examples “just work”.
OPENJTALK_BUNDLE_ASSETS ?= 1

# Use the repo-pinned GNU config scripts by default; allow override via env.
CONFIG_SUB ?= $(CURDIR)/vendor/config/config.sub

# ------------------------------------------------------------------------------
# Minimal vendor readiness check (used as an order-only prerequisite)
# ------------------------------------------------------------------------------
VENDOR_DIR := $(CURDIR)/vendor
VENDOR_PAYLOADS := \
  $(VENDOR_DIR)/config/config.sub \
  $(VENDOR_DIR)/config/config.guess \
  $(VENDOR_DIR)/mecab-0.996.tar.gz \
  $(VENDOR_DIR)/hts_engine_API-1.10.tar.gz \
  $(VENDOR_DIR)/open_jtalk-1.11.tar.gz \
  $(VENDOR_DIR)/open_jtalk_dic_utf_8-1.11.tar.gz \
  $(VENDOR_DIR)/MMDAgent_Example-1.8.zip

.PHONY: vendor_ready
vendor_ready:
	@missing=; \
	for f in $(VENDOR_PAYLOADS); do \
	  if [ ! -f $$f ]; then echo "missing: $$f"; missing=1; fi; \
	done; \
	if [ -n "$$missing" ]; then \
	  echo "Preparing vendor payloads..."; \
	  /usr/bin/env bash "$(SCRIPT_DIR)/prepare_vendor.sh"; \
	else \
	  echo "vendor looks ready."; \
	fi

# ------------------------------------------------------------------------------
# Targets
# ------------------------------------------------------------------------------
.PHONY: all dictionary voice clean distclean show-config-sub

ifeq ($(OPENJTALK_BUNDLE_ASSETS),1)
all: $(PRIV_DIR)/bin/open_jtalk $(PRIV_DIR)/dictionary/sys.dic $(PRIV_DIR)/voices/mei_normal.htsvoice
else
all: $(PRIV_DIR)/bin/open_jtalk
endif

dictionary: $(PRIV_DIR)/dictionary/sys.dic
voice:      $(PRIV_DIR)/voices/mei_normal.htsvoice

show-config-sub:
	@printf "CONFIG_SUB = %s\n" "$(CONFIG_SUB)"

# Build everything. The script handles:
# - triplet guard (purges obj on host change)
# - vendor extraction
# - dependency + open_jtalk build
$(PRIV_DIR)/bin/open_jtalk: | $(OBJ_DIR) $(PRIV_DIR)/bin $(PRIV_DIR)/lib vendor_ready
	+@echo "Building Open JTalk"; \
	  OBJ_DIR="$(OBJ_DIR)" OBJ_VENDOR="$(OBJ_VENDOR)" \
	  MECAB_TGZ="$(MECAB_TGZ)" HTS_TGZ="$(HTS_TGZ)" OJT_TGZ="$(OJT_TGZ)" \
	  MECAB_SRC="$(MECAB_SRC)" HTS_SRC="$(HTS_SRC)" OJT_SRC="$(OJT_SRC)" \
	  OJT_DEPS_PREFIX="$(OJT_DEPS_PREFIX)" OJT_PREFIX="$(OJT_PREFIX)" HOST="$(HOST_NORM)" \
	  CC="$(CC)" CXX="$(CXX)" AR="$(AR)" RANLIB="$(RANLIB)" STRIP_BIN="$(STRIP)" \
	  CONFIG_SUB="$(CONFIG_SUB)" EXTRA_CPPFLAGS="$(EXTRA_CPPFLAGS)" EXTRA_LDFLAGS="$(EXTRA_LDFLAGS)" \
	  DEST_BIN="$(PRIV_DIR)/bin/open_jtalk" \
	  /usr/bin/env bash "$(SCRIPT_DIR)/build_openjtalk.sh"

# Assets: install pinned dictionary & one voice
$(PRIV_DIR)/dictionary/sys.dic: | vendor_ready $(PRIV_DIR)/dictionary
	+@DIC_TGZ="$(DIC_TGZ)" DEST_DIR="$(PRIV_DIR)/dictionary" \
	  /usr/bin/env bash "$(SCRIPT_DIR)/install_dictionary.sh"

$(PRIV_DIR)/voices/mei_normal.htsvoice: | vendor_ready $(PRIV_DIR)/voices
	+@VOICE_ZIP="$(MEI_ZIP)" DEST_VOICE="$(PRIV_DIR)/voices/mei_normal.htsvoice" \
	  /usr/bin/env bash "$(SCRIPT_DIR)/install_voice.sh"

# Dirs
$(OBJ_DIR) \
$(OJT_DEPS_PREFIX) \
$(PRIV_DIR) \
$(PRIV_DIR)/bin \
$(PRIV_DIR)/lib \
$(PRIV_DIR)/dictionary \
$(PRIV_DIR)/voices:
	mkdir -p "$@"

# Clean only current target’s build artefacts
clean:
	rm -rf "$(PRIV_DIR)/bin/open_jtalk" "$(PRIV_DIR)/lib" "$(OBJ_DIR)"

# Only remove assets (archives remain)
distclean: clean
	rm -rf "$(PRIV_DIR)/dictionary" "$(PRIV_DIR)/voices"

# Friendly hint if building locally without a cross toolchain.
ifeq ($(strip $(CROSSCOMPILE)),)
  $(warning No cross-compiler detected. Building native code in test mode.)
endif

