理解`Makevars`用于链接到R包中的外部C库

时间:2018-03-07 14:38:25

标签: rcpp r-package

我正在开发一个包含来自第三方库(SUNDIALS)的C代码的软件包。包使用以下执行静态链接的Makevars文件进行编译和工作(即,能够解决测试ODE)

CXX=clang++

PKG_CPPFLAGS = -I../inst/include
PKG_LDFLAGS = /usr/local/lib
PKG_LIBS= $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS) $(PKG_LDFLAGS)/libsundials_cvode.a $(PKG_LDFLAGS)/libsundials_nvecserial.a

然而,略有修改版本(基于R-Exts中的示例,即 -  PKG_LIBS = -L$(XML_DIR)/lib -lxml2(下方)的Makevars}失败

CXX=clang++

PKG_CPPFLAGS = -I../inst/include
PKG_LDFLAGS = /usr/local/lib
PKG_LIBS= $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS) -L$(PKG_LDFLAGS) -lsundials_cvode -lsundials_nvecserial -lm

失败,并显示以下错误消息。

Error: package or namespace load failed for ‘Rcppsbmod’ in dyn.load(file, DLLpath = DLLpath, ...):
 unable to load shared object '/Library/Frameworks/R.framework/Versions/3.4/Resources/library/Rcppsbmod/libs/Rcppsbmod.so':
  dlopen(/Library/Frameworks/R.framework/Versions/3.4/Resources/library/Rcppsbmod/libs/Rcppsbmod.so, 6): Library not loaded: libsundials_cvode.3.dylib
  Referenced from: /Library/Frameworks/R.framework/Versions/3.4/Resources/library/Rcppsbmod/libs/Rcppsbmod.so
  Reason: image not found
Error: loading failed
Execution halted
ERROR: loading failed
* removing ‘/Library/Frameworks/R.framework/Versions/3.4/Resources/library/Rcppsbmod’
* restoring previous ‘/Library/Frameworks/R.framework/Versions/3.4/Resources/library/Rcppsbmod’

Exited with status 1.

当我将PKG_LDFLAGS指定为/usr/local/lib时,我不确定为什么要在其他位置查找库。

顺便说一句,SUNDIALS包编译并使用以下命令的测试示例

gcc -Wall cvRoberts_dns.c -o cvRoberts_dns.exe -I/usr/local/include -L/usr/local/lib/ -lsundials_cvode -lsundials_nvecserial -lm

因此,我知道库已正确安装,并且/usr/local/lib位置提供了正确的文件(用于链接)。

整个软件包源代码可以在 - https://github.com/sn248/Rcppsbmod

找到

任何帮助或指导都将受到高度赞赏!

2 个答案:

答案 0 :(得分:3)

我正在与类似的问题作斗争,c。 Runtime linking R-extension on MacOS。我目前的解决方法是在编译时设置rpath。在你的情况下,这意味着:

CXX=clang++

PKG_CPPFLAGS = -I../inst/include
PKG_LDFLAGS = /usr/local/lib
PKG_LIBS= $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS) -L$(PKG_LDFLAGS) -lsundials_cvode -lsundials_nvecserial -lm -Wl,-rpath,$(PKG_LDFLAGS) 

但是,这并不能解决您的问题。比较错误消息,我发现有一点不同:在您的情况下,找不到库libsundials_cvode.3.dylib,而在我的情况下,它是@rpath/libaf.3.dylib。这意味着您安装的库将自己标识为libsundials_cvode.3.dylib。您可以使用

进行检查
$ otool -L /usr/local/lib/libsundials_cvode.3.dylib 
/usr/local/lib/libsundials_cvode.3.dylib:
    /usr/local/opt/sundials/lib/libsundials_cvode.3.dylib (compatibility version 3.0.0, current version 3.1.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.0.0)

在您的情况下,第二个输出行不应包含绝对路径,而只应包含库的基本名称。我的安装使用brew,它通常使用绝对路径作为库名。在一些简单的测试中,我将R扩展与这些库链接没有问题。

我看到了几种可能性:

  • brew尝试SUNDIAL。
  • 使用

    调整已安装库中的库路径
    install_name_tool -id /usr/local/lib/libsundials_cvode.3.dylib /usr/local/lib/libsundials_cvode.3.dylib
    

    使用绝对路径。

  • 使用

    调整已安装库中的库路径
    install_name_tool -id '@rpath/libsundials_cvode.3.dylib' /usr/local/lib/libsundials_cvode.3.dylib
    

    并按上述方式设置rpath

  • 通过添加Makevars

    ,调整R分机正在查找的库的名称
    all: $(SHLIB)
        @if command -v install_name_tool; then install_name_tool -change libsundials_cvode.3.dylib /usr/local/lib/libsundials_cvode.3.dylib $(SHLIB); fi
    

答案 1 :(得分:2)

系统范围的动态链接,如第二个失败的用例,需要系统上动态链接器的配合。

这意味着在构建并将库复制到/usr/local/lib之后,通常必须运行sudo ldconfig来更新链接器缓存。

您可以通过ldconfig -p的输出来查看是否知道库。在我的系统上,没有日,,

edd@rob:~$ ldconfig -p | grep sundials
edd@rob:~$ 

相关地,您可以(本地)通过声明它们来使用不同的目录 /etc/ld.so.conf.d/somefile.conf - 但这当然不是便携式的,也无法帮助您使用为CRAN指定的包。

使用您在第一个示例中构建的静态库作为包的一部分,因为需要任何系统帮助。每次构建库只需要更长的时间。