Hi,
This post is the sequel of the Rcpp installation (
http://groups.google.com/group/brumail/browse_thread/thread/aefbcab7a6f7804b
)
Assuming the Rcpp is properly installed on the system, this post is
meant for calling C++ function from R environment.
We will start with hello world program to gain confidence and then we
can move on to more sophisticated program.
The sample program is on linux ( Windows as usual somewhat
difficult.we need to download Rtools and lot of configuration, but for
sure we are going to break it)
For calling C/C++ functions from R following things should be taken
care of:
1. Linking the Rcpp header file. For this you have two options
OPTION 1: Give the directory path of the Rcpp in the
LD_LIBRARY_PATH
export LD_LIBRARY_PATH=/usr/lib64/R/
library/Rcpp/include
This option however was not working for
me, and i didn't dig more on this so i chose the second option.
OPTION 2: Copy the entire include directory in the /usr/
include/R directory
cp -r /usr/lib64/R/library/Rcpp/include /
usr/include/R
2.Writing C++ function:
(A) The C++ function which you will be calling from the R should be
enclosed in the extern "C" scope. Even though Rcpp is meant for
calling c++ function from R, but it compiles only C function. if you
dont enclose the functions within extern "C" scope, there wont be any
error but the function will not be loaded in the R symbol table.(More
on this later)
(B) While passing arguments to these C/C++ function, the arguments
should be pointer. While sending the "R" variables to these functions,
R will convert them to pointers and send them to the functions.
(C) The most intriguing part is that the function which you need to
call should take at least one parameter or else error will be thrown.
The following steps will give you the idea to how to call the
functions from R
Step1: Write your cpp function
Step2: Run the command R CMD SHLIB file.cpp. This command will create
the library and the object file
Step3: On the R side, load the library which is created in the step2
by using the function
dyn.load("path to the library name")
Step4: Call the function which you have declared in the cpp file by
the following conventions
(i) .C("FunctionName",variable that is needed by the
functions,...)
(ii) .Call("FunctionName",.....)
You need to send the variables in the same order in which the function
wants that or else you know what will happen?
Step4: The result you can verify
Now if the steps are clear, we can move on to our first sample
program:
------------------------------------------------
(1) Writing Cpp functions
------------------------------------------------
The following lines are there in my file hello_world.cpp
#include <Rcpp.h>
#include <R.h>
extern "C"
{
void Print(int* i)
{
Rprintf("hello world=%d",*i);
}
}
Description: As you can see that i have a function name Print(int* i),
even though that is not useful, but this is the restriction. I need to
do some research on that. The Rprintf function is C equivalent of
printf function which is defined in the header file R.h.
Another important thing to note is that i have enclosed the function
in the extern "C" scope. This is another restriction
---------------------------------------------------
(2) Running the command to create library and object file
-----------------------------------------------------
Run the following command to create the library:
R CMD SHLIB hello_world.cpp
This command if runs successfully will create the library
hello_world.so and hello_world.o in the same directory where the cpp
file is residing.
----------------------------------------------------
(3) Loading the libray
--------------------------------------------------
use the function dyn.load() to load the libray
dyn.load("/home/som/CPP/hello_world.so")
--------------------------------------------------------
(4)Check whether the function "Print" which you have written in
hello_world.cpp is present in the symbol table or not
-----------------------------------------------------------------------------------------------
is.loaded("Print")
if it returns true, then no problem, but if it written false, then
there could be following reasons:
(A) Library is not loaded
(B) Library is properly loaded since dyn.load is not throwing
error, then you have to check whether the Print function is under
extern "C" scope or not
----------------------------------------
(5) Calling the function
----------------------------------
If all the above steps are successful, then just declare some
arbitrary variable for ex: x<-10
and call the function as follows:
.C("Print",as.integer(x))
the output on the screen will be
hello world=10[[1]]
[1] 10
The list which you are seeing is nothing but the function returns
list back to the R.
---------------------------------
Sample R script hello.R
---------------------------------
myfirst=function(x)
{
if(!is.loaded('Print'))dyn.load('/home/drilldown/CPP/hello_world.so')
z=.C('Print',as.integer(x))
return(z)
}
z<-10;
ans<-myfirst(z)
if you run this script the output will be something like this:
>source("/home/som/CPP/hello.R")
>hello world=10
if you print "ans" then it will print the list
> ans
[[1]]
[1] 10
Hope you got this. The next post we will deal with some advanced
examples and usage of R variables in c++ functions
Regards,
Som Shekhar