# gKeyMapper - Build # Dependencies: g++, pkg-config, gettext (msgfmt, for the translations), # libgtk-4-dev, libusb-1.0-0-dev, libxkbcommon-dev # Installation: sudo apt install build-essential gettext libgtk-4-dev libusb-1.0-0-dev libxkbcommon-dev CXX ?= g++ CXXFLAGS ?= -std=c++17 -O2 -Wall -Wextra -Wpedantic PKG_CONFIG ?= pkg-config MSGFMT ?= msgfmt GLIB_COMPILE_RESOURCES ?= glib-compile-resources GTK_CFLAGS := $(shell $(PKG_CONFIG) --cflags gtk4) GTK_LIBS := $(shell $(PKG_CONFIG) --libs gtk4) 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) GIO_CFLAGS := $(shell $(PKG_CONFIG) --cflags gio-2.0) GIO_LIBS := $(shell $(PKG_CONFIG) --libs gio-2.0) 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) # Icons embedded into the GUI (generated from data/icons.gresource.xml). GUI_RES := build/gresources.c GUI_RES_SRC := data/icons.gresource.xml PREFIX ?= /usr/local DEB_VERSION ?= 0.1.0 DEB_ARCH := $(shell dpkg --print-architecture 2>/dev/null || echo amd64) BINDIR := $(PREFIX)/bin LOCALEDIR := $(PREFIX)/share/locale ASSETS_DIR := $(PREFIX)/share/$(PACKAGE)/assets UDEV_DIR := $(PREFIX)/lib/udev/rules.d MODULES_DIR := $(PREFIX)/lib/modules-load.d UNIT_DIR := $(PREFIX)/lib/systemd/user DBUS_DIR := $(PREFIX)/share/dbus-1/services CXXFLAGS += -DPACKAGE=\"$(PACKAGE)\" -DLOCALEDIR=\"$(LOCALEDIR)\" -DASSETS_DIR=\"$(ASSETS_DIR)\" CXXFLAGS += -I$(SHARED_DIR) # 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. PO_FILES := $(wildcard po/*.po) LANGS := $(patsubst po/%.po,%,$(PO_FILES)) MO_FILES := $(patsubst %,locale/%/LC_MESSAGES/$(PACKAGE).mo,$(LANGS)) I18N := $(CURDIR)/scripts/i18n.sh .PHONY: all clean run install translations daemon pot i18n-check i18n-status deb all: $(TARGET) translations $(DAEMON) # 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) daemon: $(DAEMON) $(DAEMON): $(DAEMON_SOURCES) $(DAEMON_HEADERS) $(CXX) $(CXXFLAGS) $(USB_CFLAGS) $(XKB_CFLAGS) $(GIO_CFLAGS) -o $@ $(DAEMON_SOURCES) $(USB_LIBS) $(XKB_LIBS) $(GIO_LIBS) translations: $(MO_FILES) locale/%/LC_MESSAGES/$(PACKAGE).mo: po/%.po @mkdir -p $(@D) $(MSGFMT) -o $@ $< # 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 run: $(TARGET) translations GKEYMAPPER_LOCALEDIR=$(CURDIR)/locale GKEYMAPPER_ASSETS_DIR=$(CURDIR)/assets ./$(TARGET) deb: $(CURDIR)/scripts/make-deb.sh $(DEB_VERSION) $(DEB_ARCH) clean: rm -f $(TARGET) $(DAEMON) rm -rf locale build install: $(TARGET) $(DAEMON) translations install -d $(DESTDIR)$(BINDIR) install -m 755 $(TARGET) $(DESTDIR)$(BINDIR)/$(TARGET) install -m 755 $(DAEMON) $(DESTDIR)$(BINDIR)/$(DAEMON) 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; \ 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 # 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 -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)"