|
50 | 50 | system2("cp", c("-P", shQuote(tbbLib), shQuote(tbbDest))) |
51 | 51 | } |
52 | 52 |
|
| 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 | + |
53 | 58 | } else { |
54 | 59 |
|
55 | 60 | # using system tbb |
@@ -145,6 +150,92 @@ buildTbbStub <- function(tbbDest) { |
145 | 150 |
|
146 | 151 | } |
147 | 152 |
|
| 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 | + |
148 | 239 | # Report which TBB libraries are about to be installed, and from where. |
149 | 240 | # Stale or unexpected libraries copied here have historically been a |
150 | 241 | # subtle source of load failures in downstream packages, so make the |
|
0 commit comments