Friday, December 30, 2016

rJava: The Gift That Keeps On Giving

I've written not once but twice before (in 2011 and 2015) about the hassles of getting the rJava package to work with R. Every time I think I have a fix for it, someone changes something somewhere and the previous fix no longer works. I had to reinstall rJava today (from the Canonical repositories) after a system upgrade on PC. So, naturally it declined to work.

The symptoms, in both R terminal sessions and when running RStudio, were the same as in 2015. Executing library(rJava) in an R session earned me an error message containing the same nugget
libjvm.so: cannot open shared object file: No such file or directory
as before. Executing Sys.getenv(c("JAVA_HOME", "LD_LIBRARY_PATH")) showed me that the proximate cause was the same as in 2015: the library path was missing the "/jre" piece near its middle. So, same problem implies same cure, right? Wrong! The paths in /usr/lib/R/etc/ldpaths were correct; they just were not working as expected.

The key lines in  /usr/lib/R/etc/ldpaths were as follows.
: ${JAVA_HOME=/usr/lib/jvm/java-8-oracle/jre}
: ${R_JAVA_LD_LIBRARY_PATH=${JAVA_HOME}/lib/amd64/server}
They look correct, but apparently they are only executed if the corresponding environment variables (JAVA_HOME and R_JAVA_LD_LIBRARY_PATH) are not already defined. I suspect this is due to the colon at the start of each line, but I'm no expert on BASH syntax. You can test this in a terminal by running something like the following: execute
JAVA_HOME="silly" R
at the terminal prompt (which temporarily resets the JAVA_HOME environment variable to something, well, silly), and in the R session execute
Sys.getenv("LD_LIBRARY_PATH")
which prints a path whose Java portion starts with "silly".

The source of the predefined value of JAVA_HOME, at least on my system, is /etc/profile.d/jdk.sh, which contains the following lines.

export J2SDKDIR=/usr/lib/jvm/java-8-oracle
export J2REDIR=/usr/lib/jvm/java-8-oracle/jre
export PATH=$PATH:/usr/lib/jvm/java-8-oracle/bin:/usr/lib/jvm/java-8-oracle/db/bin:/usr/lib/jvm/java-8-oracle/jre/bin
export JAVA_HOME=/usr/lib/jvm/java-8-oracle
export DERBY_HOME=/usr/lib/jvm/java-8-oracle/db

One solution would be to append "/jre" to JAVA_HOME in that file (making it identical to J2REDIR), but that has two problems. The first is that whatever installer created /etc/profile.d/jdk.sh is likely to overwrite the change the next time the installer is run. The second, potentially more serious, problem is that JAVA_HOME is presumably being set to its current value for a reason. Changing it might have unforeseen consequences with another program.

So my "solution" (hack) is to modify one line in /usr/lib/R/etc/ldpaths as seen below.
## : ${R_JAVA_LD_LIBRARY_PATH=${JAVA_HOME}/lib/amd64/server}
: ${R_JAVA_LD_LIBRARY_PATH=${JAVA_HOME}/jre/lib/amd64/server}
That's still subject to being overwritten by an installer in the future, but at least it only affects R (and it works).

5 comments:

  1. This "hack" worked for me. Thanks a lot.

    ReplyDelete
  2. The witty banter in this made me lol twice. Thank u

    ReplyDelete
    Replies
    1. You're welcome. This is one of those situations where I either laugh or I cry.

      Delete
  3. Worked for me. Thanks so much! This is also my 3rd or 4th time solving this :(

    ReplyDelete

Due to intermittent spamming, comments are being moderated. If this is your first time commenting on the blog, please read the Ground Rules for Comments. In particular, if you want to ask an operations research-related question not relevant to this post, consider asking it on Operations Research Stack Exchange.