# Copyright (C) 2026 Shanghai Symthosm(Xian Dao Zhi Jue) Intelligent Technology Co., Ltd.
#                   上海先道智觉科技有限责任公司
# Author: Lu Haoran <luhaoran1981@icloud.com>
#         芦浩然
# SPDX-License-Identifier: GPL-2.0-or-later

VERSION       = 0.2.1
SOVER_MAJOR   = 0

CC            = gcc
AR            = ar

# Compiler/linker flags. Distro build systems (Fedora %set_build_flags, Debian
# dpkg-buildflags) inject hardening flags (-fPIE/-pie, fortify, relro) via the
# environment; use ?= so those take precedence. Our own mandatory flags live in
# CPPFLAGS (appended), so they survive any external CFLAGS override.
CFLAGS   ?= -Wall -Wextra -std=c11 -O2 -g
LDFLAGS  ?=
CPPFLAGS ?=

CPPFLAGS += -DTASKHEALTH_VERSION=\"$(VERSION)\" \
            -I $(SRCDIR) -I $(DAEMONDIR) -I $(INCDIR)
PTHREAD   = -pthread
# Library objects must be position-independent for the shared library.
PIC_FLAGS = -fPIC

COMPILE = $(CC) $(CPPFLAGS) $(CFLAGS) $(PTHREAD)
LINK    = $(CC) $(CFLAGS) $(PTHREAD)

prefix         = /usr/local
bindir         = $(prefix)/bin
sbindir        = $(prefix)/sbin
libdir         = $(prefix)/lib
includedir     = $(prefix)/include
pkgconfigdir   = $(libdir)/pkgconfig
mandir         = $(prefix)/share/man
systemdunitdir = $(prefix)/lib/systemd/system

SRCDIR        = src
INCDIR        = include
TESTDIR       = test
DEMODIR       = demo
DAEMONDIR     = daemon

LIBST         = libtaskhealth.a
LIBSO         = libtaskhealth.so
LIBSONAME     = $(LIBSO).$(SOVER_MAJOR)
LIBSOREAL     = $(LIBSO).$(VERSION)

LIB_OBJS      = $(SRCDIR)/taskhealth.o $(SRCDIR)/taskhealth_mutex.o
PUBLIC_HEADERS = $(SRCDIR)/taskhealth.h $(SRCDIR)/taskhealth_mutex.h
PROTOCOL_HEADER = $(INCDIR)/taskhealth/protocol.h
HEADERS       = $(PUBLIC_HEADERS) $(PROTOCOL_HEADER)
DAEMON_SRCS   = $(DAEMONDIR)/main.c $(DAEMONDIR)/server.c $(DAEMONDIR)/registry.c \
                $(DAEMONDIR)/watchdog.c $(DAEMONDIR)/probe.c $(DAEMONDIR)/alert.c
DAEMON_OBJS   = $(DAEMON_SRCS:.c=.o)
TARNAME       = taskhealth-$(VERSION).tar.gz

# default: static + shared library + daemon
all: $(LIBST) $(LIBSONAME) taskhealthd

$(LIBST): $(LIB_OBJS)
	$(AR) rcs $@ $^

$(LIBSONAME): $(LIB_OBJS)
	$(CC) -shared -Wl,-soname,$(LIBSONAME) -o $(LIBSOREAL) $^ $(LDFLAGS) $(PTHREAD)
	ln -sf $(LIBSOREAL) $(LIBSONAME)
	ln -sf $(LIBSONAME) $(LIBSO)

taskhealthd: $(DAEMON_OBJS)
	$(LINK) -o $@ $^ $(LDFLAGS)

$(SRCDIR)/taskhealth.o: $(SRCDIR)/taskhealth.c $(SRCDIR)/taskhealth.h $(PROTOCOL_HEADER)
	$(COMPILE) $(PIC_FLAGS) -c -o $@ $<

$(SRCDIR)/taskhealth_mutex.o: $(SRCDIR)/taskhealth_mutex.c $(SRCDIR)/taskhealth_mutex.h $(SRCDIR)/taskhealth_internal.h
	$(COMPILE) $(PIC_FLAGS) -c -o $@ $<

$(DAEMONDIR)/%.o: $(DAEMONDIR)/%.c
	$(COMPILE) -c -o $@ $<

# demo program
demo: $(DEMODIR)/demo.c $(LIBST) $(HEADERS)
	$(LINK) -o $(DEMODIR)/$@ $< -L. -ltaskhealth $(LDFLAGS)

# unit test (client library API only; needs a running taskhealthd
# on the default socket for the register round-trip tests)
test: $(TESTDIR)/test.c $(LIBST) $(HEADERS)
	$(LINK) -o $(TESTDIR)/$@ $< -L. -ltaskhealth $(LDFLAGS)

check: test
	LD_LIBRARY_PATH=.:$$LD_LIBRARY_PATH $(TESTDIR)/test

# functional daemon tests: connect to a running taskhealthd over the raw
# protocol (see test/run_daemon_tests.sh for the start/assert/stop harness)
test-daemon: $(TESTDIR)/test_daemon.c $(PROTOCOL_HEADER)
	$(LINK) -o $(TESTDIR)/test_daemon $< $(LDFLAGS)

check-daemon: all-full test-daemon
	./$(TESTDIR)/run_daemon_tests.sh

