Rcpp 理解“Makevars”以链接到R包中的外部C库

Rcpp 理解“Makevars”以链接到R包中的外部C库,rcpp,r-package,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)/

我正在开发一个软件包,其中包括来自第三方库(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中的示例,即-
Makevars
(以下)的PKG_LIBS=-L$(XML_DIR)/lib-lxml2)失败

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

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.
当我将
pkgldflags
指定为
/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
位置获得正确的文件(用于链接)

整个软件包源代码可在以下位置找到-


任何帮助或指导都将不胜感激

系统范围的动态链接,就像在第二个失败的用例中一样,需要系统上的动态链接器的合作

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

您可以通过查询
ldconfig-p
的输出来检查库是否已知。在我的系统上,没有日晷:

edd@rob:~$ ldconfig -p | grep sundials
edd@rob:~$ 
相关地,您可以(本地)通过在中声明不同的目录来使用它们
/etc/ld.so.conf.d/somefile.conf
——但这当然是不可移植的,也无助于您使用指定用于CRAN的包


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

我正在为类似的问题而斗争,c.f。我目前的解决方法是在编译时设置
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) 
但是,这并不能解决您的问题。比较这些错误消息,我发现了一个区别:在您的示例中,找不到库
libsundails\u cvode.3.dylib
,而在我的示例中,它是
@rpath/libaf.3.dylib
。这意味着您安装的库将自己标识为
libsundails\u 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)
在您的情况下,第二个输出行不应该包含绝对路径,而应该只包含库的basename。我的安装使用
brew
,它通常使用绝对路径作为库名称。在一些琐碎的测试中,我将R扩展与这些库链接起来没有问题

我认为有几种可能性:

  • brew
    尝试日晷
  • 使用调整已安装库中的库路径

    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
    
    使用绝对路径

  • 使用调整已安装库中的库路径

    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

    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
    

谢谢@Dirk的建议。在OSX上(之前应该提到过),没有
ldconfig
,但是有
sudo-update\u-dyld\u-shared\u-cache
。运行此命令
sudo update_dyld_shared_cache | grep sundials
会显示一条长消息,例如
update_dyld_shared_cache:warning@rpath system framework的安装名称:/System/Library/PrivateFrameworks/AssetCacheStensions.framework/Versions/A/XPCServices/AssetCacheTheratorService.xpc/Contents/Frameworks/MobileDeviceLite.framework/Versions/A/MobileDeviceLite
。但是,如果静态与动态不那么重要,我现在不会做任何更改。我的下一个挑战是捆绑软件包,这样就没有在系统上安装库的先决条件(因为在Windows上安装日晷并不是那么简单)。谢谢你的回答。拉尔夫-谢谢你的回答。我尝试了你的方法(用
-rpath
而不是
rpath
做了一些细微的改变)。我收到以下消息(见下文)。任何建议都欢迎<代码>错误:dyn.load(文件,DLLpath=DLLpath,…)中的“Rcppsbmod”的包或命名空间加载失败:无法加载共享对象“/Library/Frameworks/R.framework/R.framework/Versions/3.4/Resources/Library/Rcppsbmod/libs/Rcppsbmod.so”:dlopen(/Library/Frameworks/R.framework/Versions/3.4/Resources/libs/Rcppsbmod.so,6):库未加载:libsundials\u cvode.3.dylib引用自:/Library/Frameworks/R.framework/Versions/3.4/Resources/Library/Rcppsbmod/libs/Rcppsbmod.so原因:找不到图像错误:加载失败libsundals_cvode.3.1.0.dylib libsundals_cvode.3.dylib libsundals_cvodes.a libsundals_cvodes.2.0.0.dylib libsundals_cvodes.2.dylib libsundals_cvodes.3.1.0.dylib libsundals_cvodes.3.dylibsundals_cvodes.a libsundals_cvodes.dylib@SN248您是如何安装Sundals库和安装Sundals的我认为Linux没有那么难。我特别想到的是Windows。无论如何,我希望用户能够使用这个软件包,即使他们没有安装日晷。我已经看到了这一点(nloptr、RCPPCAF),并将尝试复制那里正在做的事情。谢谢