[Rd] Linking to native routines in other packages

Gregor Kastner gregor.kastner at wu.ac.at
Mon Jan 27 09:24:12 CET 2014


Thanks Romain for that elegant solution.

Best,
Gregor

On Wed, 22 Jan 2014 20:23:10 +0100
Romain François <romain at r-enthusiasts.com> wrote:

> Hello, 
> 
> The problem is that you have logic in both your mother and child packages.
> IMO, you should only have logic in the mother package. 
> 
> I’ve done this in a number of packages, it requires a bit of work
> initially, but not that much. 
> 
> What I’d do is have something like this in mother/inst/include/mother.h : 
> 
> #if defined(COMPILING_MOTHER)
> // just declare, will be defined in test.c
> SEXP fun(SEXP test) ; 
> #else
> inline SEXP fun(SEXP test){
>     typedef SEXP(*Fun)(SEXP); 
>     static Fun fun = (Fun)R_GetCCallable("mother", "fun") ;
>     return fun(test) ;
> }
> #endif
> 
> In your test.c file, make sure you define COMPILING_MOTHER before you
> include mother.h, something like this
> 
> #include <R.h>
> #include <Rinternals.h>
> #include <R_ext/Rdynload.h>
> #define COMPILING_MOTHER
> #include <mother.h>
> 
> SEXP fun(SEXP);
> 
> void R_init_mother(DllInfo *dll) {
>     R_RegisterCCallable("mother", "fun", (DL_FUNC) &fun);
> }
> 
> SEXP fun(SEXP test) {
>     Rprintf("fun so much fun\n");
>     return R_NilValue;
> }
> 
> So that in your child package you only have to use it, something like: 
> 
> #include <Rinternals.h>
> #include <R_ext/Rdynload.h>
> #include <mother.h>
> 
> SEXP afun(SEXP test) {
>    fun(test);
>    return R_NilValue;
> }
> 
> Note that if you only want the interface between the two packages to be at
> low level (not visible from R), then you don’t need to conform to the
> SEXP(SEXP...) interface. You can use anything you like. 
> 
> Romain
> 
> Le 22 janv. 2014 à 19:56, Gregor Kastner <gregor.kastner at wu.ac.at> a écrit :
> 
> > Hi again,
> > 
> > On Wed, 22 Jan 2014 06:39:17 -0600
> > Dirk Eddelbuettel <edd at debian.org> wrote:
> > 
> > | Working examples I know of:   
> > | 
> > |    'xts' importing two functions from 'zoo'
> > | 
> > |    'RcppXts' importing approx. ten functions from 'xts'
> > | 
> > | Maybe by comparing to these you can sort out the missing step at your
> > end.
> > 
> > Thanks Dirk for the hints; I finally got the code running. Important point
> > is that R_init_PKGNAME() is declared as extern "C" (or RcppExport, of
> > course) if using g++ in both the mother and the child package.
> > (Interestingly, dyn.load() only complains when either the mother or the
> > child package don't do so, but not if both don't do so => SEGFAULT.)
> > Since it took me almost the entire afternoon to figure that out, I'll
> > document a working example here. 
> > 
> > Scenario: We have a 'mother' package, which wants to make some C/C++
> > routines available to the 'child' package to be called directly from
> > C/C++ level. Thus, mother's 'src' cointains:
> > 
> > 
> > ********* BEGIN test.c *********
> > 
> > #include <R.h>
> > #include <Rinternals.h>
> > #include <R_ext/Rdynload.h>
> > 
> > SEXP fun(SEXP);
> > 
> > void R_init_mother(DllInfo *dll) {
> > R_RegisterCCallable("mother", "fun", (DL_FUNC) &fun);
> > }
> > 
> > SEXP fun(SEXP test) {
> > Rprintf("fun so much fun\n");
> > return R_NilValue;
> > }
> > 
> > ********** END test.c **********
> > 
> > 
> > (Note that no extern "C" is needed here because it will be compiled with
> > gcc anyway).
> > 
> > The child uses Rcpp and mother, thus has
> > 
> > 
> > ********* BEGIN DESCRIPTION *********
> > 
> > LinkingTo: mother, Rcpp
> > Depends: mother, Rcpp
> > Imports: mother, Rcpp
> > 
> > ********** END DESCRIPTION **********
> > 
> > 
> > in its DESCRIPTION file, and 
> > 
> > 
> > ********* BEGIN test.cpp *********
> > 
> > #include <Rinternals.h>
> > #include <R_ext/Rdynload.h>
> > 
> > extern "C" {
> > SEXP afun(SEXP);
> > SEXP(*fun)(SEXP);
> > 
> > void R_init_child(DllInfo *info) {
> >  fun = (SEXP(*)(SEXP)) R_GetCCallable("mother", "fun");
> > }
> > 
> > SEXP afun(SEXP test) {
> >  fun(test);
> >  return R_NilValue;
> > }
> > }
> > 
> > ********** END test.cpp **********
> > 
> > (Note that extern "C" is crucial here.) After installing mother and
> > child, we have:
> > 
> >> library(child)
> > Loading required package: mother
> > Loading required package: Rcpp
> >> .Call("afun", 123, PACKAGE="child")
> > fun so much fun
> > NULL
> >> 
> > 
> > Maybe it is of help to someone; please excuse me if I bored anyone with
> > trivialities.
> > 
> > Best,
> > Gregor
> > 
> > ______________________________________________
> > R-devel at r-project.org mailing list
> > https://stat.ethz.ch/mailman/listinfo/r-devel
> 



More information about the R-devel mailing list