fix(patches): force RcppParallel to use its bundled oneTBB #146

Merged
pat-s merged 1 commit from fix/rcppparallel-force-bundled-tbb into main 2026-07-31 09:48:42 +00:00
Owner

Why

RcppParallel binaries built on ubuntu 22.04 still record NEEDED libtbb.so.12 and cannot dyn.load without the distro TBB, although #145 landed the link-order patch and build-env-images dropped TBB_INC/TBB_LIB the same morning.

The link-order fix does not survive a build image that exports those variables, and the published images still do: .crow/images.yaml in build-env-images triggers on cron/manual only, so every image in the registry is still the 2026-07-21 build.
With TBB_LIB set, configure.R never reaches the bundled-oneTBB branch at all, install.libs.R fills RcppParallel/lib with absolute symlinks into the image's library dir, and the plain -L from #145 just points at the system TBB instead of the bundled one.
Nothing on the pipeline side can undo this: R reads ~/.Renviron after the process environment, so neither a Crow environment: block nor the registry env field wins.

# the image, not the Containerfile
docker run --rm reg.devxy.io/rpkgs/build-env-ubuntu:jammy sh -lc 'grep TBB ~/.Renviron'
TBB_INC=/usr/include/oneapi
TBB_LIB=/usr/lib/x86_64-linux-gnu

Rather than couple correctness to image freshness for a third round-trip, the patch now forces the bundled TBB itself.

Changes

  • local/patches/RcppParallel/bundled-tbb-link-order.patch -> local/patches/RcppParallel/force-bundled-tbb.patch.
    Keeps the -Wl,-L -> -L link-order hunk (the bundled branch has the same problem when a distro libtbb is installed) and adds an opt-out, BINCRAFT_ALLOW_SYSTEM_TBB=TRUE, for the ambient TBB_ROOT/TBB_LIB/TBB_INC.
  • All four read sites have to move together; patching only configure.R builds the bundled TBB and then segfaults R on the post-install load test:
    • tools/config/configure.R: branch selection.
    • src/install.libs.R: R CMD INSTALL runs it outside the tbb rule in src/Makevars that passes the configured values, so at install time it still sees the image environment.
    • R/tbb.R tbbLibraryPath(): run time. .onLoad() would dyn.load the system TBB into the global scope next to the bundled one that RcppParallel.so needs - two copies of the same symbols, hence the segfault.
    • R/tbb.R tbbCxxFlags() / tbbLdFlags(): otherwise dependents such as rstan get the system TBB handed back to them.
  • local/patches/registry.json: new patch path and a reason describing both failure modes.

Verification

Built through bincraft:::prepare_patched_repo() on the current, unfixed images (all three still export TBB_INC/TBB_LIB), with bincraft v5.0.1, i.e. what CI deploys:

image NEEDED rpath RcppParallel/lib load, all system libtbb* moved away
build-env-ubuntu:jammy libtbb.so $ORIGIN/../lib real libtbb.so.2, 5.0 MB OK, 12 threads
build-env-redhat:9 libtbb.so $ORIGIN/../lib real libtbb.so.2, 5.1 MB OK, 12 threads
build-env-alpine:3.24 libtbb.so $ORIGIN/../lib real libtbb.so.2, 4.7 MB OK, 12 threads

For contrast, the same jammy build without this change:

NEEDED   libtbb.so.12
RUNPATH  /usr/lib/x86_64-linux-gnu:$ORIGIN/../lib
lib/     libtbb.so.12.5 -> /usr/lib/x86_64-linux-gnu/libtbb.so.12.5   (dangling off the image)
load     libtbb.so.12: cannot open shared object file: No such file or directory

With TBB_LIB still exported, RcppParallel::tbbLibraryPath() resolves to the package's own lib, and CxxFlags() emits the package's own include plus -DTBB_INTERFACE_NEW - not /usr/include/oneapi.

Behaviour change

Published RcppParallel binaries carry their own oneTBB on every platform, whichever image version CI pulls. The patch content changed, so the patched-binary cache key changes with it and no stale entry is reused.

The build-env-images fix is still worth rolling out (those images also carry the broken el8 uvr and uvr 0.4.1), but RcppParallel no longer waits on it.

Follow-up, not in this PR

The binaries already in B2 are the broken ones; they need a rebuild, and a Bunny /purge does not evict Perma-Cache.

