Skip to content
Dirk Eddelbuettel edited this page Jan 20, 2014 · 4 revisions

Rcpp is now "header only". Well, not really, but for the purpose of this document that is an accurate enough description.

This means client packages no longer need Makevars and Makevars.win, nor need to deal with what we used to call the Rcpp user library. No such thing anymore, we just don't build it anymore. No more need to use Rcpp:::LdFlags. The only thing that is needed from now is:

LinkingTo: Rcpp

There also appears to be a need for an explicit import statement in the file NAMESPACE. Just using import(Rcpp) is unfortunately not sufficient, but importing a function (actually: any function) works:

importFrom(Rcpp, evalCpp)

as Rcpp:::CxxFlags had been unnecessary for a while.

Moving Code to headers

The first step of this conversion was to move a lot of code to headers. This was achieved thanks to inlining and generalization through templates.

inlining

This is pretty simple. Make a function inline, move it to the headers. Done.

API policy design

If you look into the details, you'll see that classes from the Rcpp API are now instantiations of template classes instead of classes. For example, RObject looks like this:

template < template <class> class StoragePolicy > class RObject_Impl : 
    public StoragePolicy<RObject_Impl<StoragePolicy> >,                
    public SlotProxyPolicy<RObject_Impl<StoragePolicy> >,              
    public AttributeProxyPolicy<RObject_Impl<StoragePolicy> >,         
    public RObjectMethods< RObject_Impl<StoragePolicy> >
{
     ...
}

typedef RObject_Impl<PreserveStorage> RObject ;

So RObject is the instantiation of RObject_Impl where the storage is controlled by the PreserveStorage template. This is policy design class. If you're curious about this, you can look into the Modern C++ design book.

For most of use it changes nothing. You'll still be able to use RObject or any Rcpp API class as before.

What the storage policy controls is protection of the underlying SEXP from the garbage collector. The PreserveStorage template is used as default. It protects the SEXP the same way we did before, i.e. with R_PreserveObject/R_ReleaseObject.

But we could imagine to create a LocalStorage template suitable for StoragePolicy that would use the PROTECT/UNPROTECT stack instead, or another template doing no protection at all. It sometimes makes sense when we know an object is already protected. For example symbols don't need protection since they're cached.

Anyway, so classes from the Rcpp API are now instantiations of policy based templates.

Registered functions

Sometimes, we could not move things to templates or to inline functions, because we need the function to exist only once, right inside Rcpp. For this we've used R's mechanism for registering functions. The mechanism is described in writing R extensions.

The idea is that an actual function is compiled in the shared library of Rcpp and when Rcpp is loaded, the function is registered by using the R_RegisterCCallable

void registerFunctions(){
    using namespace Rcpp ;
    using namespace Rcpp::internal ;
    
    #define RCPP_REGISTER(__FUN__) R_RegisterCCallable( "Rcpp", #__FUN__ , (DL_FUNC)__FUN__ );
    RCPP_REGISTER(rcpp_get_stack_trace)
    ...
}

Then in Rcpp headers, we do condition compiling depending on whether we are compiling Rcpp or something else:

#if defined(COMPILING_RCPP)
    // just a declaration. will be defined in one of Rcpp's .cpp files
    SEXP rcpp_get_stack_trace() ;
#else
    #define GET_CALLABLE(__FUN__) (Fun) R_GetCCallable( "Rcpp", __FUN__ )
    
    // defining it right here
    inline SEXP rcpp_get_stack_trace(){
        // the actual function pointer type
        typedef SEXP (*Fun)(void) ;

        // retrieve the function with R_GetCCallable
        static Fun fun = GET_CALLABLE("rcpp_get_stack_trace") ;

        // call it
        return fun() ;
    }
    
#endif

In the future, this boiler plate code might be generated automatically by an Rcpp::register attribute, but for now it is hand crafted.