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

时间:2019-10-20 21:42:33

标签: rcpp arrayfire

由于Rcpp库,我正在尝试开发一个使用Arrayfire的R包。 我已经开始编写示例代码(将其命名为 hello_world.cpp ),如下所示:

#include <arrayfire.h>

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

然后,我尝试使用sourceCpp函数

对其进行编译
Rcpp::sourceCpp('src/hello_world.cpp')

我的第一个惊喜是必须手动设置一些标志(sourceCpp在编译一段C ++代码时似乎忽略了 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")

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

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

不幸的是,我找不到解决问题的方法(即使某些堆栈溢出问题引起的问题乍一看也差不多)。

我该如何解决?

2 个答案:

答案 0 :(得分:3)

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

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

如果我尝试您的示例,则与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)

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

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

  • 编辑/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安装到链接器默认搜索的目录中。自从我从源代码编译并使用resulting DEB packages以来,我就是这样做的。

对于Rcpp::sourceCpp不遵守Makevars文件的问题:问题是您编写的C ++文件不能直接使用。而是Rcpp属性必须创建其他包装函数,这是在临时目录中完成的。现在,原则上也可以将Makevars文件复制到该目录中。但是,通常使用Rcpp::pluginsRcpp::depends属性来设置此类变量。例如,使用// [[Rcpp::plugins(cpp11)]]完成打开C ++ 11的操作。对于其他变量,您可以编写自己的插件,也可以编写由我的RcppArrayFire提供的插件。

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

答案 1 :(得分:2)

一些事情,很快:

  • 使用sourceCpp()时不使用包裹
  • 随机删除与软件包一起使用的变量没有帮助
  • 实际上,是 Ralf whi的包裹可能会响起
  • 我们有一篇有关here at the Rcpp Gallery
  • 的文章

因此,我可能首先从Rcpp Gallery article about RcppArrayFire重做/重建示例。