From 81739adaa2fbd115b6668e8c1f87cfcc2f3e090a Mon Sep 17 00:00:00 2001 From: Ray Donnelly Date: Thu, 8 Jun 2017 15:42:06 +0100 Subject: [PATCH] Improve {lib,}jvm.{so,dylib,dll} loading Use the values from Makeconf to find java (Unix), falling back to JAVA_HOME (which is needed on Windows). Add the directory to PATH on Windows or dyn.load the shared library it on Linux. macOS is kept largely the same as it was except we check Makeconf before JAVA_HOME. --- R/zzz.R.in | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/R/zzz.R.in b/R/zzz.R.in index eb8aba7..f00e1bd 100644 --- a/R/zzz.R.in +++ b/R/zzz.R.in @@ -1,9 +1,71 @@ +getMakeconfVar <- function(makeconf, var) { + # With some assistance from: + # https://github.com/r-hub/sysreqs/blob/master/R/platform.R + result <- grep(paste("^", var, "[ ]?=",sep=''), makeconf, value = TRUE) + sub(paste("^", var, "[ ]?=[ ]?", sep=''), "", result) +} + .onLoad <- function(libname, pkgname) { - Sys.setenv("LD_LIBRARY_PATH"=paste(Sys.getenv("LD_LIBRARY_PATH"),"@JAVA_LD@",sep=':')) + # Conda refuses to mess with LD_LIBRARY_PATH (etc/ldconfig does not do that now) + # as it is the Linux equivalent of DLL-hell and has caused real problems with + # R, instead we pre-load libjvm.so from the location detected by javareconf. + Makeconf <- readLines(file.path(R.home(), "etc", Sys.getenv('R_ARCH'), "Makeconf")) + dylib_ext <- getMakeconfVar(Makeconf, "DYLIB_EXT") + if (length(grep("^mingw", R.version$os))) { + exe_ext <- ".exe" + lib_prefix <- "" + } else { + exe_ext <- "" + lib_prefix <- "lib" + } + jvm_fname = paste(lib_prefix, "jvm", dylib_ext, sep='') + jh <- getMakeconfVar(Makeconf, "JAVA_HOME") + j_ld_lp <- gsub("$(JAVA_HOME)", jh, getMakeconfVar(Makeconf, "JAVA_LD_LIBRARY_PATH"), fixed=TRUE) + jvm <- file.path(j_ld_lp, jvm_fname) + if (!length(j_ld_lp) || !file.exists(jvm)) { + if (!length(jh)) { + # In this case (which will always happen on Windows) fall back to JAVA_HOME + jh <- Sys.getenv("JAVA_HOME") + java_exe <- file.path(jh, 'bin', paste('java', exe_ext, sep='')) + Javaconf <- system2(java_exe, args=c("-XshowSettings:properties", "-version"), stderr = TRUE, stdout = TRUE, minimized = TRUE) + j_ld_lp <- grep(' *sun\\.boot\\.library\\.path[ ]?=', Javaconf, perl = TRUE, value = TRUE) + j_ld_lp <- sub(' *sun\\.boot\\.library\\.path[ ]?=[ ]?', "", j_ld_lp) + if (file.exists(file.path(j_ld_lp, "server", jvm_fname))) { + j_ld_lp <- file.path(j_ld_lp, "server") + } else if (file.exists(file.path(j_ld_lp, "client", jvm_fname))) { + j_ld_lp <- file.path(j_ld_lp, "client") + } + } + } + jvm <- file.path(j_ld_lp, jvm_fname) + + if (length(grep("^darwin", R.version$os))) { + # NYI, need to re-create the dylib stub to point to the real JVM dylib + } else if (length(grep("^linux", R.version$os))) { + if (file.exists(jvm)) { + dyn.load(jvm, local=FALSE, now=TRUE) + } else { + # This is what the code originally did. Kept as a last resort only, but if it is run + # then something bad has happened. + Sys.setenv("LD_LIBRARY_PATH"=paste(Sys.getenv("LD_LIBRARY_PATH"),"@JAVA_LD@",sep=':')) + } + } else if (length(grep("^mingw", R.version$os))) { + # When all you have is a hammer. If the dir is not on PATH then add it. + # It would be nice here to find the first jvm.dll on PATH and if that + # entry comes before our directory (or our directory is not on PATH) then + # re-arrange the entries so that ours appears before it. Overkill though? + win_j_ld_lp <- gsub("/", "\\\\", j_ld_lp) + split_path <- strsplit(Sys.getenv("PATH"), ";") + if (!win_j_ld_lp %in% unlist(split_path)) { + if (file.exists(win_j_ld_lp) && file.info(win_j_ld_lp)$isdir == TRUE) { + Sys.setenv("PATH"=paste(win_j_ld_lp, Sys.getenv("PATH"), sep=';')) + } + } + } + ## On OS X with Oracle Java we may need to work around Oracle bug: ## https://bugs.openjdk.java.net/browse/JDK-7131356 if (length(grep("^darwin", R.version$os)) && file.exists("/usr/libexec/java_home")) { - jh <- Sys.getenv("JAVA_HOME") if (!nzchar(jh)) jh <- system("/usr/libexec/java_home", intern=TRUE)[1L] if (file.exists(file.path(jh, "jre/lib"))) jh <- file.path(jh, "jre") if (file.exists(jli <- file.path(jh, "lib/jli/libjli.dylib"))) {