# Copyright (C) Microsoft Corporation. All rights reserved.
#
# Builds common.o plus one self-contained binary per sample. Sources live in src/; every build
# artifact (object files, sample binaries, and the runtime soname symlink) is emitted into bin/.
# Each sample includes the public header <azihsm_api_resilient.h> and links the resilience
# shared library (libazihsm_api_resilient.so) from the api workspace target directory.

CC      ?= cc
CFLAGS  ?= -std=c11 -Wall -Wextra -O2
SRCDIR   = src
BINDIR   = bin

# File names of the two relocatable inputs we need to find.
LIB_NAME := libazihsm_api_resilient.so
HDR_NAME := azihsm_api_resilient.h

# ---------------------------------------------------------------------------
# Locating the shared library and the public header.
#
# Two documented, user-overridable knobs (both honour the command line, e.g.
# `make AZIHSM_LIB_DIR=/path AZIHSM_INCLUDE_DIR=/path`):
#
#   AZIHSM_LIB_DIR      directory containing libazihsm_api_resilient.so
#   AZIHSM_INCLUDE_DIR  directory containing azihsm_api_resilient.h
#
# Optional precise override:
#   AZIHSM_LIB          full path to a specific .so (its directory becomes the
#                       link-search path); use when the file is not named, or
#                       not located, where the dir knobs would look.
#
# When the knobs are NOT set, we auto-discover by checking a small, ordered set
# of candidate directories and using the first that actually contains the file.
# This makes the "everything copied into one folder" relocated layout work with
# zero arguments, while still falling back to the in-repo dev paths last so the
# in-tree workflow is byte-for-byte unchanged. No recursive searching is done.
#
# Library search order:  ./  ./lib  ./bin  ../../target/debug  (in-repo default)
# Header  search order:   ./  ./include  ../../resilience_lib/include (in-repo)
# ---------------------------------------------------------------------------
_LIB_CANDIDATES := . ./lib ./bin ../../target/debug
_INC_CANDIDATES := . ./include ../../resilience_lib/include

# First candidate directory that actually contains the file (empty if none).
_LIB_FOUND := $(firstword $(patsubst %/$(LIB_NAME),%,$(wildcard $(addsuffix /$(LIB_NAME),$(_LIB_CANDIDATES)))))
_INC_FOUND := $(firstword $(patsubst %/$(HDR_NAME),%,$(wildcard $(addsuffix /$(HDR_NAME),$(_INC_CANDIDATES)))))

# Documented knobs: default to discovery, falling back to the in-repo dev paths.
AZIHSM_LIB_DIR     ?= $(if $(_LIB_FOUND),$(_LIB_FOUND),../../target/debug)
AZIHSM_INCLUDE_DIR ?= $(if $(_INC_FOUND),$(_INC_FOUND),../../resilience_lib/include)

# Legacy alias: honour INCDIR if a user still passes it on the command line.
ifdef INCDIR
  AZIHSM_INCLUDE_DIR := $(INCDIR)
endif

# Optional precise .so override. When unset, derive it from AZIHSM_LIB_DIR; when
# set, its directory becomes the link-search path so -L/-rpath stay consistent.
AZIHSM_LIB ?=
ifeq ($(strip $(AZIHSM_LIB)),)
  AZIHSM_LIB     := $(AZIHSM_LIB_DIR)/$(LIB_NAME)
else
  AZIHSM_LIB_DIR := $(patsubst %/,%,$(dir $(AZIHSM_LIB)))
endif

# The shared object carries a versioned soname (DT_SONAME = libazihsm_api_resilient.so.1), so a
# soname-named file must exist at run time. A system install (scripts/install.sh) provides it;
# a raw `cargo build` emits only the plain `.so`. So for the in-tree dev workflow we create the
# soname symlink next to the binaries (in bin/) and add `$ORIGIN` to the rpath, keeping
# everything self-contained (no install step, no LD_LIBRARY_PATH).
SONAME       = libazihsm_api_resilient.so.1
PLAIN_SO     = $(AZIHSM_LIB)

CPPFLAGS = -I$(AZIHSM_INCLUDE_DIR)
# Link against the shared object AND embed rpaths so no LD_LIBRARY_PATH is needed at run time:
# `$ORIGIN` (the binary's own directory, i.e. bin/, where the soname symlink lives) and the lib
# dir (for a system/installed layout that already provides the soname file).
LDFLAGS  = -L$(AZIHSM_LIB_DIR) -Wl,-rpath,'$$ORIGIN' -Wl,-rpath,$(AZIHSM_LIB_DIR)
LDLIBS   = -lazihsm_api_resilient

SAMPLES  = aes_cbc aes_gcm aes_xts ecdsa_sign_verify ecdh_key_agreement \
           rsa_public_key attestation device_info tracing

BINARIES = $(addprefix $(BINDIR)/,$(addsuffix .app,$(SAMPLES)))

all: $(BINDIR)/$(SONAME) $(BINARIES)

# Create the output directory on demand (order-only prerequisite).
$(BINDIR):
	mkdir -p $(BINDIR)

# Soname symlink in bin/ -> the built plain .so. Use a RELATIVE symlink (ln -r)
# and recreate it on every build (FORCE) so it never embeds a build-machine
# absolute path and never goes stale when bin/ is copied to another machine.
# The .so is a real prerequisite, yielding a clear error if it cannot be found.
.PHONY: FORCE
FORCE:

$(BINDIR)/$(SONAME): $(PLAIN_SO) FORCE | $(BINDIR)
	rm -f $@
	ln -sr $(PLAIN_SO) $@

# Each sample is its own binary (bin/<name>.app), linked with common.o, and needs the soname
# symlink at run time. This is an explicit pattern rule so the stem `%` is the bare sample name
# (mapping to bin/<name>.o); a `.app`-suffixed static-pattern would make the stem `<name>.app`
# and wrongly require `<name>.app.o`.
$(BINDIR)/%.app: $(BINDIR)/%.o $(BINDIR)/common.o | $(BINDIR)/$(SONAME)
	$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS) $(LDLIBS)

# Compile each source from src/ into an object in bin/.
$(BINDIR)/%.o: $(SRCDIR)/%.c $(SRCDIR)/common.h | $(BINDIR)
	$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@

clean:
	rm -rf $(BINDIR)
	rm -f *.trace.log

.PHONY: all clean
