# Builds the cix_p1_nif.so NIF against the CIX NOE runtime (libnoe/libaipudrv).
#
# Under a Nerves firmware build, elixir_make inherits the cross toolchain (CC,
# CFLAGS, LDFLAGS, --sysroot) and NERVES_SDK_SYSROOT from the Nerves env. The
# NOE headers/libs live in a non-standard prefix, so we add them explicitly.
#
# On a plain host with no NOE SDK the native build is skipped so that
# `mix compile` / `mix test` still work for the pure-Elixir modules.

ifndef MIX_APP_PATH
	MIX_APP_PATH = $(shell pwd)
endif

PRIV_DIR = $(MIX_APP_PATH)/priv
NIF_SO   = $(PRIV_DIR)/cix_p1_nif.so
C_SRC    = $(shell pwd)/c_src

# Erlang NIF headers (elixir_make usually sets ERTS_INCLUDE_DIR for us).
ERTS_INCLUDE_DIR ?= $(shell erl -noshell -eval "io:format(\"~ts/erts-~ts/include/\", [code:root_dir(), erlang:system_info(version)])" -s init stop)

# Root that contains include/npu and lib. On-device this is /usr/share/cix;
# in a Nerves build it lives inside the staging sysroot. Override with
# CIX_SDK_ROOT if your layout differs.
ifdef NERVES_SDK_SYSROOT
	CIX_SDK_ROOT ?= $(NERVES_SDK_SYSROOT)/usr/share/cix
else
	CIX_SDK_ROOT ?= /usr/share/cix
endif
# CIX_INCLUDE / CIX_LIB may each be a space-separated list of dirs. They default
# to the single sysroot layout above, but `crossbuild` overrides them to point at
# the two sibling blob dirs (noe + npu headers/libs live in separate packages).
CIX_INCLUDE ?= $(CIX_SDK_ROOT)/include/npu
CIX_LIB     ?= $(CIX_SDK_ROOT)/lib

CFLAGS  ?= -O2
CFLAGS  += -std=c11 -fPIC -Wall -Wextra -I"$(ERTS_INCLUDE_DIR)" $(addprefix -I,$(CIX_INCLUDE))
LDFLAGS += -shared $(addprefix -L,$(CIX_LIB)) -Wl,-rpath,/usr/share/cix/lib
LDLIBS  += -lnoe -laipudrv

CC ?= cc

# Nerves system checkout used by `crossbuild` for off-target compile+link (CI).
# It is git-cloned into NERVES_SYSTEM_DIR (no relative-path assumptions); point
# NERVES_SYSTEM_DIR at an existing checkout to skip the clone.
NERVES_SYSTEM_REPO ?= https://github.com/monoflow-ayvu/nerves_system_orangepi6.git
NERVES_SYSTEM_REF  ?= main
NERVES_SYSTEM_DIR  ?= $(CURDIR)/.nerves-system
SYSTEM_BLOBS        = $(NERVES_SYSTEM_DIR)/blobs

# aarch64 cross compiler used by `crossbuild` (devenv/CI provide it on PATH).
CROSS_CC ?= aarch64-unknown-linux-gnu-gcc

all: build

# Real build only when the target sysroot has the NOE SDK (Nerves firmware
# build). On a plain host it is a no-op so `mix compile` / `mix test` still work;
# use `make crossbuild` for a full off-target compile+link check.
build:
	@if [ -f "$(firstword $(CIX_INCLUDE))/cix_noe_standard_api.h" ]; then \
		$(MAKE) --no-print-directory "$(NIF_SO)"; \
	else \
		echo "cix_p1_tpu: NOE SDK not found in sysroot; skipping native NIF build."; \
		echo "           (host build — cross-compile with 'make crossbuild')."; \
		mkdir -p "$(PRIV_DIR)"; \
	fi

# Clone the Nerves system (with its LFS-tracked NOE blobs) if not already present.
fetch-system:
	@if [ ! -e "$(SYSTEM_BLOBS)/cix-noe-umd/usr/share/cix/include/npu/cix_noe_standard_api.h" ]; then \
		if [ ! -d "$(NERVES_SYSTEM_DIR)/.git" ]; then \
			echo "cix_p1_tpu: cloning $(NERVES_SYSTEM_REPO) ($(NERVES_SYSTEM_REF)) into $(NERVES_SYSTEM_DIR)"; \
			git clone --depth 1 --branch "$(NERVES_SYSTEM_REF)" "$(NERVES_SYSTEM_REPO)" "$(NERVES_SYSTEM_DIR)"; \
		fi; \
		cd "$(NERVES_SYSTEM_DIR)" && git lfs pull; \
	fi

$(NIF_SO): $(C_SRC)/cix_p1_nif.c
	mkdir -p "$(PRIV_DIR)"
	$(CC) $(CFLAGS) "$(C_SRC)/cix_p1_nif.c" $(LDFLAGS) $(LDLIBS) -o "$(NIF_SO)"

# Full off-target compile+link check for CI: cross-compile the NIF for aarch64
# and link it against the system repo's real libnoe/libaipudrv blobs. Produces a
# genuine aarch64 .so (proves it compiles and every symbol resolves). Requires
# CROSS_CC (an aarch64 gcc); clones the Nerves system for the blobs.
crossbuild: fetch-system
	$(MAKE) "$(NIF_SO)" \
		CC="$(CROSS_CC)" \
		CIX_INCLUDE="$(SYSTEM_BLOBS)/cix-noe-umd/usr/share/cix/include/npu $(SYSTEM_BLOBS)/cix-npu-umd/usr/share/cix/include/npu" \
		CIX_LIB="$(SYSTEM_BLOBS)/cix-noe-umd/usr/share/cix/lib $(SYSTEM_BLOBS)/cix-npu-umd/usr/share/cix/lib"
	@file "$(NIF_SO)"

clean:
	rm -f "$(NIF_SO)"

.PHONY: all build fetch-system crossbuild clean
