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.
1.6 KiB
1.6 KiB
CLAUDE.md
CI pipelines (Crow, in .crow/) that build R binaries and upload them to Backblaze B2.
Conventions
- PRs: the remote is Forgejo on
git.devxy.io; usefj -H git.devxy.io(notgh). - Storage: Backblaze B2 bucket
devxy-r-builds(endpoint configured in.crow/build.yaml).
Gotchas
- B2 requires authentication for the list-bucket API. Anonymous GET only works for individual public-read objects — an empty bucket listing usually means missing credentials, not an empty bucket. This silently broke rebuild dedup once.
- R's configure silently disables graphics devices when headers are missing.
It never fails the build, so a missing
-devpackage yields a working R whosecapabilities()reportscairo,png,jpegandtiffasFALSE. Installing the runtime libraries on the target system afterwards cannot bring compiled-out devices back; the binary has to be rebuilt.builder/build.shtherefore assertsREQUIRED_CAPABILITIES(set per Dockerfile) aftermake install. - The
--with-x=noon the Alpine images does not disable cairo. R's bitmap and pangocairo checks run independently ofR_X11, sopng()andsvg()work headless via cairo. - Artifact filenames carry only the R version, not the builder image.
When a builder change alters the resulting binary, dedup would keep serving the stale artifact forever; set
FORCE_REBUILDin.crow/build.yamlto rebuild and overwrite in place. - When a pipeline fails, fetch the Crow logs yourself instead of asking the user to paste them, and monitor reruns in the background until green.