Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
211 changes: 142 additions & 69 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,44 +1,36 @@
# =============================================================================
# Build and Test Workflow for libppd (x86_64 / ubuntu-latest)
# Multi-Architecture Build & Test Workflow for libppd
#
# Modelled on the libcupsfilters CI in the sister OpenPrinting repository.
# Scope is intentionally restricted to a single native architecture
# (x86_64 on ubuntu-latest) so the build runs quickly and deterministically
# while still proving:
# Modelled on the QEMU-based CI used in the sister OpenPrinting repositories
# (libcupsfilters, cups-filters). Proves on every push / PR / manual dispatch
# that libppd compiles end-to-end (libppd.la + every check_PROGRAMS binary)
# and that every registered TEST in Makefile.am passes under
# `make check V=1 VERBOSE=1` on FOUR architectures:
#
# * The complete repository compiles end-to-end (libppd.la plus all
# declared programs and tests under check_PROGRAMS) — not just that
# the test binaries link against an already-built library.
# * All registered TESTS pass (the 8 native C unit tests added in this
# cycle: testppd, test_ppd_localize, test_ppd_cache, test_ppd_ipp,
# test_ppd_mark, test_ppd_custom, test_ppd_attr, test_ppd_page,
# test_ppd_conflicts). test_ppd_load_profile is intentionally
# deregistered in Makefile.am pending mentor review of a latent
# bug in ppdLutLoad().
# * amd64 - native, ubuntu-latest
# * arm64 - native, ubuntu-24.04-arm
# * armhf - emulated via QEMU (armv7)
# * riscv64 - emulated via QEMU
#
# The apt package list was derived from a direct scan of configure.ac:
# The hermetic C unit tests exercised: testppd, test_ppd_localize,
# test_ppd_cache, test_ppd_ipp, test_ppd_mark, test_ppd_custom,
# test_ppd_attr, test_ppd_page, test_ppd_conflicts.
#
# * PKG_CHECK_MODULES([LIBCUPSFILTERS], [libcupsfilters]) -> libcupsfilters-dev
# * PKG_CHECK_MODULES([ZLIB], [zlib]) -> zlib1g-dev
# * AC_PATH_TOOL(CUPSCONFIG, [cups-config]) (cups3 absent
# on ubuntu-latest, falls back to libcups2) -> libcups2-dev
# * AC_CHECK_PROG(CUPS_GHOSTSCRIPT, gs) -> ghostscript
# * AC_CHECK_PROG(CUPS_PDFTOPS, pdftops) -> poppler-utils
# * AC_CHECK_PROG(CUPS_MUTOOL, mutool) -> mupdf-tools
# * pdftocairo (Poppler renderer) -> poppler-utils
# * AM_GNU_GETTEXT([external]) / AM_ICONV -> gettext, autopoint
# * AC_PROG_CC, AC_PROG_CXX, AX_CXX_COMPILE_STDCXX([11]) -> build-essential
# * LT_INIT -> libtool
# * PKG_PROG_PKG_CONFIG -> pkg-config
# * AC_PROG_INSTALL -> (provided by build-essential)
#
# All three of ghostscript / poppler-utils / mupdf-tools are installed so
# the default ./configure (no --disable-* flags) succeeds — that gives us
# the maximum-coverage build the user asked for ("comprehensive build,
# rather than just checking if the unit tests run").
# apt package list derived from libppd's configure.ac:
# PKG_CHECK_MODULES([LIBCUPSFILTERS]) -> libcupsfilters-dev
# PKG_CHECK_MODULES([ZLIB]) -> zlib1g-dev
# AC_PATH_TOOL(CUPSCONFIG) -> libcups2-dev
# AC_CHECK_PROG(gs / pdftops / mutool) -> ghostscript, poppler-utils,
# mupdf-tools
# AM_GNU_GETTEXT([external]) -> gettext, autopoint
# AC_PROG_CC / CXX / LT_INIT / pkg-config -> build-essential, autoconf,
# automake, libtool,
# libtool-bin, pkg-config
# transitive (poppler / qpdf renderers) -> libqpdf-dev, libpoppler-dev,
# libpoppler-cpp-dev
# =============================================================================

name: Build and Test (libppd)
name: Build and Test (libppd, multi-arch)

on:
push:
Expand All @@ -51,73 +43,154 @@ on:

jobs:
build:
name: Build & Test (x86_64)
runs-on: ubuntu-latest
name: Build & Test (${{ matrix.arch }})
runs-on: ${{ matrix.runs-on }}

strategy:
fail-fast: false
matrix:
include:
- arch: amd64
runs-on: ubuntu-latest
use-qemu: false
- arch: arm64
runs-on: ubuntu-24.04-arm
use-qemu: false
- arch: armhf
runs-on: ubuntu-latest
use-qemu: true
qemu-arch: armv7
- arch: riscv64
runs-on: ubuntu-latest
use-qemu: true
qemu-arch: riscv64

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Save workspace directory
run: echo "REPO_DIR=$(pwd)" >> $GITHUB_ENV

