Skip to content

Commit 77684de

Browse files
authored
ship versioned tbb libraries on linux again (#260)
* ship versioned tbb libraries on linux again The oneTBB cmake build only versions its output on Windows, so on Linux RcppParallel 6.0.x installed unversioned libraries (e.g. 'libtbb.so' with SONAME 'libtbb.so'). RcppParallel 5.1.11 and earlier shipped a real 'libtbb.so.2' plus a 'libtbb.so' redirect, inherited from Intel TBB's make-based build (which set the SONAME from TBB_COMPATIBLE_INTERFACE_VERSION). Binaries compiled against those releases recorded a load-time dependency on 'libtbb.so.2', and so fail to load after an upgrade with "libtbb.so.2: cannot open shared object file". Restore the versioned layout for the bundled TBB on Linux by renaming 'libtbb*.so' to 'libtbb*.so.2' and re-creating 'libtbb*.so' as a symlink. A symlink (rather than a linker script) is used so the name resolves at runtime as well as at link time. * split versioning log message onto separate lines * fall back to copying when the libtbb.so symlink can't be created * fail loudly when tbb libraries cannot be versioned
1 parent 8f0f0d9 commit 77684de

2 files changed

Lines changed: 99 additions & 0 deletions

File tree

NEWS.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# RcppParallel (development version)
22

3+
* On Linux, the bundled TBB libraries are once again installed with versioned
4+
names (e.g. `libtbb.so.2`) plus an unversioned `libtbb.so` symlink, matching
5+
the layout shipped by RcppParallel 5.1.11 and earlier. The oneTBB cmake build
6+
produces only unversioned libraries on Linux, so binaries compiled against
7+
those releases (which recorded a load-time dependency on `libtbb.so.2`) would
8+
otherwise fail to load after an upgrade with "libtbb.so.2: cannot open shared
9+
object file".
10+
311
* Fixed linking of downstream packages using the TBB scalable allocator
412
on Windows, e.g. via RcppArmadillo's `ARMA_USE_TBB_ALLOC`. RcppParallel
513
now links the whole Rtools `tbbmalloc` archive into `RcppParallel.dll`

src/install.libs.R

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@
5050
system2("cp", c("-P", shQuote(tbbLib), shQuote(tbbDest)))
5151
}
5252

53+
# restore the versioned library layout shipped by RcppParallel 5.1.11
54+
# and earlier (a real 'libtbb.so.2' plus a 'libtbb.so' symlink)
55+
if (Sys.info()[["sysname"]] == "Linux")
56+
versionBundledTbbLibraries(tbbDest)
57+
5358
} else {
5459

5560
# using system tbb
@@ -145,6 +150,92 @@ buildTbbStub <- function(tbbDest) {
145150

146151
}
147152

153+
# Give the bundled TBB libraries the versioned '.so.<N>' names, plus an
154+
# unversioned 'libtbb.so' compatibility symlink, that RcppParallel shipped on
155+
# Linux through 5.1.11. That layout came from Intel TBB's make-based build,
156+
# which set the library SONAME from TBB_COMPATIBLE_INTERFACE_VERSION (2) and
157+
# emitted 'libtbb.so' as a linker script pointing at 'libtbb.so.2'. The
158+
# oneTBB cmake build only versions its output on Windows, so on Linux it
159+
# produces unversioned libraries (e.g. 'libtbb.so' with SONAME 'libtbb.so')
160+
# instead. Binaries compiled against RcppParallel <= 5.1.11 recorded a
161+
# load-time dependency on 'libtbb.so.2'; without this, they fail to load after
162+
# an upgrade with "libtbb.so.2: cannot open shared object file".
163+
versionBundledTbbLibraries <- function(tbbDest) {
164+
165+
# downstream binaries look for exactly '.so.2', matching the SONAME suffix
166+
# the old TBB build derived from TBB_COMPATIBLE_INTERFACE_VERSION
167+
suffix <- "2"
168+
169+
libs <- list.files(tbbDest, pattern = "^libtbb.*\\.so$", full.names = TRUE)
170+
for (lib in libs)
171+
versionBundledTbbLibrary(lib, paste0(lib, ".", suffix))
172+
173+
}
174+
175+
# Version a single bundled TBB library. Failing to produce the versioned
176+
# layout is an error: a partial or silently-skipped layout would only
177+
# resurface later as load failures in downstream binaries, so fail the
178+
# install loudly instead.
179+
versionBundledTbbLibrary <- function(lib, versioned) {
180+
181+
# leave symlinks (i.e. an already-versioned layout) untouched; only real,
182+
# unversioned libraries need renaming
183+
if (nzchar(Sys.readlink(lib)))
184+
return(invisible(FALSE))
185+
186+
# only version actual ELF libraries; this leaves linker scripts alone
187+
# (in old-style layouts, 'libtbb.so' is an INPUT() script and the real
188+
# library already sits at 'libtbb.so.2'), while still replacing a stale
189+
# 'libtbb.so.2' left behind by a previous installation
190+
if (!isElfFile(lib))
191+
return(invisible(FALSE))
192+
193+
fmt <- "** versioning tbb library '%s' -> '%s'"
194+
msg <- sprintf(fmt, basename(lib), basename(versioned))
195+
writeLines(msg)
196+
197+
# 'libtbb.so' -> 'libtbb.so.2'
198+
if (!isTRUE(file.rename(lib, versioned))) {
199+
fmt <- "couldn't rename '%s' to '%s'"
200+
stop(sprintf(fmt, lib, versioned))
201+
}
202+
203+
# re-create 'libtbb.so' as a relative symlink pointing back at the
204+
# versioned library
205+
linked <- tryCatch(
206+
file.symlink(basename(versioned), lib),
207+
warning = function(w) FALSE
208+
)
209+
if (isTRUE(linked))
210+
return(invisible(TRUE))
211+
212+
# if the symlink couldn't be created (e.g. a filesystem without symlink
213+
# support), fall back to a plain copy so that 'libtbb.so' still exists.
214+
# the library has already been renamed at this point, so a failed copy
215+
# would leave no 'libtbb.so' at all; fail loudly rather than complete a
216+
# broken install
217+
writeLines("** couldn't create symlink; copying instead")
218+
copied <- tryCatch(
219+
file.copy(versioned, lib, overwrite = TRUE),
220+
warning = function(w) FALSE
221+
)
222+
if (!isTRUE(copied)) {
223+
fmt <- "couldn't copy '%s' to '%s'"
224+
stop(sprintf(fmt, versioned, lib))
225+
}
226+
227+
invisible(TRUE)
228+
229+
}
230+
231+
isElfFile <- function(path) {
232+
header <- tryCatch(
233+
readBin(path, "raw", n = 4L),
234+
condition = function(cnd) raw()
235+
)
236+
identical(header, charToRaw("\x7fELF"))
237+
}
238+
148239
# Report which TBB libraries are about to be installed, and from where.
149240
# Stale or unexpected libraries copied here have historically been a
150241
# subtle source of load failures in downstream packages, so make the

0 commit comments

Comments
 (0)