2026-10-16 22:11:52 +02:00
|
|
|
# gKeyMapper - Build
|
2026-10-18 20:26:22 +02:00
|
|
|
# Dependencies: g++, pkg-config, gettext (msgfmt, for the translations),
|
|
|
|
|
# libgtk-4-dev, libusb-1.0-0-dev, libxkbcommon-dev
|
2026-10-17 03:53:51 +02:00
|
|
|
# Installation: sudo apt install build-essential gettext libgtk-4-dev libusb-1.0-0-dev libxkbcommon-dev
|
2026-10-16 22:11:52 +02:00
|
|
|
|
|
|
|
|
CXX ?= g++
|
|
|
|
|
CXXFLAGS ?= -std=c++17 -O2 -Wall -Wextra -Wpedantic
|
|
|
|
|
PKG_CONFIG ?= pkg-config
|
|
|
|
|
MSGFMT ?= msgfmt
|
2026-10-18 02:57:29 +02:00
|
|
|
GLIB_COMPILE_RESOURCES ?= glib-compile-resources
|
2026-10-16 22:11:52 +02:00
|
|
|
|
|
|
|
|
GTK_CFLAGS := $(shell $(PKG_CONFIG) --cflags gtk4)
|
|
|
|
|
GTK_LIBS := $(shell $(PKG_CONFIG) --libs gtk4)
|
2026-10-17 03:53:51 +02:00
|
|
|
USB_CFLAGS := $(shell $(PKG_CONFIG) --cflags libusb-1.0)
|
|
|
|
|
USB_LIBS := $(shell $(PKG_CONFIG) --libs libusb-1.0)
|
|
|
|
|
XKB_CFLAGS := $(shell $(PKG_CONFIG) --cflags xkbcommon)
|
|
|
|
|
XKB_LIBS := $(shell $(PKG_CONFIG) --libs xkbcommon)
|
2026-10-18 02:57:29 +02:00
|
|
|
GIO_CFLAGS := $(shell $(PKG_CONFIG) --cflags gio-2.0)
|
|
|
|
|
GIO_LIBS := $(shell $(PKG_CONFIG) --libs gio-2.0)
|
2026-10-16 22:11:52 +02:00
|
|
|
|
2026-10-17 03:53:51 +02:00
|
|
|
PACKAGE := gkeymapper
|
|
|
|
|
TARGET := gkeymapper
|
|
|
|
|
DAEMON := gkeymapper-daemon
|
|
|
|
|
SRC_DIR := src
|
|
|
|
|
SHARED_DIR := shared
|
|
|
|
|
DAEMON_DIR := daemon
|
|
|
|
|
GUI_SOURCES := $(wildcard $(SRC_DIR)/*.cpp) $(wildcard $(SHARED_DIR)/*.cpp)
|
|
|
|
|
GUI_HEADERS := $(wildcard $(SRC_DIR)/*.h) $(wildcard $(SHARED_DIR)/*.h)
|
|
|
|
|
DAEMON_SOURCES := $(wildcard $(DAEMON_DIR)/*.cpp) $(wildcard $(SHARED_DIR)/*.cpp)
|
|
|
|
|
DAEMON_HEADERS := $(wildcard $(DAEMON_DIR)/*.h) $(wildcard $(SHARED_DIR)/*.h)
|
2026-10-18 02:57:29 +02:00
|
|
|
# Icons embedded into the GUI (generated from data/icons.gresource.xml).
|
|
|
|
|
GUI_RES := build/gresources.c
|
|
|
|
|
GUI_RES_SRC := data/icons.gresource.xml
|
2026-10-17 03:53:51 +02:00
|
|
|
PREFIX ?= /usr/local
|
2026-10-18 22:58:08 +02:00
|
|
|
DEB_VERSION ?= 0.1.1
|
2026-10-18 22:53:39 +02:00
|
|
|
DEB_ARCH := $(shell dpkg --print-architecture 2>/dev/null || echo amd64)
|
2026-10-17 03:53:51 +02:00
|
|
|
BINDIR := $(PREFIX)/bin
|
|
|
|
|
LOCALEDIR := $(PREFIX)/share/locale
|
2026-10-16 22:11:52 +02:00
|
|
|
ASSETS_DIR := $(PREFIX)/share/$(PACKAGE)/assets
|
2026-10-17 03:53:51 +02:00
|
|
|
UDEV_DIR := $(PREFIX)/lib/udev/rules.d
|
|
|
|
|
MODULES_DIR := $(PREFIX)/lib/modules-load.d
|
|
|
|
|
UNIT_DIR := $(PREFIX)/lib/systemd/user
|
2026-10-18 02:57:29 +02:00
|
|
|
DBUS_DIR := $(PREFIX)/share/dbus-1/services
|
2026-10-16 22:11:52 +02:00
|
|
|
|
|
|
|
|
CXXFLAGS += -DPACKAGE=\"$(PACKAGE)\" -DLOCALEDIR=\"$(LOCALEDIR)\" -DASSETS_DIR=\"$(ASSETS_DIR)\"
|
2026-10-17 03:53:51 +02:00
|
|
|
CXXFLAGS += -I$(SHARED_DIR)
|
2026-10-16 22:11:52 +02:00
|
|
|
|
2026-10-18 20:26:22 +02:00
|
|
|
# Translations. The .pot is generated from the sources (make pot) and the
|
|
|
|
|
# catalogs are merged against it (scripts/i18n.sh update); the rules are in
|
|
|
|
|
# po/README.md.
|
2026-10-16 22:11:52 +02:00
|
|
|
PO_FILES := $(wildcard po/*.po)
|
|
|
|
|
LANGS := $(patsubst po/%.po,%,$(PO_FILES))
|
|
|
|
|
MO_FILES := $(patsubst %,locale/%/LC_MESSAGES/$(PACKAGE).mo,$(LANGS))
|
2026-10-18 20:26:22 +02:00
|
|
|
I18N := $(CURDIR)/scripts/i18n.sh
|
2026-10-16 22:11:52 +02:00
|
|
|
|
2026-10-18 22:53:39 +02:00
|
|
|
.PHONY: all clean run install translations daemon pot i18n-check i18n-status deb
|
2026-10-16 22:11:52 +02:00
|
|
|
|
2026-10-17 03:53:51 +02:00
|
|
|
all: $(TARGET) translations $(DAEMON)
|
2026-10-16 22:11:52 +02:00
|
|
|
|
2026-10-18 02:57:29 +02:00
|
|
|
# Embedded GUI icons. --c-name keeps the gkeymapper_* symbols stable; --sourcedir
|
|
|
|
|
# is the repository root because the XML refers to the assets by their real path.
|
|
|
|
|
$(GUI_RES): $(GUI_RES_SRC) assets/icon.png assets/icon.svg
|
|
|
|
|
@mkdir -p $(@D)
|
|
|
|
|
$(GLIB_COMPILE_RESOURCES) --generate-source --target=$@ --sourcedir=. \
|
|
|
|
|
--c-name $(PACKAGE) $(GUI_RES_SRC)
|
|
|
|
|
|
|
|
|
|
$(TARGET): $(GUI_SOURCES) $(GUI_HEADERS) $(GUI_RES)
|
|
|
|
|
$(CXX) $(CXXFLAGS) $(GTK_CFLAGS) $(XKB_CFLAGS) -o $@ $(GUI_SOURCES) $(GUI_RES) $(GTK_LIBS) $(XKB_LIBS)
|
2026-10-17 03:53:51 +02:00
|
|
|
|
|
|
|
|
daemon: $(DAEMON)
|
|
|
|
|
|
|
|
|
|
$(DAEMON): $(DAEMON_SOURCES) $(DAEMON_HEADERS)
|
2026-10-18 02:57:29 +02:00
|
|
|
$(CXX) $(CXXFLAGS) $(USB_CFLAGS) $(XKB_CFLAGS) $(GIO_CFLAGS) -o $@ $(DAEMON_SOURCES) $(USB_LIBS) $(XKB_LIBS) $(GIO_LIBS)
|
2026-10-16 22:11:52 +02:00
|
|
|
|
|
|
|
|
translations: $(MO_FILES)
|
|
|
|
|
|
|
|
|
|
locale/%/LC_MESSAGES/$(PACKAGE).mo: po/%.po
|
|
|
|
|
@mkdir -p $(@D)
|
|
|
|
|
$(MSGFMT) -o $@ $<
|
|
|
|
|
|
2026-10-18 20:26:22 +02:00
|
|
|
# Regenerate po/gkeymapper.pot from the sources. "make translations" does not: a
|
|
|
|
|
# pot that is written by a build is a pot that nobody has looked at, and the
|
|
|
|
|
# strings are reviewed by hand (po/README.md, "Adding or changing a string").
|
|
|
|
|
pot:
|
|
|
|
|
$(I18N) extract
|
|
|
|
|
|
|
|
|
|
# Everything that can be wrong with the translations at once: the pot against the
|
|
|
|
|
# sources, every catalog against the pot, and the language list of the GUI against
|
|
|
|
|
# po/*.po. Run it before committing a string change.
|
|
|
|
|
i18n-check:
|
|
|
|
|
$(I18N) check
|
|
|
|
|
|
|
|
|
|
i18n-status:
|
|
|
|
|
$(I18N) status
|
|
|
|
|
|
2026-10-16 22:11:52 +02:00
|
|
|
run: $(TARGET) translations
|
|
|
|
|
GKEYMAPPER_LOCALEDIR=$(CURDIR)/locale GKEYMAPPER_ASSETS_DIR=$(CURDIR)/assets ./$(TARGET)
|
|
|
|
|
|
2026-10-18 22:53:39 +02:00
|
|
|
deb:
|
|
|
|
|
$(CURDIR)/scripts/make-deb.sh $(DEB_VERSION) $(DEB_ARCH)
|
|
|
|
|
|
|
|
|
|
|
2026-10-16 22:11:52 +02:00
|
|
|
clean:
|
2026-10-17 03:53:51 +02:00
|
|
|
rm -f $(TARGET) $(DAEMON)
|
2026-10-18 02:57:29 +02:00
|
|
|
rm -rf locale build
|
2026-10-16 22:11:52 +02:00
|
|
|
|
2026-10-17 03:53:51 +02:00
|
|
|
install: $(TARGET) $(DAEMON) translations
|
|
|
|
|
install -d $(DESTDIR)$(BINDIR)
|
|
|
|
|
install -m 755 $(TARGET) $(DESTDIR)$(BINDIR)/$(TARGET)
|
|
|
|
|
install -m 755 $(DAEMON) $(DESTDIR)$(BINDIR)/$(DAEMON)
|
2026-10-16 22:11:52 +02:00
|
|
|
install -d $(DESTDIR)$(ASSETS_DIR)
|
|
|
|
|
install -m 644 assets/* $(DESTDIR)$(ASSETS_DIR)/
|
|
|
|
|
install -d $(DESTDIR)$(PREFIX)/share/icons/hicolor/256x256/apps
|
|
|
|
|
install -m 644 assets/icon.png $(DESTDIR)$(PREFIX)/share/icons/hicolor/256x256/apps/$(PACKAGE).png
|
|
|
|
|
install -d $(DESTDIR)$(PREFIX)/share/icons/hicolor/scalable/apps
|
|
|
|
|
install -m 644 assets/icon.svg $(DESTDIR)$(PREFIX)/share/icons/hicolor/scalable/apps/$(PACKAGE).svg
|
|
|
|
|
-command -v gtk-update-icon-cache >/dev/null && gtk-update-icon-cache -q -t $(DESTDIR)$(PREFIX)/share/icons/hicolor 2>/dev/null || true
|
|
|
|
|
install -d $(DESTDIR)$(PREFIX)/share/applications
|
|
|
|
|
install -m 644 data/gkeymapper.desktop $(DESTDIR)$(PREFIX)/share/applications/$(PACKAGE).desktop
|
|
|
|
|
-command -v update-desktop-database >/dev/null && update-desktop-database $(DESTDIR)$(PREFIX)/share/applications 2>/dev/null || true
|
|
|
|
|
for lang in $(LANGS); do \
|
|
|
|
|
install -d $(DESTDIR)$(LOCALEDIR)/$$lang/LC_MESSAGES; \
|
|
|
|
|
install -m 644 locale/$$lang/LC_MESSAGES/$(PACKAGE).mo \
|
|
|
|
|
$(DESTDIR)$(LOCALEDIR)/$$lang/LC_MESSAGES/$(PACKAGE).mo; \
|
2026-10-17 03:53:51 +02:00
|
|
|
done
|
|
|
|
|
# udev: access to the vendor interface and /dev/uinput without root.
|
|
|
|
|
install -d $(DESTDIR)$(UDEV_DIR)
|
|
|
|
|
install -m 644 data/60-gkeymapper.rules $(DESTDIR)$(UDEV_DIR)/60-gkeymapper.rules
|
|
|
|
|
# Kernel module needed for the virtual keyboard.
|
|
|
|
|
install -d $(DESTDIR)$(MODULES_DIR)
|
|
|
|
|
install -m 644 data/gkeymapper-uinput.conf $(DESTDIR)$(MODULES_DIR)/$(PACKAGE).conf
|
|
|
|
|
# systemd user unit (@BINDIR@ is substituted with the configured PREFIX).
|
|
|
|
|
install -d $(DESTDIR)$(UNIT_DIR)
|
|
|
|
|
sed 's|@BINDIR@|$(BINDIR)|g' data/$(DAEMON).service > $(DESTDIR)$(UNIT_DIR)/$(DAEMON).service
|
|
|
|
|
chmod 644 $(DESTDIR)$(UNIT_DIR)/$(DAEMON).service
|
2026-10-18 02:57:29 +02:00
|
|
|
# D-Bus activation: the first GUI call can start the daemon on demand.
|
|
|
|
|
install -d $(DESTDIR)$(DBUS_DIR)
|
|
|
|
|
sed 's|@BINDIR@|$(BINDIR)|g' data/dev.rager.gkeymapper.Daemon.service > $(DESTDIR)$(DBUS_DIR)/dev.rager.gkeymapper.Daemon.service
|
|
|
|
|
chmod 644 $(DESTDIR)$(DBUS_DIR)/dev.rager.gkeymapper.Daemon.service
|
2026-10-17 03:53:51 +02:00
|
|
|
-command -v udevadm >/dev/null && udevadm control --reload-rules 2>/dev/null || true
|
|
|
|
|
-systemctl --user daemon-reload 2>/dev/null || true
|
|
|
|
|
@echo
|
|
|
|
|
@echo "Installed. Enable the daemon in your user session with:"
|
|
|
|
|
@echo " systemctl --user daemon-reload"
|
|
|
|
|
@echo " systemctl --user enable --now $(DAEMON)"
|