# -----------------------------------------------------------------------
# System dependencies — derived from configure.ac (see header comment).
# NATIVE LEG (amd64 on ubuntu-latest, arm64 on ubuntu-24.04-arm)
# -----------------------------------------------------------------------
- name: Install build & runtime dependencies
- name: Install dependencies (native)
if: matrix.use-qemu == false
run: |
set -ex
sudo apt-get update --fix-missing -y
sudo apt-get clean
sudo apt-get update --fix-missing -y -o Acquire::Retries=3
# Drop any pre-shipped libppd-dev so our local build wins
sudo apt-get remove -y libppd-dev || true
sudo apt-get install -y --no-install-recommends \
build-essential \
autoconf \
automake \
autopoint \
libtool \
libtool-bin \
pkg-config \
gettext \
git \
wget \
tar \
libcups2-dev \
libcupsfilters-dev \
libqpdf-dev \
libpoppler-dev \
libpoppler-cpp-dev \
zlib1g-dev \
ghostscript \
poppler-utils \
mupdf-tools

# -----------------------------------------------------------------------
# Full build — autogen.sh regenerates configure / Makefile.in from the
# autotools sources; configure runs without --disable-* flags so every
# external renderer (gs / pdftops / mutool / pdftocairo) is exercised;
# make -j$(nproc) builds the library AND every check_PROGRAMS binary,
# surfacing any compiler errors or warnings as build output.
# -----------------------------------------------------------------------
- name: autogen.sh
run: ./autogen.sh

- name: configure
run: ./configure

- name: make
run: make -j$(nproc) V=1
- name: Build & test libppd (native)
if: matrix.use-qemu == false
run: |
set -ex
cd "$REPO_DIR"
./autogen.sh
./configure
make -j$(nproc) V=1
make check V=1 VERBOSE=1 || {
echo "==== test-suite.log ===="
test -f test-suite.log && cat test-suite.log
echo "==== per-test logs ===="
for f in $(find . -name '*.log' -not -name 'config.log'); do
echo "---- $f ----"; cat "$f"
done
exit 1
}

# -----------------------------------------------------------------------
# Run the registered TESTS. V=1 and VERBOSE=1 expose both the
# compile-line per object AND each test's stderr in the workflow log
# on failure, matching the libcupsfilters CI pattern. We deliberately
# do NOT pipe stderr away — a failing test prints its full diagnostic
# before the step exits non-zero, and the test-suite.log artifact (see
# next step) preserves the full automake summary for download.
# EMULATED LEG (armhf via QEMU armv7, riscv64 via QEMU)
# -----------------------------------------------------------------------
- name: make check
id: check
run: make check V=1 VERBOSE=1
- name: Set up QEMU
if: matrix.use-qemu == true
uses: docker/setup-qemu-action@v3
with:
platforms: ${{ matrix.qemu-arch }}

- name: Build & test libppd (emulated)
if: matrix.use-qemu == true
uses: uraimo/run-on-arch-action@v3
with:
arch: ${{ matrix.qemu-arch }}
distro: ubuntu24.04
dockerRunArgs: |
--volume "${{ github.workspace }}:/workspace"
install: |
apt-get clean
apt-get update --fix-missing -y -o Acquire::Retries=3
DEBIAN_FRONTEND=noninteractive apt-get install -y tzdata
apt-get remove -y libppd-dev 2>/dev/null || true
apt-get install -y --no-install-recommends \
build-essential \
gcc g++ \
autoconf \
automake \
autopoint \
libtool \
libtool-bin \
pkg-config \
gettext \
git \
wget \
tar \
libcups2-dev \
libcupsfilters-dev \
libqpdf-dev \
libpoppler-dev \
libpoppler-cpp-dev \
zlib1g-dev \
ghostscript \
poppler-utils \
mupdf-tools
run: |
set -ex
cd /workspace
./autogen.sh
./configure
make -j$(nproc) V=1
make check V=1 VERBOSE=1 || {
echo "==== test-suite.log ===="
test -f test-suite.log && cat test-suite.log
echo "==== per-test logs ===="
for f in $(find . -name '*.log' -not -name 'config.log'); do
echo "---- $f ----"; cat "$f"
done
exit 1
}

# -----------------------------------------------------------------------
# Artifact upload — only fires when `make check` failed. Captures the
# top-level test-suite.log automake produces plus any per-test .log /
# .trs files so the failure can be diagnosed offline.
# ARTIFACT UPLOAD (all four legs, only on failure)
# -----------------------------------------------------------------------
- name: Upload test-suite.log on failure
if: failure() && steps.check.conclusion == 'failure'
- name: Upload test logs on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: libppd-test-suite-log-x86_64
name: libppd-test-logs-${{ matrix.arch }}
path: |
test-suite.log
**/*.log
Expand Down
Loading