dxpdf 0.2.23

A fast DOCX-to-PDF converter powered by Skia
name: CI

on:
  pull_request:
    branches: [main]
  push:
    branches: [main]

env:
  CARGO_TERM_COLOR: always
  RUST_BACKTRACE: 1

jobs:
  check:
    name: Check & Lint
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: dtolnay/rust-toolchain@stable
        with:
          components: clippy, rustfmt

      - uses: Swatinem/rust-cache@v2

      - name: Install system dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y libfontconfig1-dev libfreetype-dev

      - name: Check formatting
        run: cargo fmt --all -- --check

      - name: Clippy
        run: cargo clippy --all-targets -- -D warnings

  test:
    name: Test (${{ matrix.os }})
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, macos-latest]
    steps:
      - uses: actions/checkout@v4

      - uses: dtolnay/rust-toolchain@stable

      - uses: Swatinem/rust-cache@v2

      - name: Install system dependencies (Linux)
        if: runner.os == 'Linux'
        run: |
          sudo apt-get update
          sudo apt-get install -y libfontconfig1-dev libfreetype-dev

      - name: Run tests
        run: cargo test --all

  build:
    name: Build release
    runs-on: ubuntu-latest
    needs: [check, test]
    steps:
      - uses: actions/checkout@v4

      - uses: dtolnay/rust-toolchain@stable

      - uses: Swatinem/rust-cache@v2

      - name: Install system dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y libfontconfig1-dev libfreetype-dev

      - name: Build release binary
        run: cargo build --release

      - name: Print binary size
        run: ls -lh target/release/dxpdf

  # Mirrors the build matrix in `python.yml` to validate every wheel target
  # is buildable on every PR — not only at release time. Keep the matrix in
  # sync with `python.yml`; a divergence between the two means the publish
  # workflow can fail on a target that CI does not exercise.
  build-wheels:
    name: Build wheel (${{ matrix.target.label }})
    runs-on: ${{ matrix.target.runner }}
    strategy:
      fail-fast: false
      matrix:
        target:
          - label: linux-x86_64
            os: linux
            runner: ubuntu-latest
            triple: x86_64-unknown-linux-gnu
          - label: linux-aarch64
            os: linux
            runner: ubuntu-24.04-arm
            triple: aarch64-unknown-linux-gnu
          - label: macos-arm64
            os: macos
            runner: macos-latest
            triple: aarch64-apple-darwin
          - label: macos-x86_64
            os: macos
            runner: macos-15-intel
            triple: x86_64-apple-darwin
          - label: windows-x86_64
            os: windows
            runner: windows-latest
            triple: x86_64-pc-windows-msvc
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"

      - name: Build wheel (linux)
        if: matrix.target.os == 'linux'
        uses: PyO3/maturin-action@v1
        env:
          # skia-bindings only supports clang on Linux: it unconditionally
          # injects clang-only `--target=<triple>` into Skia's GN cflags.
          # AlmaLinux 8's default libstdc++ (GCC 8) lacks C++20 <compare>,
          # so point clang at gcc-toolset-13's libstdc++ via --gcc-toolchain.
          # Skia's GN build does NOT propagate CFLAGS/CXXFLAGS — we have to
          # inject the toolchain flag through SKIA_GN_ARGS (`+=` to preserve
          # skia-bindings' own extra_cflags like `-O3` and `--target=...`).
          CC: clang
          CXX: clang++
          CFLAGS: --gcc-toolchain=/opt/rh/gcc-toolset-13/root/usr
          CXXFLAGS: --gcc-toolchain=/opt/rh/gcc-toolset-13/root/usr
          BINDGEN_EXTRA_CLANG_ARGS: --gcc-toolchain=/opt/rh/gcc-toolset-13/root/usr
          # `+=` requires the variable to already exist in the GN scope.
          # `extra_cflags` is auto-set by skia-bindings (so `+=` extends it);
          # `extra_ldflags` is not, so we'd get "Undefined identifier" on `+=`.
          # The Skia build only emits static archives (no link step), so we
          # don't need extra_ldflags here — the cdylib link is rustc's job.
          SKIA_GN_ARGS: 'extra_cflags+=["--gcc-toolchain=/opt/rh/gcc-toolset-13/root/usr"]'
        with:
          args: --release --out dist --features python
          manylinux: 2_28
          before-script-linux: dnf install -y fontconfig-devel clang ninja-build gcc-toolset-13
          target: ${{ matrix.target.triple }}
          # maturin-action filters env vars by prefix (CC/CXX/CFLAGS pass; SKIA_*
          # and BINDGEN_* don't). Forward the two we set above explicitly.
          docker-options: -e SKIA_GN_ARGS -e BINDGEN_EXTRA_CLANG_ARGS

      - name: Build wheel (macos)
        if: matrix.target.os == 'macos'
        uses: PyO3/maturin-action@v1
        with:
          args: --release --out dist --features python
          target: ${{ matrix.target.triple }}

      - name: Build wheel (windows)
        if: matrix.target.os == 'windows'
        uses: PyO3/maturin-action@v1
        with:
          args: --release --out dist --features python
          target: ${{ matrix.target.triple }}

      - name: Verify FreeType is embedded (linux/macos)
        if: matrix.target.os != 'windows'
        shell: bash
        run: python3 scripts/verify_wheel.py dist/*.whl