Search code examples
rdynamic-loadinginstall.packages

How to specify (non-R) library path for dynamic library loading in R?


I keep getting the following error when attempting to install readxl or haven in R (both dependencies of tidyverse) post-compilation, when the installer runs the loading test:

** testing if installed package can be loaded
Error in dyn.load(file, DLLpath = DLLpath, ...) :
  unable to load shared object '<my_lib_Path>/readxl/libs/readxl.so':
  <my_lib_path>/readxl/libs/readxl.so: undefined symbol: libiconv
Error loading failed

I have libiconv.so in a local lib path (not for R packages) that is included in LD_LIBRARY_PATH and I've verified in my R session that Sys.getenv("LD_LIBRARY_PATH") has that directory. Why can't R's dynamic library loader find this shared object? Is there a different R-specific environment variable I need to define to have the dynamic library loader in R search my local lib path?

Please note that this is not an issue with an R library path, but instead for a non-R dependency that an R package has. If I were compiling and linking C++ code, gcc would use ld, and hence LD_LIBRARY_PATH to track down dynamic dependencies. R doesn't appear to respect this rather common approach, and I can't seem to find any documentation on how to manage these more fine-grained dependency issues.


Additional Details

!> sessionInfo()
 R version 3.3.3 (2017-03-06)
 Platform: x86_64-pc-linux-gnu (64-bit)
 Running under: CentOS Linux 7 (Core)

 locale:
  [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C
  [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8
  [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8
  [7] LC_PAPER=en_US.UTF-8       LC_NAME=C
  [9] LC_ADDRESS=C               LC_TELEPHONE=C
 [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C

 attached base packages:
 [1] stats     graphics  grDevices utils     datasets  methods   base
 > 

I had previously compiled libiconv because it was a dependency for something else (don't recall what now - likely not an R package given current problems). I tried reinstalling it, but made no difference.


Edit

I have also tried manually loading the library prior to installation:

> dyn.load(".local/lib/libiconv.so")
> is.loaded("libiconv")
[1] TRUE
> install.packages("tidyverse")

but it fails just as above.


Solution

  • Normally, the iconv method is picked up from glibc, which is linked to during build of the R packages in question. For whatever reason, however, iconv is getting resolved to libiconv in this case, but it is not linked by the R packages during build.

    Original Workaround

    One can make the linking to libiconv explicit by adding the following line to the haven/src/Makevars source file

    PKG_LIBS=-liconv
    

    which then let's you install from source R CMD INSTALL haven. However, editing packages feels hacky, plus this is something that will need to be done every upgrade, which sounds like a hassle.

    Cleaner Workaround

    Another option is to use withr::with_makevars, which allows one to temporarily control Makevars content. With this technique, one can install directly from the repo:

    withr::with_makevars(c(PKG_LIBS="-liconv"), install.packages("haven"), assignment="+=")
    

    Credit: @knb suggested that I inspect the readxl.so with ldd and this turned out to be super useful because it showed that the shared object wasn't even trying to link to libiconv. Knowing that, I realized I could manually add the reference via the -liconv flag. Thanks @knb!

    Additional Info

    On the package side of things, relevant details about connecting libraries to R packages can be found in the guide for building libraries. On the system configuration side, the R-admin guide has some useful sections.