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)