I have been struggling on this for a while as well, but once you know how I'ts actually not that difficult.
First create a Rust library following these instructions: rust-inside-other-languages.
Here is an example Rust library:
//src/lib.rs
#[no_mangle]
pub fn kelvin_to_fahrenheit(n: f64) -> f64 {
n * 9.0/5.0 - 459.67
}
If you follow the instructions in rust-inside-other-languages, then you should be able to generate a *.so
(or *.dll
or .dylib
, depending on your system). Let's presume this compiled file is called libtempr.so
.
Now create a C++ file which will pass the functions you need to R:
//embed.cpp
extern "C" {
double kelvin_to_fahrenheit(double);
}
// [[Rcpp::export]]
double cpp_kelvin_to_fahrenheit(double k) {
double f = kelvin_to_fahrenheit(k);
return(f);
}
Now before starting R, make sure the environment variable LD_LIBRARY_PATH
contains the directory where the shared object generated previously (libtempr.so
) is stored. In the shell do:
$ export LD_LIBRARY_PATH=/home/sam/path/to/shared/object:$LD_LIBRARY_PATH
$ rstudio # I highly recommend using Rstudio for your R coding
Finally in Rstudo, write this file:
library(Rcpp)
Sys.setenv("PKG_LIBS"="-L/home/sam/path/to/shared/object -ltempr")
sourceCpp("/home/sam/path/to/embed.cpp", verbose = T, rebuild = T)
cpp_kelvin_to_fahrenheit(300)
- Be careful that in
Sys.setenv
the -L
option points to the directory containing your Rust shared object.
- Also be careful that
-l
option is the name of your shared object without the lib
prefix and without the .so
(or whatever it is on your system) postfix.
- Using
Sys.setenv
in R to set the LD_LIBRARY_PATH
variable DOES NOT WORK. Export the variable before starting R.
- The
verbose
option is there so that you can see what Rcpp
does to compile your C++ file. Notice how the options in PKG_LIBS
above are used for compiling your C++ file.
- The
rebuild
options is there to force a rebuild of the C++ file every time you run this line of R code.
If you did everything well, then run the R file above in the interactive console and it should output 80.33
when you reach the last line.
If anything is not clear, ask in the comments, and I'll try to improve my answer.
Hope it helped :)
Final note, the base functions dyn.load
and .C
can be used as an alternative approach. But this requires writing a lot more boilerplate wrapper code than this approach.