I am trying to define a function using Rcpp for speedup. The situation is as follows:
Another option, in case you don't mind introducing Rcpp
into package FOO
- follow along with Section 3.5 of Rcpp-attributes and do the following:
Place // [[Rcpp::interfaces(cpp)]]
at the top of the .cpp
source files containing functions you'd like to be made available to other packages,
Place // [[Rcpp::export]]
in front of those functions you would like exported,
Call compileAttributes()
in the package directory of FOO
to generate files in inst/include
that can then be used by package BAR
, using // [[Rcpp::depends(FOO)]]
,
Install package FOO
.
If you have this set up correctly, you should be able to call a function with a template like this (supposing foo_a
is an exported function from FOO
):
// [[Rcpp::depends(FOO)]]
#include <Rcpp.h>
#include <FOO.h>
using namespace Rcpp;
// [[Rcpp::export]]
SEXP some_function() {
return FOO::foo_a();
}
I would recommend one of these options:
If foo_a
and foo_b
are simple enough, just have them as inline
functions in headers of FOO
and put these headers in FOO/inst/include/FOO.h
. Rcpp::depends(FOO)
will then include this file when you invoke compileAttributes
(or perhaps load_all
) on BAR
.
Otherwise, consider registering the functions using R's registration model. this is a bit more work, but that's bearable. Writing R extensions has the details. I would suggest putting all the registration logic in FOO
so that the client package BAR
only has to use it. For example, I'd have foo_a
like this in FOO
's headers, e.g. in FOO/inst/include/FOO.h
:
#ifdef COMPILING_FOO
inline int foo_a(int x, double y, const std::string& z){
typedef int (*Fun)(int, double, const std::string&) ;
static Fun fun = (Fun)R_GetCCallable( "FOO", "foo_a" ) ;
return fun(x,y,z) ;
}
#else
// just declare it
int foo_a(int x, double y, const std::string& z) ;
#endif
and the actual definition of foo_a
in some .cpp
file in FOO/src
:
#define COMPILING_FOO
#include <FOO.h>
int foo_a(int x, double y, const std::string& z){
// do stuff
}
Then, you need to register foo_a
using R_RegisterCCallable
in the function R_init_FOO
:
extern "C" void R_init_FOO( DllInfo* info ){
R_RegisterCCallable( "FOO", "foo_a", (DL_FUNC)foo_a );
}
The RcppXts package does just that for a bunch of functions from the well-known xts package.
Edit: Here is some code from xts.
First, xts::src/init.c does the registration via a dozen or so declarations like
R_RegisterCCallable("xts","do_is_ordered",(DL_FUNC) &do_is_ordered);
Second, xts::inst/include/xtsApi.h provides a header for client packages with eg
SEXP attribute_hidden xtsIsOrdered(SEXP x, SEXP increasing, SEXP strictly) {
static SEXP(*fun)(SEXP,SEXP,SEXP) = NULL;
fun = (SEXP(*)(SEXP,SEXP,SEXP)) R_GetCCallable("xts","do_is_ordered");
return fun(x, increasing, strictly);
}
Third, in a client package such as RcppXts we define this (using Rcpp Modules) as
function("xtsIsOrdered",
&xtsIsOrdered,
List::create(Named("x"),
Named("increasing") = true,
Named("strictly") = true),
"Tests whether object is (strictly) (increasing) ordered");
which exposes it to R. We could equally well call the C function xtsIsOrdered
from C++ code.
I removed the incorrect earlier comment that functions have to conform to 'SEXP in, SEXP out'.