## Why `RcppParallel` binaries built on ubuntu 22.04 still record `NEEDED libtbb.so.12` and cannot `dyn.load` without the distro TBB, although #145 landed the link-order patch and build-env-images dropped `TBB_INC`/`TBB_LIB` the same morning. The link-order fix does not survive a build image that exports those variables, and the published images still do: `.crow/images.yaml` in build-env-images triggers on `cron`/`manual` only, so every image in the registry is still the 2026-07-21 build. With `TBB_LIB` set, `configure.R` never reaches the bundled-oneTBB branch at all, `install.libs.R` fills `RcppParallel/lib` with absolute symlinks into the image's library dir, and the plain `-L` from #145 just points at the system TBB instead of the bundled one. Nothing on the pipeline side can undo this: R reads `~/.Renviron` **after** the process environment, so neither a Crow `environment:` block nor the registry `env` field wins. ``` # the image, not the Containerfile docker run --rm reg.devxy.io/rpkgs/build-env-ubuntu:jammy sh -lc 'grep TBB ~/.Renviron' TBB_INC=/usr/include/oneapi TBB_LIB=/usr/lib/x86_64-linux-gnu ``` Rather than couple correctness to image freshness for a third round-trip, the patch now forces the bundled TBB itself. ## Changes - `local/patches/RcppParallel/bundled-tbb-link-order.patch` -> `local/patches/RcppParallel/force-bundled-tbb.patch`. Keeps the `-Wl,-L` -> `-L` link-order hunk (the bundled branch has the same problem when a distro libtbb is installed) and adds an opt-out, `BINCRAFT_ALLOW_SYSTEM_TBB=TRUE`, for the ambient `TBB_ROOT`/`TBB_LIB`/`TBB_INC`. - All four read sites have to move together; patching only `configure.R` builds the bundled TBB and then **segfaults R on the post-install load test**: - `tools/config/configure.R`: branch selection. - `src/install.libs.R`: `R CMD INSTALL` runs it outside the `tbb` rule in `src/Makevars` that passes the configured values, so at install time it still sees the image environment. - `R/tbb.R` `tbbLibraryPath()`: run time. `.onLoad()` would `dyn.load` the system TBB into the global scope next to the bundled one that `RcppParallel.so` needs - two copies of the same symbols, hence the segfault. - `R/tbb.R` `tbbCxxFlags()` / `tbbLdFlags()`: otherwise dependents such as `rstan` get the system TBB handed back to them. - `local/patches/registry.json`: new patch path and a `reason` describing both failure modes. ## Verification Built through `bincraft:::prepare_patched_repo()` on the **current, unfixed** images (all three still export `TBB_INC`/`TBB_LIB`), with bincraft v5.0.1, i.e. what CI deploys: | image | `NEEDED` | rpath | `RcppParallel/lib` | load, all system `libtbb*` moved away | | --- | --- | --- | --- | --- | | `build-env-ubuntu:jammy` | `libtbb.so` | `$ORIGIN/../lib` | real `libtbb.so.2`, 5.0 MB | OK, 12 threads | | `build-env-redhat:9` | `libtbb.so` | `$ORIGIN/../lib` | real `libtbb.so.2`, 5.1 MB | OK, 12 threads | | `build-env-alpine:3.24` | `libtbb.so` | `$ORIGIN/../lib` | real `libtbb.so.2`, 4.7 MB | OK, 12 threads | For contrast, the same jammy build without this change: ``` NEEDED libtbb.so.12 RUNPATH /usr/lib/x86_64-linux-gnu:$ORIGIN/../lib lib/ libtbb.so.12.5 -> /usr/lib/x86_64-linux-gnu/libtbb.so.12.5 (dangling off the image) load libtbb.so.12: cannot open shared object file: No such file or directory ``` With `TBB_LIB` still exported, `RcppParallel::tbbLibraryPath()` resolves to the package's own `lib`, and `CxxFlags()` emits the package's own `include` plus `-DTBB_INTERFACE_NEW` - not `/usr/include/oneapi`. ## Behaviour change Published `RcppParallel` binaries carry their own oneTBB on every platform, whichever image version CI pulls. The patch content changed, so the patched-binary cache key changes with it and no stale entry is reused. The build-env-images fix is still worth rolling out (those images also carry the broken el8 `uvr` and uvr 0.4.1), but RcppParallel no longer waits on it. ## Follow-up, not in this PR The binaries already in B2 are the broken ones; they need a rebuild, and a Bunny `/purge` does not evict Perma-Cache.
The link-order fix alone does not survive a build image that exports
TBB_INC/TBB_LIB. RcppParallel's configure.R then never reaches the
bundled branch at all: it links the image's TBB, install.libs.R fills
RcppParallel/lib with absolute symlinks into the image's library dir,
and the published binary records NEEDED libtbb.so.12 (libtbb.so.2 for
the classic Intel TBB on el8/el9), so it cannot dyn.load on a consumer
machine without that exact library. build-env-images dropped those
variables, but its images are rebuilt only by cron or a manual run, and
R reads ~/.Renviron after the process environment, so nothing on the
pipeline side can override them in the meantime.

Patch the package to ignore an ambient TBB_ROOT/TBB_LIB/TBB_INC instead
of relying on the image being clean, in all four places that read them:
configure.R (branch selection), install.libs.R (which R CMD INSTALL runs
outside the src/Makevars rule that passes the configured values), and
R/tbb.R at run time -- .onLoad() would otherwise dyn.load a second,
unrelated TBB next to the bundled one, which segfaults R on load, and
RcppParallelLibs()/CxxFlags() would hand the system TBB to dependents
such as rstan. BINCRAFT_ALLOW_SYSTEM_TBB=TRUE restores the upstream
behaviour. Keep the link-order hunk: the bundled branch passes its build
dir as '-Wl,-L', which gcc still places after its own search dirs.

Verified on the current (pre-fix) build-env images, which still export
TBB_INC/TBB_LIB -- ubuntu jammy, redhat 9 and alpine 3.24: NEEDED
libtbb.so, rpath $ORIGIN/../lib, real libtbb.so.2 in RcppParallel/lib,
and the package loads with every system libtbb moved away. Without the
patch on jammy the same build yields NEEDED libtbb.so.12 and fails to
load; with the configure-only patch it builds the bundled TBB but
segfaults on the post-install load test.
pat-s merged commit fe2289af56 into main 2026-07-31 09:48:42 +00:00
pat-s deleted branch fix/rcppparallel-force-bundled-tbb 2026-07-31 09:48:42 +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/build-cran-binaries!146
No description provided.