Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*.sh text eol=lf
*.yml text eol=lf
*.yaml text eol=lf
212 changes: 154 additions & 58 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,79 +1,175 @@
name: Build SpliX
name: Build Splix .deb Packages (CMake)

on:
push:
paths:
- 'src/**'
branches: [master, main, modernized-2026]
tags: ['v*']
pull_request:
paths:
- 'src/**'
branches: [master, main, modernized-2026]
workflow_dispatch:

permissions:
contents: read

concurrency:
group: splix-build-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
build:
name: Build ${{ matrix.deb_arch }}
runs-on: ubuntu-latest
name: Build
steps:
- name: Git checkout
uses: actions/checkout@v4
timeout-minutes: 30
permissions:
contents: write # Required only when the release step runs for v* tags.
strategy:
fail-fast: false
matrix:
include:
# ── AMD64 (native) ──────────────────────────────────────────────
- deb_arch: amd64
cmake_preset: ci-amd64

- name: Declare short commit variable
id: vars
run: |
echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
# ── ARM64 (cross-compiled) ─────────────────────────────────────
- deb_arch: arm64
cmake_preset: ci-arm64

- name: Create cache directory
run: mkdir ~/cache
# ── ARMHF (cross-compiled) ─────────────────────────────────────
- deb_arch: armhf
cmake_preset: ci-armhf

- id: cache
name: Initialize cache
uses: actions/cache@v5
# ── i386 (cross-compiled) ──────────────────────────────────────
- deb_arch: i386
cmake_preset: ci-i386

# ── RISCV64 (cross-compiled) ───────────────────────────────────
- deb_arch: riscv64
cmake_preset: ci-riscv64

steps:
- name: Checkout code
uses: actions/checkout@v7
with:
path: ~/cache
key: cache-${{ runner.os }}
fetch-depth: 0 # Fetch all history for all branches and tags

- name: APT install
run: |
sudo sed -i 's~Types: ~Types: deb-src ~' /etc/apt/sources.list.d/ubuntu.sources
sudo apt update
sudo DEBIAN_FRONTEND=noninteractive apt install -y build-essential libcups2-dev cups groff nano less ninja-build
sudo DEBIAN_FRONTEND=noninteractive apt build-dep -y cups
- name: Restore ccache
uses: actions/cache@v6
with:
path: .ccache
key: ccache-cmake-${{ matrix.deb_arch }}-${{ github.sha }}
restore-keys: |
ccache-cmake-${{ matrix.deb_arch }}-

- if: steps.cache.outputs.cache-hit != 'true'
name: Build polyfill-glibc
- name: Build and package inside Debian stable
run: |
git clone https://github.com/corsix/polyfill-glibc.git && cd polyfill-glibc && ninja
cp polyfill-glibc ~/cache/
mkdir -p "${PWD}/artifacts" "${PWD}/.ccache"

- if: steps.cache.outputs.cache-hit != 'true'
name: Build libjbig
run: |
mkdir jbig && cd jbig && apt source jbigkit
cd jbigkit-* && make -j4
cp libjbig/libjbig85.a ~/cache/
docker run --rm \
--platform linux/amd64 \
-v "${PWD}:/workspace" \
-v "${PWD}/.ccache:/root/.ccache" \
-w /workspace \
-e CCACHE_DIR=/root/.ccache \
-e DEB_ARCH="${{ matrix.deb_arch }}" \
-e CMAKE_PRESET="${{ matrix.cmake_preset }}" \
-e GITHUB_REF_NAME="${{ github.ref_name }}" \
debian:stable \
bash -c '
set -euo pipefail

- name: Build SpliX
run: |
JB=$(realpath ~/cache/libjbig85.a)
echo $JB
ls -la $JB
# use static libjbig
sed -i "s~-ljbig85~/${JB}~" module.mk
# force libcupsimage dynamic linking, as newer cups on newer ubuntu links it from libcups
sed -i 's~rastertoqpdl_LIBS.*:= ~rastertoqpdl_LIBS := -lcupsimage ~' module.mk
grep 'libjbig' module.mk
make DRV_ONLY=1 -j4
make ppd
rm -rf optimized/src
mv ppd optimized/

