From b1514d2fe415fe53367989ee9dd127020a5f5722 Mon Sep 17 00:00:00 2001 From: acetone <63557806+freeacetone@users.noreply.github.com> Date: Fri, 2 Oct 2026 04:36:41 -0400 Subject: [PATCH] build static deb and rpm packages for all architectures --- .github/workflows/build-static.yml | 78 +++++++++++++++++- contrib/static/debian/control | 17 ++++ contrib/static/debian/copyright-bundled | 9 +++ contrib/static/debian/i2pd.docs | 2 + contrib/static/debian/i2pd.links | 4 + contrib/static/debian/i2pd.lintian-overrides | 2 + contrib/static/debian/i2pd.manpages | 1 + contrib/static/debian/i2pd.postinst | 47 +++++++++++ contrib/static/debian/i2pd.postrm | 15 ++++ contrib/static/debian/i2pd.prerm | 12 +++ contrib/static/debian/rules | 28 +++++++ contrib/static/debian/source/format | 1 + contrib/static/i2pd.spec | 84 ++++++++++++++++++++ contrib/static/package.sh | 51 ++++++++++++ 14 files changed, 347 insertions(+), 4 deletions(-) create mode 100644 contrib/static/debian/control create mode 100644 contrib/static/debian/copyright-bundled create mode 100644 contrib/static/debian/i2pd.docs create mode 100644 contrib/static/debian/i2pd.links create mode 100644 contrib/static/debian/i2pd.lintian-overrides create mode 100644 contrib/static/debian/i2pd.manpages create mode 100644 contrib/static/debian/i2pd.postinst create mode 100644 contrib/static/debian/i2pd.postrm create mode 100644 contrib/static/debian/i2pd.prerm create mode 100755 contrib/static/debian/rules create mode 100644 contrib/static/debian/source/format create mode 100644 contrib/static/i2pd.spec create mode 100755 contrib/static/package.sh diff --git a/.github/workflows/build-static.yml b/.github/workflows/build-static.yml index fc5f3f61..8e8bd8a4 100644 --- a/.github/workflows/build-static.yml +++ b/.github/workflows/build-static.yml @@ -6,18 +6,18 @@ on: - '*' paths: - .github/workflows/build-static.yml - - contrib/static/** + - contrib/** - daemon/** + - debian/** - i18n/** - libi2pd/** - libi2pd_client/** - Makefile - Makefile.linux - tags: - - '*' pull_request: branches: - '*' + workflow_call: jobs: build: @@ -30,15 +30,33 @@ jobs: include: - arch: x86_64 runner: ubuntu-latest + platform: linux/amd64 - arch: aarch64 runner: ubuntu-24.04-arm + platform: linux/arm64 + - arch: armhf + runner: ubuntu-latest + platform: linux/arm/v6 + qemu: true + - arch: x86 + runner: ubuntu-latest + platform: linux/386 + setarch: linux32 + - arch: s390x + runner: ubuntu-latest + platform: linux/s390x + qemu: true steps: - name: Checkout uses: actions/checkout@v4 + - name: Set up QEMU + if: ${{ matrix.qemu }} + uses: docker/setup-qemu-action@v3 + - name: Build in Alpine - run: docker run --rm -v "$PWD":/src -w /src alpine:3.22 sh contrib/static/build-musl.sh + run: docker run --rm --platform ${{ matrix.platform }} -v "$PWD":/src -w /src alpine:3.22 ${{ matrix.setarch }} sh contrib/static/build-musl.sh - name: Check binary run: | @@ -62,3 +80,55 @@ jobs: with: name: i2pd-static-${{ matrix.arch }} path: i2pd + + package: + name: deb and rpm packages + needs: build + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Download binaries + uses: actions/download-artifact@v4 + with: + pattern: i2pd-static-* + path: bin + + - name: Set package version + run: | + if [ "$GITHUB_REF_TYPE" = tag ]; then + echo "VERSION=$GITHUB_REF_NAME" >> $GITHUB_ENV + echo "RPM_VERSION=$GITHUB_REF_NAME" >> $GITHUB_ENV + echo "RPM_RELEASE=1" >> $GITHUB_ENV + else + base=$(sed -nE 's/^#define I2PD_VERSION_(MAJOR|MINOR|MICRO) ([0-9]+)$/\2/p' libi2pd/version.h | paste -sd.) + rev=git$(git log -1 --format=%cd --date=format:%Y%m%d).$(git rev-parse --short=7 HEAD) + echo "VERSION=$base+$rev" >> $GITHUB_ENV + echo "RPM_VERSION=$base" >> $GITHUB_ENV + echo "RPM_RELEASE=0.$rev" >> $GITHUB_ENV + fi + + - name: Build deb packages + run: docker run --rm -e VERSION -v "$PWD":/src -w /src debian:bookworm sh contrib/static/package.sh deb bin out + + - name: Build rpm packages + run: docker run --rm -e VERSION -e RPM_VERSION -e RPM_RELEASE -v "$PWD":/src -w /src rockylinux:9 sh contrib/static/package.sh rpm bin out + + - name: Test packages + run: | + for img in debian:trixie ubuntu:24.04; do + docker run --rm -e DEBIAN_FRONTEND=noninteractive -v "$PWD/out":/o $img sh -ec \ + 'apt-get update -qq; apt-get install -y -qq /o/*_linux-all_amd64.deb; dpkg -V i2pd; i2pd --version; apt-get purge -y -qq i2pd' + done + for img in rockylinux:9 fedora:latest; do + docker run --rm -v "$PWD/out":/o $img sh -ec \ + 'dnf -q -y install /o/*_linux-all_x86_64.rpm; rpm -V i2pd; i2pd --version; dnf -q -y remove i2pd' + done + + - name: Upload packages + uses: actions/upload-artifact@v4 + with: + name: i2pd-linux-all + path: out/* diff --git a/contrib/static/debian/control b/contrib/static/debian/control new file mode 100644 index 00000000..6d469ebf --- /dev/null +++ b/contrib/static/debian/control @@ -0,0 +1,17 @@ +Source: i2pd +Section: net +Priority: optional +Maintainer: r4sas +Build-Depends: debhelper-compat (= 13) +Standards-Version: 4.5.1 +Homepage: https://i2pd.website/ +Rules-Requires-Root: binary-targets + +Package: i2pd +Architecture: amd64 arm64 armhf i386 s390x +Depends: adduser, ${misc:Depends} +Description: Full-featured C++ implementation of I2P client (static build) + I2P (Invisible Internet Protocol) is a universal anonymous network layer. + . + This package ships a fully static binary (musl, bundled OpenSSL, Boost, + zlib and miniupnpc) that does not depend on the distribution release. diff --git a/contrib/static/debian/copyright-bundled b/contrib/static/debian/copyright-bundled new file mode 100644 index 00000000..aea773bc --- /dev/null +++ b/contrib/static/debian/copyright-bundled @@ -0,0 +1,9 @@ + +Files: usr/bin/i2pd +Comment: The binary statically links the following third-party components. + OpenSSL - Apache-2.0 + Boost (program_options, json, url) - BSL-1.0 + zlib - Zlib + miniupnpc - BSD-3-Clause + musl - MIT + libstdc++ and libgcc - GPL-3.0+ with GCC Runtime Library Exception diff --git a/contrib/static/debian/i2pd.docs b/contrib/static/debian/i2pd.docs new file mode 100644 index 00000000..6498e8de --- /dev/null +++ b/contrib/static/debian/i2pd.docs @@ -0,0 +1,2 @@ +src/README.md +src/ChangeLog diff --git a/contrib/static/debian/i2pd.links b/contrib/static/debian/i2pd.links new file mode 100644 index 00000000..16558791 --- /dev/null +++ b/contrib/static/debian/i2pd.links @@ -0,0 +1,4 @@ +etc/i2pd/i2pd.conf var/lib/i2pd/i2pd.conf +etc/i2pd/tunnels.conf var/lib/i2pd/tunnels.conf +etc/i2pd/tunnels.conf.d var/lib/i2pd/tunnels.d +usr/share/i2pd/certificates var/lib/i2pd/certificates diff --git a/contrib/static/debian/i2pd.lintian-overrides b/contrib/static/debian/i2pd.lintian-overrides new file mode 100644 index 00000000..5a37b0da --- /dev/null +++ b/contrib/static/debian/i2pd.lintian-overrides @@ -0,0 +1,2 @@ +i2pd: embedded-library +i2pd: statically-linked-binary diff --git a/contrib/static/debian/i2pd.manpages b/contrib/static/debian/i2pd.manpages new file mode 100644 index 00000000..b82d209d --- /dev/null +++ b/contrib/static/debian/i2pd.manpages @@ -0,0 +1 @@ +src/debian/i2pd.1 diff --git a/contrib/static/debian/i2pd.postinst b/contrib/static/debian/i2pd.postinst new file mode 100644 index 00000000..475f5ddb --- /dev/null +++ b/contrib/static/debian/i2pd.postinst @@ -0,0 +1,47 @@ +#!/bin/sh +set -e + +LOGFILE='/var/log/i2pd/i2pd.log' +I2PDHOME='/var/lib/i2pd' +I2PDUSER='i2pd' + +case "$1" in + configure|reconfigure) + # Older versions of adduser created the home directory. + # The version of adduser in Debian unstable does not. + # Create user and group as a system user. + if getent passwd $I2PDUSER > /dev/null 2>&1; then + groupadd -f $I2PDUSER || true + else + adduser --system --quiet --group --home $I2PDHOME $I2PDUSER + fi + + mkdir -p -m0750 /var/log/i2pd + chown -f ${I2PDUSER}:adm /var/log/i2pd + touch $LOGFILE + chmod 640 $LOGFILE + chown -f ${I2PDUSER}:adm $LOGFILE + mkdir -p $I2PDHOME + chown -f -P ${I2PDUSER}:${I2PDUSER} ${I2PDHOME} + chmod 0700 $I2PDHOME + ;; + abort-upgrade|abort-remove|abort-deconfigure) + echo "Aborting upgrade" + exit 0 + ;; + *) + echo "postinst called with unknown argument '$1'" >&2 + exit 0 + ;; +esac + +#DEBHELPER# + +if [ "$1" = "configure" ] && [ -x /etc/init.d/i2pd ]; then + update-rc.d i2pd defaults >/dev/null + if [ ! -d /run/systemd/system ]; then + invoke-rc.d i2pd restart || true + fi +fi + +exit 0 diff --git a/contrib/static/debian/i2pd.postrm b/contrib/static/debian/i2pd.postrm new file mode 100644 index 00000000..951a1331 --- /dev/null +++ b/contrib/static/debian/i2pd.postrm @@ -0,0 +1,15 @@ +#!/bin/sh +set -e + +if [ "$1" = "purge" ]; then + update-rc.d i2pd remove >/dev/null || true + rm -f /etc/default/i2pd + rm -rf /etc/i2pd + rm -rf /var/lib/i2pd + rm -rf /var/log/i2pd + rm -rf /run/i2pd +fi + +#DEBHELPER# + +exit 0 diff --git a/contrib/static/debian/i2pd.prerm b/contrib/static/debian/i2pd.prerm new file mode 100644 index 00000000..6c29f5fe --- /dev/null +++ b/contrib/static/debian/i2pd.prerm @@ -0,0 +1,12 @@ +#!/bin/sh +set -e + +if [ ! -d /run/systemd/system ] && [ -x /etc/init.d/i2pd ]; then + case "$1" in + remove|upgrade|deconfigure) invoke-rc.d i2pd stop || true ;; + esac +fi + +#DEBHELPER# + +exit 0 diff --git a/contrib/static/debian/rules b/contrib/static/debian/rules new file mode 100755 index 00000000..52d16b6f --- /dev/null +++ b/contrib/static/debian/rules @@ -0,0 +1,28 @@ +#!/usr/bin/make -f +include /usr/share/dpkg/architecture.mk + +PKG := debian/i2pd + +%: + dh $@ + +override_dh_auto_build override_dh_auto_test override_dh_auto_clean override_dh_auto_configure: + +override_dh_auto_install: + install -D -m 0755 bin/i2pd-$(DEB_HOST_ARCH) $(PKG)/usr/bin/i2pd + install -D -m 0644 src/contrib/i2pd.conf $(PKG)/etc/i2pd/i2pd.conf + install -D -m 0644 src/contrib/tunnels.conf $(PKG)/etc/i2pd/tunnels.conf + install -D -m 0644 src/contrib/subscriptions.txt $(PKG)/etc/i2pd/subscriptions.txt + install -D -m 0644 src/contrib/tunnels.d/README $(PKG)/etc/i2pd/tunnels.conf.d/README + install -d $(PKG)/usr/share/i2pd + cp -r src/contrib/certificates $(PKG)/usr/share/i2pd/ + +override_dh_strip override_dh_dwz override_dh_shlibdeps override_dh_makeshlibs: + +override_dh_builddeb: + dh_builddeb -- -Zxz + +# generated invoke-rc.d --skip-systemd-native needs init-system-helpers >= 1.54, +# which Ubuntu 18.04 lacks; the maintainer scripts handle sysvinit themselves +override_dh_installinit: + dh_installinit --no-scripts diff --git a/contrib/static/debian/source/format b/contrib/static/debian/source/format new file mode 100644 index 00000000..89ae9db8 --- /dev/null +++ b/contrib/static/debian/source/format @@ -0,0 +1 @@ +3.0 (native) diff --git a/contrib/static/i2pd.spec b/contrib/static/i2pd.spec new file mode 100644 index 00000000..9142541b --- /dev/null +++ b/contrib/static/i2pd.spec @@ -0,0 +1,84 @@ +%global debug_package %{nil} +%global __os_install_post %{nil} +%global _build_id_links none +# xz payload and sha256 digests: readable by rpm 4.11 (CentOS 7) and newer +%define _binary_payload w9.xzdio +%define _source_payload w9.xzdio +%define _binary_filedigest_algorithm 8 +%define _source_filedigest_algorithm 8 + +Name: i2pd +Version: %{ver} +Release: %{rel} +Summary: I2P router written in C++ (static build) +License: BSD-3-Clause +URL: https://i2pd.website/ +Source0: i2pd-%{_target_cpu} +Requires(pre): /usr/sbin/useradd +Requires(pre): /usr/sbin/groupadd +Requires(pre): /usr/bin/getent + +%description +I2P router written in C++. Fully static binary (musl, bundled OpenSSL, +Boost, zlib and miniupnpc) that does not depend on the distribution release. + +%prep +%build + +%install +S=%{srcdir} +install -D -m 755 %{SOURCE0} %{buildroot}/usr/bin/i2pd +install -d -m 755 %{buildroot}/usr/share/i2pd +install -d -m 700 %{buildroot}/var/lib/i2pd +install -d -m 700 %{buildroot}/var/log/i2pd +install -D -m 644 $S/contrib/i2pd.conf %{buildroot}/etc/i2pd/i2pd.conf +install -D -m 644 $S/contrib/subscriptions.txt %{buildroot}/etc/i2pd/subscriptions.txt +install -D -m 644 $S/contrib/tunnels.conf %{buildroot}/etc/i2pd/tunnels.conf +install -D -m 644 $S/contrib/tunnels.d/README %{buildroot}/etc/i2pd/tunnels.conf.d/README +install -D -m 644 $S/contrib/i2pd.logrotate %{buildroot}/etc/logrotate.d/i2pd +install -D -m 644 $S/contrib/i2pd.service %{buildroot}/usr/lib/systemd/system/i2pd.service +install -D -m 644 $S/debian/i2pd.1 %{buildroot}/usr/share/man/man1/i2pd.1 +install -D -m 644 $S/LICENSE %{buildroot}/usr/share/licenses/i2pd/LICENSE +cp -r $S/contrib/certificates %{buildroot}/usr/share/i2pd/certificates +ln -s /usr/share/i2pd/certificates %{buildroot}/var/lib/i2pd/certificates + +%pre +getent group i2pd >/dev/null || groupadd -r i2pd +getent passwd i2pd >/dev/null || \ + useradd -r -g i2pd -s /sbin/nologin -d /var/lib/i2pd -c 'I2P Service' i2pd +exit 0 + +%post +systemctl daemon-reload >/dev/null 2>&1 || : +if [ $1 -eq 1 ]; then + systemctl preset i2pd.service >/dev/null 2>&1 || : +fi + +%preun +if [ $1 -eq 0 ]; then + systemctl --no-reload disable --now i2pd.service >/dev/null 2>&1 || : +fi + +%postun +systemctl daemon-reload >/dev/null 2>&1 || : +if [ $1 -ge 1 ]; then + systemctl try-restart i2pd.service >/dev/null 2>&1 || : +fi + +%files +%license /usr/share/licenses/i2pd/LICENSE +/usr/bin/i2pd +%dir /etc/i2pd +%config(noreplace) /etc/i2pd/i2pd.conf +%config(noreplace) /etc/i2pd/tunnels.conf +%config(noreplace) /etc/i2pd/subscriptions.txt +%dir /etc/i2pd/tunnels.conf.d +%doc /etc/i2pd/tunnels.conf.d/README +%config(noreplace) /etc/logrotate.d/i2pd +/usr/lib/systemd/system/i2pd.service +/usr/share/man/man1/i2pd.1* +/usr/share/i2pd +%dir %attr(0700,i2pd,i2pd) /var/lib/i2pd +/var/lib/i2pd/certificates +%dir %attr(0700,i2pd,i2pd) /var/log/i2pd + diff --git a/contrib/static/package.sh b/contrib/static/package.sh new file mode 100755 index 00000000..a3992770 --- /dev/null +++ b/contrib/static/package.sh @@ -0,0 +1,51 @@ +#!/bin/sh +# Packages static binaries from BIN/i2pd-static-/i2pd, run inside debian (deb) or rocky/fedora (rpm) +# usage: package.sh deb|rpm BIN OUT, with VERSION (deb), RPM_VERSION and RPM_RELEASE in the environment +set -e + +FORMAT=$1 +BIN=$(realpath "$2") +mkdir -p "$3" +OUT=$(realpath "$3") +SRC=$(cd "$(dirname "$0")/../.." && pwd) +# alpine:deb:rpm architecture names +ARCHS="x86_64:amd64:x86_64 aarch64:arm64:aarch64 armhf:armhf:armv7hl x86:i386:i686 s390x:s390x:s390x" +WORK=$(mktemp -d) + +if [ "$FORMAT" = deb ]; then + apt-get update -qq + DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends debhelper dpkg-dev lintian >/dev/null + PKG=$WORK/pkg + mkdir -p $PKG/bin + cp -r "$SRC/contrib/static/debian" $PKG/debian + cat "$SRC/debian/copyright" $PKG/debian/copyright-bundled > $PKG/debian/copyright + rm $PKG/debian/copyright-bundled + cp "$SRC/contrib/i2pd.service" $PKG/debian/i2pd.service + cp "$SRC/contrib/debian/i2pd.tmpfile" $PKG/debian/i2pd.tmpfiles + cp "$SRC/contrib/i2pd.logrotate" $PKG/debian/i2pd.logrotate + cp "$SRC/debian/i2pd.init" $PKG/debian/i2pd.init + cp "$SRC/debian/i2pd.default" $PKG/debian/i2pd.default + ln -s "$SRC" $PKG/src + printf 'i2pd (%s-1) stable; urgency=medium\n\n * Static build.\n\n -- %s %s\n' \ + "$VERSION" "$(sed -n 's/^Maintainer: //p' $PKG/debian/control)" "$(date -R)" > $PKG/debian/changelog + for a in $ARCHS; do + alpine=${a%%:*}; rest=${a#*:}; deb=${rest%%:*} + install -m 755 "$BIN/i2pd-static-$alpine/i2pd" $PKG/bin/i2pd-$deb + (cd $PKG && dpkg-buildpackage -b -us -uc -a$deb -d) + mv $WORK/i2pd_$VERSION-1_$deb.deb "$OUT/i2pd_${VERSION}_linux-all_$deb.deb" + done + lintian --fail-on error "$OUT/i2pd_${VERSION}_linux-all_amd64.deb" +elif [ "$FORMAT" = rpm ]; then + dnf -q -y install rpm-build >/dev/null + mkdir -p $WORK/sources + for a in $ARCHS; do + alpine=${a%%:*}; rpm=${a##*:} + install -m 755 "$BIN/i2pd-static-$alpine/i2pd" $WORK/sources/i2pd-$rpm + rpmbuild -bb --target $rpm -D "ver $RPM_VERSION" -D "rel $RPM_RELEASE" -D "srcdir $SRC" \ + -D "_topdir $WORK/rpmbuild" -D "_sourcedir $WORK/sources" -D "_rpmdir $WORK/rpms" "$SRC/contrib/static/i2pd.spec" + mv $WORK/rpms/$rpm/i2pd-$RPM_VERSION-$RPM_RELEASE.$rpm.rpm "$OUT/i2pd_${VERSION}_linux-all_$rpm.rpm" + done +else + echo "usage: $0 deb|rpm BIN OUT" >&2 + exit 1 +fi