From duncan at wald.ucdavis.edu  Tue May  1 19:56:05 2007
From: duncan at wald.ucdavis.edu (Duncan Temple Lang)
Date: Tue, 1 May 2007 10:56:05 -0700
Subject: [Rd] Embedding R and registering routines
In-Reply-To: <46375AC9.5000201@vanderbilt.edu>
References: <46375AC9.5000201@vanderbilt.edu>
Message-ID: <20070501175605.GS30532@wald.ucdavis.edu>

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



-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
Url : https://stat.ethz.ch/pipermail/r-devel/attachments/20070501/29d34b5e/attachment.bin 


[Rd] Embedding R and registering routines
Duncan Temple Lang