- name: Patch for older glibc
run: |
~/cache/polyfill-glibc --target-glibc=2.17 optimized/rastertoqpdl
~/cache/polyfill-glibc --target-glibc=2.17 optimized/pstoqpdl
# ── Base dependencies ──────────────────────────────────────────
apt-get update -y
apt-get install -y --fix-missing \
build-essential cmake \
cups libcups2-dev libcupsimage2-dev libjbig-dev \
pkg-config ccache git ca-certificates

# ── Cross-compilation dependencies ───────────────────────
if [ "${DEB_ARCH}" != "amd64" ]; then
dpkg --add-architecture "${DEB_ARCH}"
apt-get update -y

case "${DEB_ARCH}" in
arm64) CROSS_PKG="gcc-aarch64-linux-gnu g++-aarch64-linux-gnu" ;;
armhf) CROSS_PKG="gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf" ;;
i386) CROSS_PKG="gcc-i686-linux-gnu g++-i686-linux-gnu" ;;
riscv64) CROSS_PKG="gcc-riscv64-linux-gnu g++-riscv64-linux-gnu" ;;
esac

apt-get install -y --fix-missing ${CROSS_PKG} \
libcups2-dev:${DEB_ARCH} \
libcupsimage2-dev:${DEB_ARCH} \
libjbig-dev:${DEB_ARCH}
fi
# Put ccache wrappers first so they intercept gcc/g++ calls.
# For cross-compilation ccache transparently wraps the cross-compiler.
export PATH="/usr/lib/ccache:${PATH}"

- name: Save build artifacts
# ── CMake configure + build ────────────────────────────────────
rm -rf /tmp/splix-build

cmake --preset "${CMAKE_PRESET}"
cmake --build --preset "${CMAKE_PRESET}"

# ── Package as .deb via CPack ──────────────────────────────────
cd /tmp/splix-build
cpack -G DEB

# Assert release identity and copy only the target package.
package_path="/tmp/splix-build/splix-3.0.0-${DEB_ARCH}.deb"
test -f "${package_path}"
cp -v "${package_path}" /workspace/artifacts/

echo "── Packaged artifacts ──────────────────────────────"
ls -lh /workspace/artifacts/
'

- name: Upload .deb artifact
uses: actions/upload-artifact@v7
with:
name: splix_x86_64_${{ steps.vars.outputs.sha_short }}
path: optimized/
name: splix-deb-${{ matrix.deb_arch }}
path: artifacts/*.deb
if-no-files-found: error

# On version tags (e.g. v3.0.0) attach the .deb files to the GitHub
# Release created for that tag.
- name: Attach to GitHub Release (version tags only)
if: startsWith(github.ref, 'refs/tags/v')
uses: softprops/action-gh-release@v3
with:
files: artifacts/*.deb

# ── Sanitizer Check ────────────────────────────────────────────────────────
# Runs the functional test suite under AddressSanitizer and
# UndefinedBehaviorSanitizer to catch memory bugs in PRs.
security-audit:
name: Sanitizer Check (ASan/UBSan)
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- name: Checkout code
uses: actions/checkout@v7
with:
fetch-depth: 0

- name: Build and Test with Sanitizers
run: |
docker run --rm \
-v "${PWD}:/workspace" \
-w /workspace \
debian:stable \
bash -c '
set -euo pipefail
apt-get update -y
apt-get install -y build-essential cmake cups libcups2-dev \
libcupsimage2-dev libjbig-dev pkg-config \
git ca-certificates xxd

# Configure with ASan preset
cmake --preset linux-asan
cmake --build --preset linux-asan

# Run tests (ctest will invoke functional_test.sh)
cd build-asan
ctest --output-on-failure
'
13 changes: 13 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,16 @@ gmon.out
optimized
ppd/*.drv
tmp

# CMake build directories
build/
build-*/

# CI artifacts
artifacts/

