fix(alpine): build R with cairo, png, jpeg and tiff graphics devices #9

Merged
pat-s merged 1 commit from fix/alpine-graphics-capabilities into main 2026-09-18 07:04:23 +00:00
Owner

Motivation

R on the Alpine images was built without graphics support: capabilities() reports cairo, png, jpeg and tiff as FALSE, while Ubuntu reports all four TRUE.
The images install R-dev but never the graphics headers, and R's configure treats those as optional and does not fail when they are absent, so the build succeeds and ships an R that cannot draw.

Reproduced in a clean alpine:3.22 container with the old package set:

Additional capabilities:  PNG, NLS, ICU
Capabilities skipped:     JPEG, TIFF, cairo

One correction to the original diagnosis: --with-x=no was not the cause, and libpng was in fact found.
R's bitmap and pangocairo checks run independently of R_X11 (configure.ac:2604 gates on want_cairo, not use_X11).
capabilities("png") needs a device backend, and with X11 off and cairo absent there was none, which is why all four read FALSE despite configure listing PNG.
So the fix is purely the missing -dev packages.
X11 stays off, which is correct for headless images, and cairo covers png() / jpeg() / tiff() / svg().

Changes

  • builder/Dockerfile.alpine-{320,321,322,323,324} — install pkgconf cairo-dev pango-dev fontconfig-dev freetype-dev libpng-dev jpeg-dev tiff-dev zlib-dev; pass --with-cairo --with-libpng --with-jpeglib --with-libtiff explicitly so the intent sits next to --with-x=no; set REQUIRED_CAPABILITIES.
  • builder/build.sh — add verify_capabilities() between compile_r and package_r. A build that loses a graphics device now fails instead of being packaged and uploaded. Opt-in via REQUIRED_CAPABILITIES, so every non-Alpine platform is untouched.
  • .crow/build.yaml — add a FORCE_REBUILD escape hatch to the dedup step. Artifact filenames carry only the R version, so the HEAD probe would otherwise keep skipping every Alpine version and serving the stale broken binaries.
  • CLAUDE.md — record the three gotchas.

Verification

Compiled R 4.5.1 in the patched alpine-322 image, through the real build.sh:

       jpeg         png        tiff       tcltk         X11        aqua
       TRUE        TRUE        TRUE        TRUE       FALSE       FALSE
        NLS       Rprof     profmem       cairo         ICU long.double
       TRUE        TRUE        TRUE        TRUE        TRUE        TRUE
All required capabilities are present.

The devices actually render, not just report TRUE (default bitmapType: cairo):

png   -> t.png (2154 bytes)
jpeg  -> t.jpeg (4489 bytes)
tiff  -> t.tiff (120160 bytes)
svg   -> t.svg (9381 bytes)

The guard was exercised in both directions against that real build: it passes on the four graphics capabilities, and returns non-zero naming the missing entry when additionally asked for X11.
crow lint .crow/ passes and bash -n builder/build.sh is clean.

Behaviour change

Alpine R binaries gain the cairo, png, jpeg and tiff devices, and link against libcairo, libpangocairo, libpng, libjpeg and libtiff.
The .apk metadata already declared those runtime dependencies, so consumer images need no change.
Any Alpine build that loses a graphics device now fails the pipeline rather than uploading silently.

Needs a follow-up after merge: the first run must have FORCE_REBUILD set, otherwise dedup skips every existing Alpine version and the broken artifacts stay in the bucket.

