如何为 R 中的动态库加载指定(非 R)库路径?

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

尝试在 R 中安装 readxlhaventidyverse 的两个依赖项)post-compilation,当安装程序运行时,我不断收到以下错误加载测试:

** 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

我在 LD_LIBRARY_PATH 中包含的本地 lib 路径(不适用于 R 包)中有 libiconv.so,并且我已经在我的 R 会话中验证 Sys.getenv("LD_LIBRARY_PATH") 有那个目录. 为什么R的动态库加载器找不到这个共享对象? 是否需要定义不同的 R 特定环境变量,以便让 R 中的动态库加载程序搜索我的本地库路径?

请注意,这不是 R 库路径的问题,而是 R 包具有的非 R 依赖项的问题。如果我正在编译和链接 C++ 代码,gcc 将使用 ld,因此 LD_LIBRARY_PATH 会跟踪动态依赖项。 R 似乎不尊重这种相当普遍的方法,而且我似乎找不到任何关于如何管理这些更细粒度的依赖性问题的文档。


其他详细信息

!> 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
 > 

我之前编译过 libiconv,因为它是对其他东西的依赖(现在不记得是什么了——考虑到当前的问题,可能不是 R 包)。我试过重新安装它,但没有任何区别。


编辑

我也试过在安装前手动加载库:

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

但是还是失败了。

通常,iconv 方法是从 glibc 中提取的,link 在相关 R 包的构建过程中被编辑到。然而,无论出于何种原因,iconv 在这种情况下被解析为 libiconv,但它在构建期间未被 R 包 link 编辑。

原始解决方法

可以通过将以下行添加到 haven/src/Makevars 源文件

来使 linking 到 libiconv 显式
PKG_LIBS=-liconv

然后让我们从源安装 R CMD INSTALL haven。然而,编辑包感觉很hacky,而且每次升级都需要做这件事,听起来很麻烦。

更清洁的解决方法

另一种选择是使用withr::with_makevars,它允许临时控制Makevars 内容。使用这种技术,可以直接从 repo 安装:

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

Credit:@knb 建议我用 ldd 检查 readxl.so,结果证明这非常有用,因为它表明共享对象甚至没有尝试 link 到 libiconv。知道这一点后,我意识到我可以通过 -liconv 标志手动添加引用。谢谢@knb!

附加信息

在包方面,有关将库连接到 R 包的相关详细信息可以在 the guide for building libraries. On the system configuration side, the R-admin guide 中找到一些有用的部分。

您是运行 RStudio Server 中的代码吗?如果是这样,这里的答案可能会有用。

我曾经在加载动态库时遇到过类似的错误。该库位于 LD_LIBRARY_PATH 中包含的路径中。当我 运行 R控制台中的代码时,它可以正确加载动态库。但是当我 运行 它在 RStudio 中时,你的 post 中出现了同样的错误。

原因是RStudio Server有自己的库搜索路径环境。您应该在 /etc/rstudio/rserver.conf 中指定以下配置:

rsession-ld-library-path=/usr/lib64/:/usr/local/lib/:OTHER_PATH_OF_YOUR_LIB

重新启动 RStudio 服务器,错误应该已修复。

这些库确实也应该是基于 RH 的系统的标准,并且可以找到。

如果必须将它们添加到 R,则必须在 启动 R 之前这样做。一种方法是通过 LD_LIBRARY_PATH,更好的方法是编辑 /etc/ld.so.conf.d/ 中的文件(假设 RH/CentOS 也有)。否则可能通过 /etc/environment.

编辑:如果/etc/够不到,你可以在$HOME下面做所有事情。标准 shell 实例化有效,R 有自己的 .Rprofile.Renviron。对于所有项目,您可以在 $HOME 以下,在每个项目目录中 and/or ---请参阅 help(Startup)

你是通过rpm安装R还是自己编译的?

解决方案 1

如果您有权限修改 R 可执行文件(shell 脚本),您可以试试这个:

编辑 ~/.local/bin/R/usr/local/bin/R/usr/bin/R

#!/bin/bash
# Shell wrapper for R executable.

export LD_LIBRARY_PATH="<my_lib_Path>/readxl/libs/"
R_HOME_DIR=...
...
...

解决方案 2

或者您可以vim ~/.local/bin/R

#!/bin/bash
# Shell wrapper for R executable.

export LD_LIBRARY_PATH="<my_lib_Path>/readxl/libs/"

/usr/bin/R

然后将 ~/.local/bin 添加到您的 PATH

我将 export LD_LIBRARY_PATH=... 语句放入文件 ~/.profile。 这样,命令行 R 和 RStudio Server 都可以找到共享库。

就我而言,我试图获取 Rglpk 包以找到 libglpk.so 文件。 根据 Stefaan Lippen's blog entry.profile 文件是这些与 bash 不严格相关的配置的首选位置。