# Compiler cache
.ccache/

# CMake user presets (local overrides, not committed)
CMakeUserPresets.json
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
Aurélien Croc <aurelien AT ap2c DOT org>
Till Kamppeter <till DOT kamppeter AT gmail DOT com>
ValdikSS <iam AT valdikss DOT org DOT ru>
Michael Maertzdorf <dutch2005 AT gmail DOT com>
119 changes: 119 additions & 0 deletions BUILDING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# Building SpliX 3.0.0

SpliX 3.0.0 uses CMake and requires a compiler/standard-library pair with the
C++23 facilities used by the driver: `std::expected`, `std::span`,
`std::semaphore`, and `std::jthread`.

## Native build

On Debian 13 (trixie) or a compatible Ubuntu release:

```bash
sudo apt-get update
sudo apt-get install \
build-essential cmake pkg-config cups \
libcups2-dev libcupsimage2-dev libjbig-dev

cmake --preset linux-amd64-release
cmake --build --preset linux-amd64-release --parallel
ctest --test-dir build-amd64 --output-on-failure
```

The minimum supported CMake version is 3.25. Configuration performs an actual
C++23 library probe; compiler version numbers alone are not treated as proof of
support.

## Debug and sanitizer builds

```bash
cmake --preset linux-debug
cmake --build --preset linux-debug --parallel
ctest --test-dir build-debug --output-on-failure

cmake --preset linux-asan
cmake --build --preset linux-asan --parallel
ctest --test-dir build-asan --output-on-failure
```

## Cross-compilation

CI cross-compiles Debian packages for `arm64`, `armhf`, `i386`, and `riscv64`.
For example, an ARM64 build on Debian requires:

```bash
sudo dpkg --add-architecture arm64
sudo apt-get update
sudo apt-get install \
gcc-aarch64-linux-gnu g++-aarch64-linux-gnu \
libcups2-dev:arm64 libcupsimage2-dev:arm64 libjbig-dev:arm64

cmake --preset linux-arm64-release
cmake --build --preset linux-arm64-release --parallel
```

The `ci-*` presets use `/tmp/splix-build` and are intended for the GitHub
Actions container. Toolchain files under `cmake/` select the target compiler,
library roots, and target `pkg-config` directory.

## Package generation

After a successful build:

```bash
cd build-amd64
cpack -G DEB
```

The resulting name follows `splix-3.0.0-<architecture>.deb`.

## Install paths and options

Common overrides:

```bash
cmake -S . -B build \
-DSPLIX_FILTER_DIR=/usr/lib/cups/filter \
-DSPLIX_PPD_DIR=/usr/share/cups/model \
-DSPLIX_PROFILE_DIR=/usr/share/cups/profiles
```

Feature options:

- `DISABLE_JBIG=ON` disables algorithms that require libjbig.
- `DISABLE_THREADS=ON` disables threaded compression.
- `DISABLE_BLACKOPTIM=ON` disables CMYK black optimization.
- `THREADS=<n>` selects compression worker count.
- `CACHESIZE=<pages>` selects the maximum resident compressed-page count.

Install to the system or a staging root with:

```bash
sudo cmake --install build-amd64
DESTDIR=/tmp/splix-stage cmake --install build-amd64
```

## Verification

The native test suite includes byte-level compression characterization,
concurrency behavior, filter functional tests, ASan/UBSan execution, and
multi-architecture compile/package checks.

Run the Docker-oriented helper used by contributors with:

```bash
./tests/run_tests_docker.sh
```

Generated PPD files are committed and installed directly; end users do not
need `cups-ppdc` to build the driver.

## Troubleshooting

- `SpliX requires C++23 library support for std::expected`: use a newer
compiler and standard library together. A new compiler with an older library
can still fail this probe.
- `CUPS development headers not found`: install `libcups2-dev` and
`pkg-config`.
- `libcupsimage not found`: install `libcupsimage2-dev`.
- `libjbig not found`: install `libjbig-dev` or configure with
`-DDISABLE_JBIG=ON`.
Loading