diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1428dec --- /dev/null +++ b/Makefile @@ -0,0 +1,140 @@ +# SPDX-License-Identifier: GPL-3.0-only +# SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts® +# +# Distro-packaging build path. project.cpp (crafter-build) remains the +# canonical build description; this Makefile mirrors it for environments +# where crafter-build isn't packaged — same clang module pipeline, same +# flags. Keep the two in sync when products, module partitions or link +# flags change. +# +# make -> build/make/{imsd,imsd-media,imsd-dialerd} +# make check -> build + run the 7 unit-test suites +# make install -> DESTDIR/PREFIX staged install (binaries + systemd +# unit, D-Bus policy, dialerd autostart, ims-pdn-up.sh) +# +# Requires clang++ with libc++ and the libc++ std module sources +# (std.cppm — Alpine: llvm-runtimes, Arch: libc++). Override STD_CPPM if +# yours lives elsewhere. + +# make's builtin default is CXX=g++, and distro build environments (abuild) +# export CXX=c++ — both gcc, which has no --precompile. This build requires +# clang: the file assignment deliberately ignores the environment while still +# yielding to an explicit `make CXX=...`. +CXX = clang++ +AR ?= ar +PKG_CONFIG ?= pkg-config +STD_CPPM ?= /usr/share/libc++/v1/std.cppm + +O ?= build/make +PCM = $(O)/pcm +OBJ = $(O)/obj + +OPT ?= -O3 +# One flag set for every TU: BMIs are rejected on compiler-option mismatch, +# so per-target extras are limited to -I/-D (compile) and -l/-L (link). +ALL_CXXFLAGS = -std=c++26 -stdlib=libc++ $(OPT) $(CXXFLAGS) +ALL_LDFLAGS = -fuse-ld=lld $(LDFLAGS) + +# pkg-config gio-2.0: only -I/-D pass through — it also emits -pthread, +# which would config-mismatch the shared std BMI (project.cpp filters +# identically). pthread lives in libc on every platform we target. +GIO_CFLAGS := $(filter -I% -D%,$(shell $(PKG_CONFIG) --cflags gio-2.0)) +GIO_LIBS := $(filter -l% -L%,$(shell $(PKG_CONFIG) --libs gio-2.0)) +ifeq ($(strip $(GIO_LIBS)),) +GIO_LIBS := -lgio-2.0 -lgobject-2.0 -lglib-2.0 +endif + +# Imsd module partitions, plus the primary interface last. The BMI file +# names must stay -.pcm — that is how clang resolves +# `import :Part;` under -fprebuilt-module-path. +PARTITIONS = Imsd-Util Imsd-Sip Imsd-Sdp Imsd-Aka Imsd-Ipsec \ + Imsd-Messages Imsd-Engine +CORE_MODULES = $(PARTITIONS) Imsd +CORE_OBJS = $(CORE_MODULES:%=$(OBJ)/%.o) + +TESTS = Util Aka Ipsec Messages Engine Sip Sdp + +all: $(O)/imsd $(O)/imsd-media $(O)/imsd-dialerd + +# ---- module BMIs ---------------------------------------------------------- + +$(PCM)/std.pcm: $(STD_CPPM) | $(PCM) + $(CXX) $(ALL_CXXFLAGS) -Wno-reserved-identifier \ + -Wno-reserved-module-identifier --precompile $< -o $@ + +$(PCM)/%.pcm: interfaces/%.cppm $(PCM)/std.pcm | $(PCM) + $(CXX) $(ALL_CXXFLAGS) -fprebuilt-module-path=$(PCM) --precompile $< -o $@ + +# partition import graph (see the `import :X;` lines in interfaces/) +$(PCM)/Imsd-Aka.pcm $(PCM)/Imsd-Ipsec.pcm: $(PCM)/Imsd-Util.pcm +$(PCM)/Imsd-Messages.pcm: $(PCM)/Imsd-Util.pcm $(PCM)/Imsd-Aka.pcm \ + $(PCM)/Imsd-Sip.pcm +$(PCM)/Imsd-Engine.pcm: $(PCM)/Imsd-Util.pcm $(PCM)/Imsd-Sip.pcm \ + $(PCM)/Imsd-Sdp.pcm $(PCM)/Imsd-Messages.pcm +$(PCM)/Imsd.pcm: $(PARTITIONS:%=$(PCM)/%.pcm) + +# ---- imsd-core (static lib of the pure-C++ engine modules) ---------------- + +$(OBJ)/%.o: $(PCM)/%.pcm | $(OBJ) + $(CXX) $(ALL_CXXFLAGS) -fprebuilt-module-path=$(PCM) -c $< -o $@ + +$(O)/libimsd-core.a: $(CORE_OBJS) + $(AR) rcs $@ $^ + +# ---- executables ----------------------------------------------------------- + +$(OBJ)/main.o: implementations/main.cpp $(PCM)/Imsd.pcm | $(OBJ) + $(CXX) $(ALL_CXXFLAGS) $(GIO_CFLAGS) -fprebuilt-module-path=$(PCM) \ + -c $< -o $@ + +$(O)/imsd: $(OBJ)/main.o $(O)/libimsd-core.a + $(CXX) $(ALL_CXXFLAGS) $(ALL_LDFLAGS) $^ $(GIO_LIBS) -lpthread -o $@ + +$(OBJ)/media.o: implementations/media.cpp $(PCM)/std.pcm | $(OBJ) + $(CXX) $(ALL_CXXFLAGS) -fprebuilt-module-path=$(PCM) -c $< -o $@ + +$(O)/imsd-media: $(OBJ)/media.o + $(CXX) $(ALL_CXXFLAGS) $(ALL_LDFLAGS) $^ -ldl -lpthread -o $@ + +$(OBJ)/dialerd.o: implementations/dialerd.cpp $(PCM)/std.pcm | $(OBJ) + $(CXX) $(ALL_CXXFLAGS) $(GIO_CFLAGS) -fprebuilt-module-path=$(PCM) \ + -c $< -o $@ + +$(O)/imsd-dialerd: $(OBJ)/dialerd.o + $(CXX) $(ALL_CXXFLAGS) $(ALL_LDFLAGS) $^ $(GIO_LIBS) -o $@ + +# ---- tests ----------------------------------------------------------------- + +$(O)/tests/%: tests/%/main.cpp $(PCM)/Imsd.pcm $(O)/libimsd-core.a | $(O)/tests + $(CXX) $(ALL_CXXFLAGS) $(ALL_LDFLAGS) -fprebuilt-module-path=$(PCM) \ + $< $(O)/libimsd-core.a -lpthread -o $@ + +check: $(TESTS:%=$(O)/tests/%) + @fail=0; for t in $(TESTS); do \ + echo "== $$t"; $(O)/tests/$$t || fail=1; \ + done; exit $$fail + +# ---- install ---------------------------------------------------------------- + +PREFIX ?= /usr + +install: all + install -Dm755 $(O)/imsd $(DESTDIR)$(PREFIX)/bin/imsd + install -Dm755 $(O)/imsd-dialerd $(DESTDIR)$(PREFIX)/bin/imsd-dialerd + install -Dm755 $(O)/imsd-media $(DESTDIR)$(PREFIX)/libexec/imsd-media + install -Dm755 packaging/ims-pdn-up.sh \ + $(DESTDIR)$(PREFIX)/libexec/ims-pdn-up.sh + install -Dm644 packaging/imsd.service \ + $(DESTDIR)$(PREFIX)/lib/systemd/system/imsd.service + install -Dm644 packaging/imsd-dialerd.desktop \ + $(DESTDIR)/etc/xdg/autostart/imsd-dialerd.desktop + install -Dm644 packaging/net.catcrafts.IMS1.conf \ + $(DESTDIR)$(PREFIX)/share/dbus-1/system.d/net.catcrafts.IMS1.conf + +$(PCM) $(OBJ) $(O)/tests: + mkdir -p $@ + +clean: + rm -rf $(O) + +.PHONY: all check install clean diff --git a/README.md b/README.md index f7a6f62..7dbec22 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,21 @@ crafter-build -- --product=dialerd # bin/imsd-dialerd-.../imsd-dialerd (dialer crafter-build test # unit tests (Util, Aka, Ipsec, Messages, Engine, Sip, Sdp) ``` +### Building with make (distro packaging) + +For environments without crafter-build, the Makefile mirrors the same clang +module pipeline: GNU make, clang++ with libc++ and the libc++ std module +sources (`std.cppm` — package `llvm-runtimes` on Alpine, `libc++` on Arch), +lld, and gio-2.0 headers. + +```sh +make # build/make/{imsd,imsd-media,imsd-dialerd} +make check # the same 7 unit-test suites +make install # DESTDIR/PREFIX staged install incl. the packaging/ files +``` + +`project.cpp` stays the canonical build description; the Makefile tracks it. + ### Cross-compiling for a phone (aarch64 Alpine/postmarketOS) ```sh @@ -121,8 +136,9 @@ after `packaging/ims-pdn-up.sh` has brought up the ims PDN through ModemManager. It spawns `/usr/libexec/imsd-media` per call. Registration resumes an in-kernel IPsec SA when one is present (avoiding the network's fresh-SA throttle) and keeps itself alive with a re-REGISTER refresh at half -the granted lifetime. `packaging/APKBUILD.binary` + `make-bin-tarball.sh` -wrap a cross-compiled build into an apk. +the granted lifetime. `packaging/APKBUILD` builds the apk from source via +the Makefile; `packaging/APKBUILD.binary` + `make-bin-tarball.sh` wrap a +cross-compiled build into an apk instead. ## Configuration diff --git a/packaging/APKBUILD b/packaging/APKBUILD index 162ba4e..9a7e429 100644 --- a/packaging/APKBUILD +++ b/packaging/APKBUILD @@ -1,9 +1,6 @@ # SPDX-License-Identifier: GPL-3.0-only # SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts® # Maintainer: Jorijn van der Graaf -# APKBUILD skeleton — buildable once crafter-build is packaged for Alpine -# (or replaced here by a bootstrap invocation). Until then this documents -# the packaging shape. pkgname=imsd pkgver=0.3.0 pkgrel=0 @@ -14,29 +11,25 @@ license="GPL-3.0-only" # the media leg dlopen's the AMR-WB codecs; pw-record/pw-play drive PipeWire — # none of which abuild's .so auto-scan can see depends="modemmanager opencore-amr vo-amrwbenc pipewire-tools" -# versioned provides = imsd satisfies soc-qcom-modem's 81voltd dependency AND -# excludes the real package: 81voltd serves the modem's own ims-PDN requests, -# which races imsd for the PDN and flaps it with a new prefix every ~2.5 min -# (fp6 journal/ims.md s57) — the two IMS stacks cannot share one PDN +# clang/libc++ C++26 modules build (see Makefile); llvm-runtimes ships the +# libc++ std module sources (/usr/share/libc++/v1/std.cppm) it precompiles +makedepends="clang lld libc++-dev llvm-libunwind-dev llvm-runtimes glib-dev pkgconf" +# the versioned provides both satisfies soc-qcom-modem's 81voltd dependency +# and excludes the real package: 81voltd serves the modem's own ims-PDN +# requests, which races imsd for the PDN and flaps it with a new prefix every +# ~2.5 min — the two IMS stacks cannot share one PDN provides="81voltd=$pkgver-r$pkgrel" -makedepends="clang lld libc++-dev glib-dev crafter-build" -source="" -options="!check" # crafter-build test needs qemu for cross; run natively in CI +source="$pkgname-$pkgver.tar.gz::$url/archive/v$pkgver.tar.gz" +builddir="$srcdir/$pkgname" build() { - crafter-build - crafter-build -- --product=media - crafter-build -- --product=dialerd + make +} + +check() { + make check } package() { - install -Dm755 bin/imsd-*/imsd "$pkgdir"/usr/bin/imsd - install -Dm755 bin/imsd-media-*/imsd-media "$pkgdir"/usr/libexec/imsd-media - install -Dm755 bin/imsd-dialerd-*/imsd-dialerd "$pkgdir"/usr/bin/imsd-dialerd - install -Dm755 packaging/ims-pdn-up.sh "$pkgdir"/usr/libexec/ims-pdn-up.sh - install -Dm644 packaging/imsd.service "$pkgdir"/usr/lib/systemd/system/imsd.service - install -Dm644 packaging/imsd-dialerd.desktop \ - "$pkgdir"/etc/xdg/autostart/imsd-dialerd.desktop - install -Dm644 packaging/net.catcrafts.IMS1.conf \ - "$pkgdir"/usr/share/dbus-1/system.d/net.catcrafts.IMS1.conf + make install DESTDIR="$pkgdir" }