# mouseboard - keyboard-driven virtual pointer for Wayland.
#
# Override on the command line, e.g.  make PREFIX=$HOME/.local
#
# `make` is the dev build: it links the system's shared wayland-client and
# xkbcommon (install the dev packages; see README). `make static` is the
# shipping build: it compiles and links against the static archives in
# musl-sysroot/, which ./provision-static.sh builds once per machine.

VERSION = 0-dev

PREFIX ?= /usr/local
BINDIR ?= $(PREFIX)/bin
MANDIR ?= $(PREFIX)/share/man/man1

CC ?= cc
PKG_CONFIG ?= pkg-config
WAYLAND_SCANNER ?= wayland-scanner

PKGS = wayland-client xkbcommon

# STATIC=1 (what the `static` target runs) switches to the provisioned musl
# sysroot: its cc wrapper, its pkg-config metadata, and a fully static link.
STATIC ?= 0
ifeq ($(STATIC),1)
SYSROOT := $(CURDIR)/musl-sysroot
CC = $(SYSROOT)/bin/cc
# provision-static.sh builds a matching wayland-scanner into the sysroot, so
# the static build needs no host wayland-scanner (versions can't drift).
WAYLAND_SCANNER = $(SYSROOT)/bin/wayland-scanner
PKGCONF = PKG_CONFIG_PATH=$(SYSROOT)/lib/pkgconfig:$(SYSROOT)/share/pkgconfig $(PKG_CONFIG)
# -s strips at link: the shipped binary carries no symbols or debug info
# (musl's and libffi's archives ship with debug sections). The dev build
# keeps symbols for gdb.
MB_LDFLAGS = -static -s
MB_LDLIBS = $(shell $(PKGCONF) --static --libs $(PKGS) 2>/dev/null)
else
PKGCONF = $(PKG_CONFIG)
MB_LDLIBS = $(shell $(PKGCONF) --libs $(PKGS) 2>/dev/null)
endif

CFLAGS ?= -std=c11 -Wall -Wextra -O2
override CPPFLAGS += -DMOUSEBOARD_VERSION='"$(VERSION)"'
override CPPFLAGS += $(shell $(PKGCONF) --cflags $(PKGS) 2>/dev/null)

# Protocols vendored under proto/; generated glue lives at the top level.
PROTOCOLS = \
	xdg-shell \
	xdg-output-unstable-v1 \
	wlr-layer-shell-unstable-v1 \
	wlr-virtual-pointer-unstable-v1

PROTO_H = $(PROTOCOLS:%=%-protocol.h)
PROTO_C = $(PROTOCOLS:%=%-protocol.c)
PROTO_O = $(PROTOCOLS:%=%-protocol.o)

OBJ = main.o core.o config.o draw.o font.o backend-wayland.o $(PROTO_O)
SELFTEST_SRC = selftest.c core.c config.c draw.c font.c

# font8x8_basic.h is vendored verbatim; its 0xFF rows overflow signed char.
font.o: override CFLAGS += -Wno-overflow

all: mouseboard

check: mouseboard-selftest
	./mouseboard-selftest

mouseboard-selftest: $(SELFTEST_SRC) config.h core.h draw.h font.h platform.h \
	font8x8_basic.h
	$(CC) $(CPPFLAGS) $(CFLAGS) -Wno-overflow -o $@ $(SELFTEST_SRC)

# Objects from the other mode were built by a different compiler, so switching
# always starts clean. Going back: make clean && make.
static:
	$(MAKE) clean
	$(MAKE) STATIC=1

mouseboard: $(OBJ)
	$(CC) $(CFLAGS) $(LDFLAGS) $(MB_LDFLAGS) -o $@ $(OBJ) \
		$(LDLIBS) $(MB_LDLIBS)

# Every object depends on every header: over-rebuilds a little, never links
# stale.
$(OBJ): $(PROTO_H) config.h core.h draw.h font.h platform.h font8x8_basic.h

ifeq ($(STATIC),1)
# provision-static.sh writes the stamp last, once the sysroot is complete.
check-deps:
	@test -f $(SYSROOT)/.provisioned || { \
		echo "mouseboard: musl-sysroot/ missing or incomplete;"; \
		echo "  run ./provision-static.sh first"; \
		exit 1; }
else
check-deps:
	@command -v $(WAYLAND_SCANNER) >/dev/null 2>&1 && \
	 $(PKG_CONFIG) --exists $(PKGS) 2>/dev/null || { \
		echo "mouseboard: wayland-client/xkbcommon not found by pkg-config."; \
		echo "  dev build: install wayland-scanner, libwayland-dev,"; \
		echo "             and libxkbcommon-dev"; \
		echo "  static binary (needs no system libs):"; \
		echo "    ./provision-static.sh && make static"; \
		exit 1; }
endif

# Every object needs the generated headers, so nothing compiles before the
# toolchain check runs.
$(PROTO_H) $(PROTO_C): | check-deps

%-protocol.h: proto/%.xml
	$(WAYLAND_SCANNER) client-header $< $@

%-protocol.c: proto/%.xml
	$(WAYLAND_SCANNER) private-code $< $@

install: mouseboard
	install -d $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)
	install -m 755 mouseboard $(DESTDIR)$(BINDIR)/mouseboard
	install -m 644 mouseboard.1 $(DESTDIR)$(MANDIR)/mouseboard.1

uninstall:
	rm -f $(DESTDIR)$(BINDIR)/mouseboard $(DESTDIR)$(MANDIR)/mouseboard.1

clean:
	rm -f mouseboard mouseboard-selftest $(OBJ) $(PROTO_H) $(PROTO_C)

.PHONY: all static check check-deps install uninstall clean
