fix(patches): replace the RcppParallel system-TBB patch with a link-order fix #145
5 changed files with 61 additions and 45 deletions
|
|
@ -7,12 +7,20 @@ exclude: |
|
|||
benchmark/|
|
||||
docker/reprex/
|
||||
)
|
||||
# The `^local/patches/.*\.patch$` excludes below keep unified diffs byte-exact:
|
||||
# a context line for a blank line is a single space, and stripping it (or
|
||||
# appending a newline) makes `git apply` reject the patch, which surfaces as
|
||||
# "patch did not apply cleanly" at build time rather than as a lint failure
|
||||
# here. The exclusions are per-hook, not global, so `validate patch registry`
|
||||
# still runs when a patch changes.
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v6.0.0
|
||||
hooks:
|
||||
- id: end-of-file-fixer
|
||||
exclude: ^local/patches/.*\.patch$
|
||||
- id: trailing-whitespace
|
||||
exclude: ^local/patches/.*\.patch$
|
||||
args:
|
||||
- --markdown-linebreak-ext=md
|
||||
- repo: https://github.com/DavidAnson/markdownlint-cli2
|
||||
|
|
@ -31,6 +39,7 @@ repos:
|
|||
rev: v3.8.0
|
||||
hooks:
|
||||
- id: editorconfig-checker
|
||||
exclude: ^local/patches/.*\.patch$
|
||||
- repo: https://github.com/adrienverge/yamllint.git
|
||||
rev: v1.38.0
|
||||
hooks:
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ For every package+tag combination:
|
|||
## Patching packages
|
||||
|
||||
Some CRAN packages fail to compile on specific platforms due to compiler- or OS-specific issues unrelated to the package itself.
|
||||
The canonical example is `RcppParallel`, whose bundled TBB sources fail on musl (Alpine) and newer compiler/OS combinations.
|
||||
The canonical example is `RcppParallel`, whose bundled TBB is linked in a way that lets a system TBB on the build host shadow it, so the published binary depends on a library the consumer does not have.
|
||||
Because such packages are often transitive dependencies of many others, a single failure cascades: all dependents fail even though nothing is wrong with the dependent itself.
|
||||
|
||||
To address this, frequently-failing packages can be "patched" before they are installed — whether as a direct build target or a transitive dependency pulled in by `pak`.
|
||||
|
|
|
|||
46
local/patches/RcppParallel/bundled-tbb-link-order.patch
Normal file
46
local/patches/RcppParallel/bundled-tbb-link-order.patch
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
diff --git a/tools/config/configure.R b/tools/config/configure.R
|
||||
index 6293fe1..2f84337 100644
|
||||
--- a/tools/config/configure.R
|
||||
+++ b/tools/config/configure.R
|
||||
@@ -186,12 +186,23 @@ define(
|
||||
)
|
||||
|
||||
# set PKG_LIBS
|
||||
+#
|
||||
+# bincraft patch: the library directories below are passed as plain '-L', not
|
||||
+# '-Wl,-L'. gcc expands its own search dirs (/usr/lib64, /usr/lib/<triplet>)
|
||||
+# into explicit '-L' options ahead of anything forwarded verbatim with '-Wl,',
|
||||
+# so with '-Wl,-L' a system libtbb.so wins over the one named here: on a build
|
||||
+# host with a distro TBB installed, '-ltbb' resolves to that library and
|
||||
+# RcppParallel.so records its SONAME (libtbb.so.12, or libtbb.so.2 for the
|
||||
+# classic Intel TBB) instead of the bundled 'libtbb.so'. The binary then loads
|
||||
+# the system TBB rather than the copy shipped in RcppParallel/lib, and fails
|
||||
+# outright on a machine that has no system TBB. gcc places a plain '-L' before
|
||||
+# its built-in dirs, so the intended library is found first.
|
||||
pkgLibs <- if (!is.na(tbbLib)) {
|
||||
|
||||
# a TBB supplied via TBB_LIB / TBB_ROOT. an rpath is meaningless on Windows,
|
||||
# where the loader has no equivalent -- see R/zzz.R for how we resolve there
|
||||
c(
|
||||
- "-Wl,-L\"$(TBB_LIB)\"",
|
||||
+ "-L\"$(TBB_LIB)\"",
|
||||
if (.Platform$OS.type != "windows")
|
||||
sprintf("-Wl,-rpath,%s", shQuote(tbbLib)),
|
||||
"-l$(TBB_NAME)",
|
||||
@@ -201,14 +212,14 @@ pkgLibs <- if (!is.na(tbbLib)) {
|
||||
} else if (R.version$os == "emscripten") {
|
||||
|
||||
c(
|
||||
- "-Wl,-Ltbb/build/lib_release",
|
||||
+ "-Ltbb/build/lib_release",
|
||||
"-l$(TBB_NAME)"
|
||||
)
|
||||
|
||||
} else {
|
||||
|
||||
c(
|
||||
- "-Wl,-Ltbb/build/lib_release",
|
||||
+ "-Ltbb/build/lib_release",
|
||||
"-l$(TBB_NAME)",
|
||||
"-l$(TBB_MALLOC_NAME)"
|
||||
)
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
diff --git a/src/Makevars.in b/src/Makevars.in
|
||||
index be8445f..7cb6c9e 100644
|
||||
--- a/src/Makevars.in
|
||||
+++ b/src/Makevars.in
|
||||
@@ -60,7 +60,13 @@ else
|
||||
endif
|
||||
|
||||
ifeq ($(UNAME), Linux)
|
||||
- USE_TBB=Linux
|
||||
+ # bincraft patch: link the system oneTBB (installed in the build-env images)
|
||||
+ # instead of building the bundled Intel TBB, which fails on musl (Alpine) and
|
||||
+ # newer toolchains (g++ 15). Leaving USE_TBB unset skips the bundled build;
|
||||
+ # -DRCPP_PARALLEL_USE_TBB=1 keeps the TBB backend so dependents (rstan, ...)
|
||||
+ # link TBB, and -ltbb/-ltbbmalloc pull the system library from default paths.
|
||||
+ PKG_CXXFLAGS += -DRCPP_PARALLEL_USE_TBB=1 -DTBB_SUPPRESS_DEPRECATED_MESSAGES=1 -DTBB_INTERFACE_NEW
|
||||
+ PKG_LIBS += -ltbb -ltbbmalloc
|
||||
endif
|
||||
|
||||
ifeq ($(UNAME), SunOS)
|
||||
|
|
@ -1,42 +1,22 @@
|
|||
[
|
||||
{
|
||||
"package": "RcppParallel",
|
||||
"versions": "*",
|
||||
"platforms": [
|
||||
"alpine",
|
||||
"ubuntu",
|
||||
"redhat"
|
||||
],
|
||||
"versions": ">=6.0.0",
|
||||
"platforms": ["*"],
|
||||
"env": {},
|
||||
"configure_args": [],
|
||||
"makevars": {},
|
||||
"patch": "RcppParallel/system-tbb.patch",
|
||||
"reason": "RcppParallel bundles an old Intel TBB whose build fails on musl and modern toolchains (g++ 8-15 + modern make); link the system oneTBB (2021+) instead, keeping the TBB backend so dependents (rstan, ...) link TBB. All build-env platforms now provide oneTBB 2021+: native on alpine/ubuntu/el10, built from source into /usr/local on el8/el9 (their stock TBB is classic 2018/2020, too old)."
|
||||
"patch": "RcppParallel/bundled-tbb-link-order.patch",
|
||||
"reason": "RcppParallel 6.x bundles oneTBB 2022 and builds it with cmake, which works on musl and g++ 8-15, so the system-TBB workaround needed for 5.x is gone. What remains broken is the link order: configure.R passes the TBB directory as '-Wl,-L', and gcc expands its own search dirs (/usr/lib64, /usr/lib/<triplet>) into '-L' options ahead of anything forwarded with '-Wl,'. On a build host with a distro TBB installed, '-ltbb' therefore resolves to the system library and RcppParallel.so records its SONAME (libtbb.so.12, or libtbb.so.2 for the classic Intel TBB on el8/el9) instead of the bundled 'libtbb.so'. The published binary then loads the system TBB rather than the copy in RcppParallel/lib and fails to dyn.load on a consumer machine without one, the same way fs did with libuv. Passing a plain '-L' puts the bundled build dir ahead of gcc's defaults; verified on alpine 3.24, el8 and ubuntu noble to produce NEEDED libtbb.so + RPATH $ORIGIN/../lib, loading with every system libtbb removed."
|
||||
},
|
||||
{
|
||||
"package": "fs",
|
||||
"versions": "*",
|
||||
"platforms": [
|
||||
"*"
|
||||
],
|
||||
"platforms": ["*"],
|
||||
"env": {},
|
||||
"configure_args": [],
|
||||
"makevars": {},
|
||||
"patch": "fs/force-vendored-libuv.patch",
|
||||
"reason": "fs 2.x configure links system libuv whenever pkg-config finds libuv-devel (installed as a build-time sysreq), producing an fs.so with NEEDED libuv.so.1. That binary fails to dyn.load on consumer machines lacking runtime libuv, because install.packages/renv do not install SystemRequirements (only pak does, and only in the build container). The patch short-circuits configure to copy src/Makevars.vendor and build the bundled static libuv (needs cmake) so the binary is self-contained on every platform. An env/pkg-config override was tried first but the rebuilt binary still linked libuv.so.1, so a source patch is used instead."
|
||||
},
|
||||
{
|
||||
"package": "rstan",
|
||||
"versions": "*",
|
||||
"platforms": [
|
||||
"*"
|
||||
],
|
||||
"env": {},
|
||||
"configure_args": [],
|
||||
"makevars": {
|
||||
"CPPFLAGS": "-DTBB_INTERFACE_NEW -I/usr/local/include"
|
||||
},
|
||||
"patch": null,
|
||||
"reason": "StanHeaders' init_threadpool_tbb.hpp unconditionally includes the legacy <tbb/tbb_stddef.h> (removed in oneTBB 2021+) for version detection, breaking compilation of Module.cpp against the bundled oneTBB. Pre-defining TBB_INTERFACE_NEW skips that include and selects the modern tbb/global_control.h + tbb/task_arena.h path that the bundled TBB provides (-I/usr/local/include preserves the default CPPFLAGS the override replaces)"
|
||||
}
|
||||
]
|
||||
|
|
|
|||
Loading…
Reference in a new issue