# Makefile for building and deploying static binaries for multiple architectures

# Variables
OUTPUT_DIR := dist

# FEATURES variable for cargo features:
#   - unset or "auto": auto-enable libkrun for supported platforms (default)
#   - ""            : disable all features
#   - "libkrun"     : explicitly enable libkrun
#   - "..."         : custom features (comma-separated)
FEATURES ?= auto
export FEATURES

# Detect Makefile location and adjust paths
MAKEFILE_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
ifeq ($(shell basename $(CURDIR)),src)
	# Running from src/ directory
	SRC_DIR := .
	PROJECT_ROOT := ..
else
	# Running from project root
	SRC_DIR := src
	PROJECT_ROOT := .
endif

# Detect host architecture and OS
HOST_ARCH := $(shell uname -m | sed -e 's/amd64/x86_64/' -e 's/arm64/aarch64/')
UNAME_S := $(shell uname -s)

# Default target is
# - development build (fast)
# - static build (necessary for running applets inside various env)
# - libkrun auto-enabled for supported platforms (see make.sh)
# Use FEATURES=xxx to override, e.g., FEATURES="" to disable libkrun

# Lua is only needed on Linux for RPM scriptlets
ifeq ($(UNAME_S),Linux)
static: $(PROJECT_ROOT)/target/lua-musl-$(HOST_ARCH)/liblua.a
	@$(PROJECT_ROOT)/bin/make.sh static-debug $(HOST_ARCH)
else
static:
	@$(PROJECT_ROOT)/bin/make.sh static-debug $(HOST_ARCH)
endif

# Static build with libkrun integrated (Cargo --features libkrun) and
# sandbox-kernel unpacked into the self env so the libkrun backend can run
# without extra manual steps on the host.
# Note: libkrun is auto-enabled for supported platforms, this target is
# kept for explicit usage documentation and appending extra features.
ifeq ($(UNAME_S),Linux)
static-libkrun: $(PROJECT_ROOT)/target/lua-musl-$(HOST_ARCH)/liblua.a
	@$(PROJECT_ROOT)/bin/make.sh static-libkrun $(HOST_ARCH)
else
static-libkrun:
	@$(PROJECT_ROOT)/bin/make.sh static-libkrun $(HOST_ARCH)
endif

# Release build target
# Note: libkrun auto-enabled for supported platforms (see make.sh)
ifeq ($(UNAME_S),Linux)
release: $(PROJECT_ROOT)/target/lua-musl-$(HOST_ARCH)/liblua.a
	@$(PROJECT_ROOT)/bin/make.sh static-release $(HOST_ARCH)
else
release:
	@$(PROJECT_ROOT)/bin/make.sh static-release $(HOST_ARCH)
endif

# Development build with dynamic linking, only useful for run in local host rootfs 
build:
	@$(PROJECT_ROOT)/bin/make.sh build

# Install development dependencies (current arch only)
dev-depends:
	@$(PROJECT_ROOT)/bin/make.sh dev-depends

# Install release dependencies (all arch cross-compilers)
crossdev-depends:
	@$(PROJECT_ROOT)/bin/make.sh crossdev-depends

# Clone required repositories (rpm-rs, resolvo, elf-loader)
clone-repos:
	@$(PROJECT_ROOT)/bin/make.sh clone-repos

# Build release binaries for all architectures (sequentially to avoid Cargo lock conflicts)
release-all:
	mkdir -p "$(OUTPUT_DIR)"
	$(MAKE) release-x86_64
	$(MAKE) release-aarch64
	$(MAKE) release-riscv64
	$(MAKE) release-loongarch64
	# Cross build macOS (asset names: epkg-macos-<arch>)
	$(MAKE) cross-macos-release ARCH=x86_64
	$(MAKE) cross-macos-release ARCH=aarch64
	# Cross build Windows (asset names: epkg-windows-<arch>.exe)
	# Note: only x86_64 supported; aarch64 requires mingw-w64 libraries not available in Debian
	$(MAKE) cross-windows-release

# Build release binary for a specific architecture
# Note: libkrun auto-enabled for supported platforms (see make.sh)
define build_release
release-$(1): $(PROJECT_ROOT)/target/lua-musl-$(1)/liblua.a
	@$(PROJECT_ROOT)/bin/make.sh static-release $(1)
endef

$(eval $(call build_release,x86_64))
$(eval $(call build_release,aarch64))
$(eval $(call build_release,riscv64))
$(eval $(call build_release,loongarch64))


# Build Lua library for a specific architecture
define build_lua_lib
$(PROJECT_ROOT)/target/lua-musl-$(1)/liblua.a:
	@$(PROJECT_ROOT)/bin/make.sh build_lua_lib $(1)
endef

# Define build targets for each architecture
$(eval $(call build_lua_lib,x86_64))
$(eval $(call build_lua_lib,aarch64))
$(eval $(call build_lua_lib,riscv64))
$(eval $(call build_lua_lib,loongarch64))

# Cross-compilation to macOS (default aarch64, debug mode)
cross-macos:
	@$(PROJECT_ROOT)/bin/make.sh cross-macos $(ARCH) debug

# Cross-compilation to macOS (release mode)
cross-macos-release:
	@$(PROJECT_ROOT)/bin/make.sh cross-macos $(ARCH) release

# Cross-compilation to Windows (x86_64 only; aarch64 not supported, debug mode)
# Note: Windows cross-compilation requires two build steps:
#   1. `make` - builds the Linux binary for the guest init process
#   2. `make cross-windows` - cross-compiles the Windows binary with embedded init
#
# Hardlink deployment chain (atomic updates across all envs):
#   build:  target/x86_64-unknown-linux-musl/debug/epkg
#              |
#              v (make.sh deploy: install_hardlink)
#   self:   ~/.epkg/envs/self/usr/bin/epkg-linux-x86_64
#              |
#              v (make.sh: update_all_env_hardlinks)
#   envs:   ~/.epkg/envs/<env>/usr/bin/epkg  ----> (hardlink, same inode as self's epkg-linux)
#           ~/.epkg/envs/<env>/usr/bin/init  ----> (hardlink, same inode as self's epkg-linux)
#           ~/.epkg/envs/<env>/usr/bin/vm-daemon -> epkg (symlink, not hardlink)
#
# Update scenarios (all hardlinks share same inode, update atomically):
#   - `make`: make.sh update_all_env_hardlinks() after build
#   - `epkg self install --force`: init.rs update_all_env_hardlinks()
#
# Windows cross-compile output:
#   target/x86_64-pc-windows-gnu/debug/epkg.exe -> dist/epkg-windows-x86_64.exe
#   (also deploys Linux epkg-linux-x86_64 to dist/ if available)
#
# The init applet in the Windows binary is the Linux guest init process,
# embedded via libkrun's embedded_init feature to run inside the Windows VM.
cross-windows:
	@$(PROJECT_ROOT)/bin/make.sh cross-windows x86_64 debug

# Cross-compilation to Windows (x86_64 only, release mode)
cross-windows-release:
	@$(PROJECT_ROOT)/bin/make.sh cross-windows x86_64 release

# Run tests (module-level unit tests)
test:
	@$(PROJECT_ROOT)/bin/make.sh test

# Clean build artifacts only
clean:
	@$(PROJECT_ROOT)/bin/make.sh clean

# Clean build artifacts and distribution files
clean-all:
	@$(PROJECT_ROOT)/bin/make.sh clean_all

.PHONY: dev-depends crossdev-depends clone-repos build static release release-all release-x86_64 release-aarch64 release-riscv64 release-loongarch64 cross-macos cross-macos-release cross-windows cross-windows-release test clean clean-all