From 434e2b9af033fad0b492b1a84853c3fe15befced Mon Sep 17 00:00:00 2001 From: Kevin Ushey Date: Thu, 23 Jul 2026 16:17:08 -0700 Subject: [PATCH] log tbb header and library provenance during install Stale or unexpected TBB libraries swept into the installed package have been a subtle source of downstream load failures, and were invisible in installation logs. Report which headers and libraries are installed and from where, and note when the tbb stub build is skipped because a tbb.dll is already present. Additionally, when the VERBOSE environment variable is set (as already used by the bundled TBB build), report how TBB libraries are resolved and loaded at package load time; this would have surfaced the lookup bug fixed in #250 immediately. --- NEWS.md | 6 ++++++ R/utils.R | 9 +++++++++ R/zzz.R | 14 ++++++++++---- src/install.libs.R | 23 +++++++++++++++++++++-- 4 files changed, 46 insertions(+), 6 deletions(-) diff --git a/NEWS.md b/NEWS.md index 661b4c50..536b3d0f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,11 @@ # RcppParallel (development version) +* RcppParallel now reports which TBB headers and libraries are installed + with the package, and from where, during package installation. In + addition, setting the `VERBOSE` environment variable to a value other + than `0` enables diagnostics describing how TBB libraries are resolved + and loaded when the package is loaded. + * On Windows, RcppParallel once again loads its compatibility stub library (`tbb.dll`) when the package is loaded. Packages linking with `-ltbb` (e.g. via StanHeaders) record a load-time dependency on `tbb.dll`, which diff --git a/R/utils.R b/R/utils.R index 9f412706..09be0897 100644 --- a/R/utils.R +++ b/R/utils.R @@ -1,4 +1,13 @@ +# opt-in diagnostics, primarily useful when debugging issues with +# TBB library resolution and loading during package load; uses the +# same VERBOSE environment variable as the TBB build in install.libs.R +verboseMessage <- function(fmt, ...) { + verbose <- Sys.getenv("VERBOSE", unset = "0") + if (!identical(verbose, "0")) + message(sprintf(fmt, ...)) +} + # like system.file(), but injects the architecture-specific subdirectory # used on Windows when set; e.g. archSystemFile("lib") resolves 'lib/x64' archSystemFile <- function(dir, name = NULL) { diff --git a/R/zzz.R b/R/zzz.R index 582b8115..768d31a6 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -24,22 +24,28 @@ loadTbbLibrary <- function(name) { # install.libs.R places the stub; tbbRoot() would prefer TBB_LIB, # which on Windows points at Rtools and holds only static libraries path <- archSystemFile("lib", paste0(name, ".dll")) - if (!file.exists(path)) + if (!file.exists(path)) { + verboseMessage("TBB library '%s' not found in package 'lib' folder; skipping", name) return(NULL) + } + verboseMessage("loading TBB library '%s'", path) return(dyn.load(path, local = FALSE, now = TRUE)) } path <- tbbLibraryPath(name) - if (is.null(path)) + if (is.null(path)) { + verboseMessage("TBB library '%s' could not be resolved; skipping", name) return(NULL) - + } + if (!file.exists(path)) { warning("TBB library ", shQuote(name), " not found.") return(NULL) } - + + verboseMessage("loading TBB library '%s'", path) dyn.load(path, local = FALSE, now = TRUE) } diff --git a/src/install.libs.R b/src/install.libs.R index 37c33c02..48ce73be 100644 --- a/src/install.libs.R +++ b/src/install.libs.R @@ -38,12 +38,14 @@ if (!nzchar(tbbLib)) { # using bundled TBB + tbbSrc <- "tbb/build/lib_release" tbbLibs <- list.files( - path = "tbb/build/lib_release", + path = tbbSrc, pattern = shlibPattern, full.names = TRUE ) + logTbbLibraries(tbbLibs, tbbSrc) for (tbbLib in tbbLibs) { system2("cp", c("-P", shQuote(tbbLib), shQuote(tbbDest))) } @@ -61,6 +63,7 @@ tbbLibs <- tbbLibs[!nzchar(Sys.readlink(tbbLibs))] # copy / link the libraries + logTbbLibraries(tbbLibs, tbbLib) useSymlinks <- Sys.getenv("TBB_USE_SYMLINKS", unset = .Platform$OS.type != "windows") if (useSymlinks) { file.symlink(tbbLibs, tbbDest) @@ -76,7 +79,9 @@ # older binaries (like rstan) can still load if (.Platform$OS.type == "windows") { tbbDll <- file.path(tbbDest, "tbb.dll") - if (!file.exists(tbbDll)) { + if (file.exists(tbbDll)) { + writeLines("** tbb.dll already exists; skipping tbb stub library") + } else { writeLines("** creating tbb stub library") status <- system("R CMD SHLIB -o tbb-compat/tbb.dll tbb-compat/tbb-compat.cpp") if (status != 0) @@ -87,8 +92,22 @@ } +# Report which TBB libraries are about to be installed, and from where. +# Stale or unexpected libraries copied here have historically been a +# subtle source of load failures in downstream packages, so make the +# provenance easy to spot in installation logs. +logTbbLibraries <- function(tbbLibs, source) { + if (length(tbbLibs)) { + fmt <- "** copying TBB libraries from '%s' [%s]" + writeLines(sprintf(fmt, source, paste(basename(tbbLibs), collapse = ", "))) + } else { + writeLines(sprintf("** no TBB libraries found in '%s'", source)) + } +} + useTbbPreamble <- function(tbbInc) { + writeLines(sprintf("** copying TBB headers from '%s'", tbbInc)) dir.create("../inst/include", recursive = TRUE, showWarnings = FALSE) for (suffix in c("oneapi", "serial", "tbb")) { tbbPath <- file.path(tbbInc, suffix)