[Rd] Embedding R and registering routines

Simon Urbanek simon.urbanek at r-project.org
Tue May 1 21:22:54 CEST 2007


Since I'm not sure I really understand Jeff's question this is just  
my interpretation, but I think the point was that you may want to  
register symbols *not* from a DLL but from the embedding application  
itself (e.g. like R.app GUI that embeds libR registers its entry for  
quartz.save). I would welcome a support for this, because the current  
dirty hack (don't do this at home, kids!) is to use R_getDllInfo 
("base") and append the entry instead of overwriting it. It is an  
ugly hack, but I don't think we have any API for this. Maybe a  
worthwhile endeavor would be to simply add something like R_getDllInfo 
("embedded") reserved specifically for such purposes (or "R" or  
whatever...).

Cheers,
Simon

On May 1, 2007, at 1:56 PM, Duncan Temple Lang wrote:

> Jeffrey Horner wrote:
>> Hello,
>>
>> The use of .Call and the like all depend on loading shared  
>> libraries and
>> registering routines from it. Also, .Primitive and .Internal  
>> depend on
>> routines being registered in the R binary. And applications that  
>> embed R
>> can override routines declared in Rinterfac.h, but is there a way  
>> for an
>> application embedding R to register other routines defined in the
>> application without loading a shared library or re-compiling R?
>
> I think I understand the question, and if so, the answer is yes!
>
> I have put some code near the end of the message that illustrates
> (tests) this idea.
>
> The basic idea is that after you initialize R and load your
> RApache package with its .so, you can ask for the corresponding
> DllInfo object for that RApache.so. (You need the full path.)
>
> Then, you call R_registerRoutines() with that object as the first
> argument and your collection of routines for .C, .Call, .Fortran, etc.
> And then those routines are available to R via the corresponding
> interface function.
>
> This is currently slightly strained in two ways.
>
> Firstly, R_registerRoutines() just overwrites any existing registered
> entries.  So we should have something that allows us to append to
> this. We could add something, if this is a worthwhile approach and
> others want to chime  in with comments.
>
> Also we are adding these symbols to a table to which they do not
> really belong, i.e. pretending they are the same as the routines in
> RApache.so. But it works.  Ideally, we would like to be able to create
> and add our own special type of DllInfo. A class system from an
> object-oriented language would really help here.  But we also would
> need to make this possible via the R API.
>
>
> (Another hacky, unreliable way is using global symbols.
>  It is possible for R to resolve symbols  on some platforms
>  by looking in the application's global symbol table.
>  So R could find symbols in the executable. Of course, you load
>  mod_R.so and so its symbols are not likely to be in the global symbol
>  as I doubt very much Apache loads modules globally.
>  And we would also have to bed R slightly to make this work.
> )
>
>
> main.c:
> -----------------------------
> #include <Rinternals.h>
> #include <Rembedded.h>
> #include <R_ext/Rdynload.h>
>
> void
> foo(int *x)
> {
>     fprintf(stderr, "In foo\n");
>     *x = 101;
> }
>
> SEXP
> bar(SEXP n)
> {
>     return(ScalarInteger(INTEGER(n)[0] * 2));
> }
>
> void
> unregistered()
> {
>     fprintf(stderr, "In unregistered\n");
> }
>
> static R_CallMethodDef callMethods[] = {
>     {"bar", (DL_FUNC) &bar, 1},
>     {NULL, NULL, 0}
> };
>
> static R_CMethodDef cmethods[] = {
>     {"foo", (DL_FUNC) &foo, 1}, /* type { INTSXP }*/
>     {NULL, NULL, 0}
> };
>
> void
> registerApplicationRoutinesWithR()
> {
>     DllInfo *dll;
>     dll = R_getDllInfo("/home/duncan/Rpackage/XML/libs/XML.so");
>     R_registerRoutines(dll, cmethods, callMethods, NULL, NULL);
> }
>
> int
> main(int argc, char *argv[])
> {
>     int errorOccurred = 0;
>     SEXP e;
>     Rf_initEmbeddedR(argc, argv);
>     registerApplicationRoutinesWithR();
>
>     PROTECT(e = allocVector(LANGSXP, 2));
>     SETCAR(e, Rf_install("source"));
>     SETCAR(CDR(e), mkString("test.R"));
>     R_tryEval(e, R_GlobalEnv, &errorOccurred);
>
>     return(0);
> }
>
>
> test.R:
> ---------------------------
> print(.C("foo", x= as.integer(1))$x)
> print(.Call("bar", as.integer(3)))
>
>
>
>
> GNUmakefile:
> -------------------------------------
>
> CFLAGS=-g -I$(R_HOME)/include
>
> main: main.o
> 	$(CC) -o $@ $^ -L$(R_HOME)/lib -lR
>
>>
>> The only such way I've found that comes close to a solution to  
>> this is
>> creating an RObjectTable and attaching that to the search path.
>> Assignments to variables in that environment can call the table's get
>> routine which is defined in the application, and I think that  
>> might be
>> an interesting solution for a new RApache implementation.
>>
>> For the RApache Project, the mod_R.c shared library get's loaded into
>> the apache process and its purpose is to initializes R. Next, it  
>> calls
>> 'library(RApache)' to load RApache.so, a package that implements the
>> RApache API. This two-library system works, but the implementation is
>> too complex. I'd like to simplify down to just one shared library.
>>
>> Any comments, suggestion are much appreciated.
>>
>> Thanks,
>>
>> Jeff
>> -- 
>> http://biostat.mc.vanderbilt.edu/JeffreyHorner
>>
>> ______________________________________________
>> R-devel at r-project.org mailing list
>> https://stat.ethz.ch/mailman/listinfo/r-devel
>
> -- 
> Duncan Temple Lang                duncan at wald.ucdavis.edu
> Department of Statistics          work:  (530) 752-4782
> 4210 Mathematical Sciences Bldg.  fax:   (530) 752-7099
> One Shields Ave.
> University of California at Davis
> Davis, CA 95616, USA
>
>
>
> ______________________________________________
> R-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel



More information about the R-devel mailing list