Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# RcppParallel (development version)

* On Linux, the bundled TBB libraries are once again installed with versioned
names (e.g. `libtbb.so.2`) plus an unversioned `libtbb.so` symlink, matching
the layout shipped by RcppParallel 5.1.11 and earlier. The oneTBB cmake build
produces only unversioned libraries on Linux, so binaries compiled against
those releases (which recorded a load-time dependency on `libtbb.so.2`) would
otherwise fail to load after an upgrade with "libtbb.so.2: cannot open shared
object file".

* Fixed linking of downstream packages using the TBB scalable allocator
on Windows, e.g. via RcppArmadillo's `ARMA_USE_TBB_ALLOC`. RcppParallel
now links the whole Rtools `tbbmalloc` archive into `RcppParallel.dll`
Expand Down
91 changes: 91 additions & 0 deletions src/install.libs.R
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@
system2("cp", c("-P", shQuote(tbbLib), shQuote(tbbDest)))
}

# restore the versioned library layout shipped by RcppParallel 5.1.11
# and earlier (a real 'libtbb.so.2' plus a 'libtbb.so' symlink)
if (Sys.info()[["sysname"]] == "Linux")
versionBundledTbbLibraries(tbbDest)

} else {

# using system tbb
Expand Down Expand Up @@ -145,6 +150,92 @@ buildTbbStub <- function(tbbDest) {

}

# Give the bundled TBB libraries the versioned '.so.<N>' names, plus an
# unversioned 'libtbb.so' compatibility symlink, that RcppParallel shipped on
# Linux through 5.1.11. That layout came from Intel TBB's make-based build,
# which set the library SONAME from TBB_COMPATIBLE_INTERFACE_VERSION (2) and
# emitted 'libtbb.so' as a linker script pointing at 'libtbb.so.2'. The
# oneTBB cmake build only versions its output on Windows, so on Linux it
# produces unversioned libraries (e.g. 'libtbb.so' with SONAME 'libtbb.so')
# instead. Binaries compiled against RcppParallel <= 5.1.11 recorded a
# load-time dependency on 'libtbb.so.2'; without this, they fail to load after
# an upgrade with "libtbb.so.2: cannot open shared object file".
versionBundledTbbLibraries <- function(tbbDest) {

# downstream binaries look for exactly '.so.2', matching the SONAME suffix
# the old TBB build derived from TBB_COMPATIBLE_INTERFACE_VERSION
suffix <- "2"

libs <- list.files(tbbDest, pattern = "^libtbb.*\\.so$", full.names = TRUE)
for (lib in libs)
versionBundledTbbLibrary(lib, paste0(lib, ".", suffix))

}

# Version a single bundled TBB library. Failing to produce the versioned
# layout is an error: a partial or silently-skipped layout would only
# resurface later as load failures in downstream binaries, so fail the
# install loudly instead.
versionBundledTbbLibrary <- function(lib, versioned) {

# leave symlinks (i.e. an already-versioned layout) untouched; only real,
# unversioned libraries need renaming
if (nzchar(Sys.readlink(lib)))
return(invisible(FALSE))

# only version actual ELF libraries; this leaves linker scripts alone
# (in old-style layouts, 'libtbb.so' is an INPUT() script and the real
# library already sits at 'libtbb.so.2'), while still replacing a stale
# 'libtbb.so.2' left behind by a previous installation
if (!isElfFile(lib))
return(invisible(FALSE))

fmt <- "** versioning tbb library '%s' -> '%s'"
msg <- sprintf(fmt, basename(lib), basename(versioned))
writeLines(msg)

# 'libtbb.so' -> 'libtbb.so.2'
if (!isTRUE(file.rename(lib, versioned))) {
fmt <- "couldn't rename '%s' to '%s'"
stop(sprintf(fmt, lib, versioned))
}

# re-create 'libtbb.so' as a relative symlink pointing back at the
# versioned library
linked <- tryCatch(
file.symlink(basename(versioned), lib),
warning = function(w) FALSE
)
if (isTRUE(linked))
return(invisible(TRUE))

# if the symlink couldn't be created (e.g. a filesystem without symlink
# support), fall back to a plain copy so that 'libtbb.so' still exists.
# the library has already been renamed at this point, so a failed copy
# would leave no 'libtbb.so' at all; fail loudly rather than complete a
# broken install
writeLines("** couldn't create symlink; copying instead")
copied <- tryCatch(
file.copy(versioned, lib, overwrite = TRUE),
warning = function(w) FALSE
)
if (!isTRUE(copied)) {
fmt <- "couldn't copy '%s' to '%s'"
stop(sprintf(fmt, versioned, lib))
}

invisible(TRUE)

}

isElfFile <- function(path) {
header <- tryCatch(
readBin(path, "raw", n = 4L),
condition = function(cnd) raw()
)
identical(header, charToRaw("\x7fELF"))
}

# 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
Expand Down
Loading