# integration tests: drive the real client library against a running
# taskhealthd (see test/run_integration_tests.sh for the harness)
test-integration: $(TESTDIR)/test_integration.c $(LIBST) $(HEADERS)
	$(LINK) -o $(TESTDIR)/test_integration $< -L. -ltaskhealth $(LDFLAGS)

check-integration: all-full test-integration
	./$(TESTDIR)/run_integration_tests.sh

# code coverage
COV_DIR   = coverage
COV_CFLAGS = -Wall -Wextra -std=c11 -pthread -O0 -g -fPIC \
             -DTASKHEALTH_VERSION=\"$(VERSION)\" -I $(SRCDIR) --coverage

cov: clean
	$(CC) $(COV_CFLAGS) -c -o $(SRCDIR)/taskhealth.o $(SRCDIR)/taskhealth.c
	$(CC) $(COV_CFLAGS) -c -o $(SRCDIR)/taskhealth_mutex.o $(SRCDIR)/taskhealth_mutex.c
	$(AR) rcs $(LIBST) $(LIB_OBJS)
	$(CC) $(COV_CFLAGS) --coverage -o $(TESTDIR)/test $(TESTDIR)/test.c \
		-L. -ltaskhealth $(LDFLAGS)
	LD_LIBRARY_PATH=.:$$LD_LIBRARY_PATH $(TESTDIR)/test 2>/dev/null
	gcov -r $(SRCDIR)/taskhealth.c $(SRCDIR)/taskhealth_mutex.c
	@echo "  => taskhealth.c.gcov  taskhealth_mutex.c.gcov"

all-full: $(LIBST) $(LIBSONAME) taskhealthd demo taskhealth.pc

clean:
	rm -f $(LIB_OBJS) $(DAEMON_OBJS) $(LIBST) $(LIBSOREAL) $(LIBSONAME) $(LIBSO) \
		taskhealthd \
		$(DEMODIR)/demo $(TESTDIR)/test $(TESTDIR)/test_daemon \
		$(TESTDIR)/test_integration \
		*.gcno *.gcda *.gcov $(SRCDIR)/*.gcno $(SRCDIR)/*.gcda \
		$(TESTDIR)/*.gcno $(TESTDIR)/*.gcda \
		$(DAEMONDIR)/*.gcno $(DAEMONDIR)/*.gcda

install: $(LIBST) $(LIBSONAME) taskhealthd demo
	install -d $(DESTDIR)$(libdir) $(DESTDIR)$(includedir) \
		$(DESTDIR)$(includedir)/taskhealth $(DESTDIR)$(bindir) \
		$(DESTDIR)$(pkgconfigdir) $(DESTDIR)$(sbindir) \
		$(DESTDIR)$(mandir)/man1 $(DESTDIR)$(mandir)/man8 \
		$(DESTDIR)$(mandir)/man7 $(DESTDIR)$(systemdunitdir)
	install -m 644 $(LIBST) $(DESTDIR)$(libdir)
	install -m 755 $(LIBSOREAL) $(DESTDIR)$(libdir)
	ln -sf $(LIBSOREAL) $(DESTDIR)$(libdir)/$(LIBSONAME)
	ln -sf $(LIBSONAME) $(DESTDIR)$(libdir)/$(LIBSO)
	install -m 644 $(PUBLIC_HEADERS) $(DESTDIR)$(includedir)
	install -m 644 $(PROTOCOL_HEADER) $(DESTDIR)$(includedir)/taskhealth
	install -m 644 taskhealth.pc $(DESTDIR)$(pkgconfigdir)
	install -m 755 taskhealthd $(DESTDIR)$(sbindir)
	install -m 755 $(DEMODIR)/demo $(DESTDIR)$(bindir)/taskhealth-demo
	install -m 644 man/taskhealthd.8 $(DESTDIR)$(mandir)/man8/taskhealthd.8
	install -m 644 man/taskhealth-demo.1 $(DESTDIR)$(mandir)/man1/taskhealth-demo.1
	install -m 644 man/taskhealth.7 $(DESTDIR)$(mandir)/man7/taskhealth.7
	install -m 644 contrib/systemd/taskhealthd.service \
		$(DESTDIR)$(systemdunitdir)/taskhealthd.service

# pkg-config file (generated at build time)
taskhealth.pc: taskhealth.pc.in
	sed -e 's|@prefix@|$(prefix)|g' \
	    -e 's|@libdir@|$(libdir)|g' \
	    -e 's|@includedir@|$(includedir)|g' \
	    -e 's|@VERSION@|$(VERSION)|g' \
	    $< > $@

# source tarball (for rpm build)
dist: clean
	mkdir -p taskhealth-$(VERSION)
	cp -r $(SRCDIR) $(INCDIR) $(DEMODIR) $(DAEMONDIR) debian contrib man Makefile \
		taskhealth.pc.in LICENSE LICENSE.MIT README.md \
		taskhealth-$(VERSION)/
	tar czf $(TARNAME) taskhealth-$(VERSION)
	rm -rf taskhealth-$(VERSION)

# Debian package
deb:
	debuild -b -uc -us

# RPM package
rpm: dist
	rpmbuild -ta $(TARNAME)

.PHONY: all all-full clean check check-daemon check-integration cov install demo test test-daemon test-integration dist deb rpm
