Rcpp:无法打开共享对象文件

Krz*_*Joa 3 rcpp arrayfire

我试图开发的R包,它利用了Arrayfire,感谢RCPP库。我已经开始编写一个示例代码(让我们将其命名为hello_world.cpp),如下所示:

#include <arrayfire.h>

// [[Rcpp::export]]
bool test_array_fire(){
    af::randu(1, 4);    
    return true;
}
Run Code Online (Sandbox Code Playgroud)

然后,我尝试使用sourceCpp函数编译它

Rcpp::sourceCpp('src/hello_world.cpp')
Run Code Online (Sandbox Code Playgroud)

我的第一个惊喜是我必须手动设置一些标志(在编译一段 C++ 代码时sourceCpp似乎忽略了Makevars配置)。我是这样做的:

Sys.setenv("PKG_CXXFLAGS"="-std=c++11")
Sys.setenv("PKG_CPPFLAGS"="-I/opt/arrayfire/include/")
Sys.setenv("PKG_LIBS"="-L/opt/arrayfire/lib64/ -laf")
Run Code Online (Sandbox Code Playgroud)

但是,代码仍然无法正确编译。每次试验都以以下输出结束:

Error in 'dyn.load("/tmp/RtmpHaODIU/sourceCpp-x86_64-pc-linux-gnu-1.0.2/sourcecpp_689c5adb8d/sourceCpp_14.so")':
unable to load shared object '/tmp/RtmpHaODIU/sourceCpp-x86_64-pc-linux-gnu-1.0.2/sourcecpp_689c5adb8d/sourceCpp_14.so':
  libaf.so.3: cannot open shared object file: No such file or directory
Run Code Online (Sandbox Code Playgroud)

不幸的是,我无法为我的问题找到解决方案(即使某些 Stack Overflow 问题引发了乍一看或多或少相似的问题)。

我该如何解决?

Ral*_*ner 7

当 R 尝试加载共享对象文件时,该错误发生在过程中的很晚。这意味着在您设置的环境变量的帮助下,编译和链接工作正常。但是在最后一步中,运行时链接器不知道libaf.so.3位于何处。这是一种通常在操作系统级别进行的配置,例如在我的系统上

ralf@barra:~$ /sbin/ldconfig -p | grep libaf
        libafopencl.so.3 (libc6,x86-64) => /lib/libafopencl.so.3
        libafopencl.so (libc6,x86-64) => /lib/libafopencl.so
        libafcpu.so.3 (libc6,x86-64) => /lib/libafcpu.so.3
        libafcpu.so (libc6,x86-64) => /lib/libafcpu.so
        libaf.so.3 (libc6,x86-64) => /lib/libaf.so.3
        libaf.so (libc6,x86-64) => /lib/libaf.so
Run Code Online (Sandbox Code Playgroud)

如果我尝试你的例子,它与链接到的共享对象文件没有问题libaf

ralf@barra:~$ ldd /tmp/RtmpcjY9dN/sourceCpp-x86_64-pc-linux-gnu-1.0.2/sourcecpp_13d33790279c/sourceCpp_7.so | grep libaf
        libaf.so.3 => /lib/libaf.so.3 (0x00007f21037ed000)
Run Code Online (Sandbox Code Playgroud)

我希望在您的情况下,第一个命令不会提供任何结果,第二个(调整后的)命令将导致“找不到文件”(?)错误。

有几种方法可以告诉运行时链接器有关库位置的信息:

  • 编辑/etc/ld.so.conf或(更好)将文件放在 中/etc/ld.so.conf.d/,参见http://arrayfire.org/docs/installing.htm#Linux
  • 设置LD_LIBRARY_PATH
  • 添加-Wl,-rpath,/opt/arrayfire/lib64/PKG_LIBS
  • 将 ArrayFire 安装到链接器默认搜索的目录中。这就是我所做的,因为我从源代码编译并使用生成的 DEB 包

至于Rcpp::sourceCpp不尊重Makevars文件:问题是你写的C++文件不能直接使用。相反,Rcpp 属性必须创建额外的包装函数,这是在临时目录中完成的。现在原则上也可以将Makevars文件复制到该目录中。但是,通常在Rcpp::pluginsRcpp::depends属性的帮助下设置此类变量。例如,使用// [[Rcpp::plugins(cpp11)]]. 对于其他变量,您可以编写自己的插件,也可以编写我的RcppArrayFire提供的插件

但是,如果这是您的目标,我建议您从一个包开始。Rcpp::sourceCpp在很多方面都很棒,但是在没有 R 包帮助的情况下与系统安装的库接口不是其中之一。