diff --git a/R/aaa.R b/R/aaa.R index 568a2aa..bfdab4c 100644 --- a/R/aaa.R +++ b/R/aaa.R @@ -5,4 +5,21 @@ TBB_LIB <- "" TBB_INC <- "" TBB_NAME <- "tbb" -TBB_MALLOC_NAME <- "tbbmalloc" \ No newline at end of file +TBB_MALLOC_NAME <- "tbbmalloc" + +# bincraft patch: our build images (and plenty of user environments) export +# TBB_ROOT / TBB_LIB / TBB_INC. A binary we publish always carries its own +# oneTBB in RcppParallel/lib -- see the companion changes in +# tools/config/configure.R and src/install.libs.R -- so honouring those +# variables at run time is actively harmful: .onLoad() would dyn.load() a +# second, unrelated TBB into the process next to the bundled one (two copies +# of the same symbols in the global scope, which segfaults R on load), and +# RcppParallelLibs() / CxxFlags() would hand that system TBB to dependents +# such as rstan, putting NEEDED libtbb.so.12 back into their binaries. Read +# the variables only when explicitly opted back in. +bincraftGetenv <- function(name, unset = "") { + if (Sys.getenv("BINCRAFT_ALLOW_SYSTEM_TBB", unset = "FALSE") == "TRUE") + Sys.getenv(name, unset = unset) + else + unset +} \ No newline at end of file diff --git a/R/tbb.R b/R/tbb.R index 6f6a745..e407986 100644 --- a/R/tbb.R +++ b/R/tbb.R @@ -17,7 +17,7 @@ tbbLibraryPath <- function(name = NULL) { sysname <- Sys.info()[["sysname"]] # find root for TBB install - tbbRoot <- Sys.getenv("TBB_LIB", unset = tbbRoot()) + tbbRoot <- bincraftGetenv("TBB_LIB", unset = tbbRoot()) if (is.null(name)) return(tbbRoot) @@ -58,3 +58,3 @@ tbbCxxFlags <- function() { # if TBB_INC is set, apply those library paths - tbbInc <- Sys.getenv("TBB_INC", unset = TBB_INC) + tbbInc <- bincraftGetenv("TBB_INC", unset = TBB_INC) if (!file.exists(tbbInc)) { @@ -117,7 +117,7 @@ tbbLdFlags <- function() { } # shortcut if TBB_LIB defined - tbbLib <- Sys.getenv("TBB_LINK_LIB", Sys.getenv("TBB_LIB", unset = TBB_LIB)) + tbbLib <- bincraftGetenv("TBB_LINK_LIB", bincraftGetenv("TBB_LIB", unset = TBB_LIB)) if (nzchar(tbbLib)) { if (R.version$os == "emscripten") { fmt <- "-L%1$s -l%2$s" diff --git a/src/install.libs.R b/src/install.libs.R index 3b3cfda..c0e6f3e 100644 --- a/src/install.libs.R +++ b/src/install.libs.R @@ -477,6 +477,18 @@ prependFlags <- function(prependFlags, toFlags) { tbbLib <- Sys.getenv("TBB_LIB") tbbInc <- Sys.getenv("TBB_INC") +# bincraft patch: the companion change in tools/config/configure.R stops an +# ambient TBB_LIB / TBB_INC from selecting a system TBB, but this script is +# also run directly by `R CMD INSTALL` (not only through the `tbb` rule in +# src/Makevars, which passes the configured values), so at install time it +# still sees the image's environment and would symlink the system libraries +# into RcppParallel/lib. Drop them here for the same reason, under the same +# opt-out. +if (Sys.getenv("BINCRAFT_ALLOW_SYSTEM_TBB", unset = "FALSE") != "TRUE") { + tbbLib <- "" + tbbInc <- "" +} + args <- commandArgs(trailingOnly = TRUE) if (identical(args, "build")) { if (nzchar(tbbLib) && nzchar(tbbInc)) { diff --git a/tools/config/configure.R b/tools/config/configure.R index 6293fe1..eae4aaa 100644 --- a/tools/config/configure.R +++ b/tools/config/configure.R @@ -40,6 +40,24 @@ tbbRoot <- Sys.getenv("TBB_ROOT", unset = NA) tbbLib <- Sys.getenv("TBB_LIB", unset = NA) tbbInc <- Sys.getenv("TBB_INC", unset = NA) +# bincraft patch: ignore an ambient TBB_ROOT / TBB_LIB / TBB_INC. Several of +# our build images export these (a leftover from RcppParallel 5.x, whose +# bundled Intel TBB would not build on musl or with modern g++), and any of +# them switches the branches below to a system TBB. The published binary then +# records NEEDED libtbb.so.12 (or libtbb.so.2 for the classic Intel TBB) and +# gets a RcppParallel/lib full of absolute symlinks into the image's library +# dir, so it cannot dyn.load on a consumer machine without that exact TBB. +# 6.x bundles oneTBB 2022 and builds it with cmake on every platform we ship, +# so the bundled copy is always the right choice here; forcing it in the +# package rather than relying on the image environment keeps the binary +# correct whichever image version CI happens to pull. Set +# BINCRAFT_ALLOW_SYSTEM_TBB=TRUE to restore the upstream behaviour. +if (Sys.getenv("BINCRAFT_ALLOW_SYSTEM_TBB", unset = "FALSE") != "TRUE") { + tbbRoot <- NA + tbbLib <- NA + tbbInc <- NA +} + tbbName <- Sys.getenv("TBB_NAME", unset = "tbb") tbbMallocName <- Sys.getenv("TBB_MALLOC_NAME", unset = "tbbmalloc") @@ -186,12 +204,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/) +# 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 +230,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)" )