## Motivation R on the Alpine images was built without graphics support: `capabilities()` reports `cairo`, `png`, `jpeg` and `tiff` as `FALSE`, while Ubuntu reports all four `TRUE`. The images install `R-dev` but never the graphics headers, and R's `configure` treats those as optional and does not fail when they are absent, so the build succeeds and ships an R that cannot draw. Reproduced in a clean `alpine:3.22` container with the old package set: ``` Additional capabilities: PNG, NLS, ICU Capabilities skipped: JPEG, TIFF, cairo ``` One correction to the original diagnosis: `--with-x=no` was not the cause, and libpng was in fact found. R's bitmap and `pangocairo` checks run independently of `R_X11` (`configure.ac:2604` gates on `want_cairo`, not `use_X11`). `capabilities("png")` needs a device *backend*, and with X11 off and cairo absent there was none, which is why all four read `FALSE` despite configure listing PNG. So the fix is purely the missing `-dev` packages. X11 stays off, which is correct for headless images, and cairo covers `png()` / `jpeg()` / `tiff()` / `svg()`. ## Changes - `builder/Dockerfile.alpine-{320,321,322,323,324}` — install `pkgconf cairo-dev pango-dev fontconfig-dev freetype-dev libpng-dev jpeg-dev tiff-dev zlib-dev`; pass `--with-cairo --with-libpng --with-jpeglib --with-libtiff` explicitly so the intent sits next to `--with-x=no`; set `REQUIRED_CAPABILITIES`. - `builder/build.sh` — add `verify_capabilities()` between `compile_r` and `package_r`. A build that loses a graphics device now fails instead of being packaged and uploaded. Opt-in via `REQUIRED_CAPABILITIES`, so every non-Alpine platform is untouched. - `.crow/build.yaml` — add a `FORCE_REBUILD` escape hatch to the dedup step. Artifact filenames carry only the R version, so the HEAD probe would otherwise keep skipping every Alpine version and serving the stale broken binaries. - `CLAUDE.md` — record the three gotchas. ## Verification Compiled R 4.5.1 in the patched `alpine-322` image, through the real `build.sh`: ``` jpeg png tiff tcltk X11 aqua TRUE TRUE TRUE TRUE FALSE FALSE NLS Rprof profmem cairo ICU long.double TRUE TRUE TRUE TRUE TRUE TRUE All required capabilities are present. ``` The devices actually render, not just report `TRUE` (`default bitmapType: cairo`): ``` png -> t.png (2154 bytes) jpeg -> t.jpeg (4489 bytes) tiff -> t.tiff (120160 bytes) svg -> t.svg (9381 bytes) ``` The guard was exercised in both directions against that real build: it passes on the four graphics capabilities, and returns non-zero naming the missing entry when additionally asked for `X11`. `crow lint .crow/` passes and `bash -n builder/build.sh` is clean. ## Behaviour change Alpine R binaries gain the cairo, png, jpeg and tiff devices, and link against `libcairo`, `libpangocairo`, `libpng`, `libjpeg` and `libtiff`. The `.apk` metadata already declared those runtime dependencies, so consumer images need no change. Any Alpine build that loses a graphics device now fails the pipeline rather than uploading silently. **Needs a follow-up after merge:** the first run must have `FORCE_REBUILD` set, otherwise dedup skips every existing Alpine version and the broken artifacts stay in the bucket.
The Alpine builder images install R-dev but never the graphics headers.
R's configure treats those as optional and does not fail when they are
absent, so the build succeeds and ships an R whose capabilities() reports
cairo, png, jpeg and tiff as FALSE. Installing the runtime libraries on
the target system afterwards cannot bring compiled-out devices back.

Note that --with-x=no was not the cause. R's bitmap and pangocairo checks
run independently of R_X11, and libpng was in fact found. capabilities("png")
needs a device backend, and with X11 off and cairo absent there was none,
which is why all four read FALSE. X11 stays off: these are headless images
and cairo covers png()/jpeg()/tiff()/svg().

- Install pkgconf, cairo-dev, pango-dev, fontconfig-dev, freetype-dev,
  libpng-dev, jpeg-dev, tiff-dev and zlib-dev in every Alpine builder image.
- Pass --with-cairo, --with-libpng, --with-jpeglib and --with-libtiff
  explicitly so the intent is visible next to --with-x=no.
- Assert REQUIRED_CAPABILITIES after make install, so a build that loses a
  device fails instead of being packaged and uploaded. Opt-in per Dockerfile,
  leaving the other platforms untouched.
- Add a FORCE_REBUILD escape hatch to the dedup step. Artifact filenames
  carry only the R version, so the HEAD probe would otherwise keep skipping
  every Alpine version and serving the stale broken binaries.
- Record the three gotchas in CLAUDE.md.

Verified by compiling R 4.5.1 in the patched alpine-322 image: jpeg, png,
tiff and cairo are TRUE, default bitmapType is cairo, and all four devices
render. The guard was exercised in both directions against that build.
pat-s merged commit 1362e0bd3a into main 2026-09-18 07:04:23 +00:00
pat-s deleted branch fix/alpine-graphics-capabilities 2026-09-18 07:04:23 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
devxy/r-builds!9
No description provided.