问题
I'm trying to develop an R package, which makes use of Arrayfire, thanks to Rcpp library. I've started writing a sample code (let's name it hello_world.cpp) which looks like this:
#include <arrayfire.h>
// [[Rcpp::export]]
bool test_array_fire(){
af::randu(1, 4);
return true;
}
Then, I tried to compile it using a sourceCpp
function
Rcpp::sourceCpp('src/hello_world.cpp')
My first suprise was the fact I had to set some flags manually (sourceCpp
seems to ignore Makevars config when compiling a piece of C++ code).
I did it with:
Sys.setenv("PKG_CXXFLAGS"="-std=c++11")
Sys.setenv("PKG_CPPFLAGS"="-I/opt/arrayfire/include/")
Sys.setenv("PKG_LIBS"="-L/opt/arrayfire/lib64/ -laf")
However, the code still does not compile properly. Each trial finishes with the following output:
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
Unfortunately, I could not find an solution for my problem (even if some Stack Overflow questions raise issues which are more or less similar at first glance).
How can I fix it?
回答1:
The error occurs very late in the process when R tries to load the shared object file. This means that compilation and linking worked fine with the help of the environment variables you set. But in the final step the run-time linker does not know where libaf.so.3
is located. This is a configuration one normally does at the OS level, e.g. on my system
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
And if I try your example it works without problems with a shared object file that is linked against 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)
I expect that in your case the first command will provide no result and the second (adjusted) command will lead a "file not found"(?) error.
There are several ways to tell the run-time linker about the location of the library:
- Edit
/etc/ld.so.conf
or (better) place a file in/etc.ld.so.conf.d/
, c.f. http://arrayfire.org/docs/installing.htm#Linux. - Set
LD_LIBRARY_PATH
. - Add
-Wl,-rpath,/opt/arrayfire/lib64/
toPKG_LIBS
- Install ArrayFire into a directory that the linker searches by default. That's what I am doing since I compile from source and use the resulting DEB packages.
As for Rcpp::sourceCpp
not respecting a Makevars
file: The problem is that the C++ file you write cannot be used directly. Instead Rcpp attributes has to create additional wrapper functions, which is done in a temporary directory. Now one could in principle copy a Makevars
file into that directory as well. However, one normally sets such variables with the help of Rcpp::plugins
and Rcpp::depends
attributes. For example, switching on C++11 is done using // [[Rcpp::plugins(cpp11)]]
. For the other variables, you could write your own plugin or us the one provided by my RcppArrayFire.
However, I suggest you start with a package if that is your goal. Rcpp::sourceCpp
is great for many things, but interfacing with a system installed library without the help of an R package is not one of them.
回答2:
A few things, quickly:
- when you use
sourceCpp()
you are not using a package - randomly dropping variable used with a package do not help
- there actually is a package by Ralf whi will probably chime in
- and we have a writeup about it here at the Rcpp Gallery
So I would probably start by redoing / rebuilding the examples from the Rcpp Gallery article about RcppArrayFire.
来源:https://stackoverflow.com/questions/58477576/rcpp-cannot-open-shared-object-file