[Rd] Dynamic C Symbols and Embedding Suggestion

Duncan Temple Lang duncan@research.bell-labs.com
Mon, 14 May 2001 08:53:29 -0400

Byron Ellis wrote:
> Hello, I've been playing around w/ the new dynamic C symbol stuff (thank
> you for doing that!) in the, um, 5/11/01 R-devel package and, unless I've
> missed something incredibly obvious, there doesn't appear to be a
> mechanism for registering functions of an embedding executable. It seems
> like this would be a Good Thing to have. 

Hi Byron,

You are correct. There is no way to explicitly make the symbols of the
host/embedding application available to R. As you point out, the code
below looks like the second half of the AddDLL() routine. And we
should arrange AddDLL() to perform the loading of the code and then
call another routine to register it at the end of the LoadedDLL
array. In this way, the host application can also call this second
routine itself (or even override it, if that should every be useful).

One reason for this omission is that I haven't yet found a need for
it. But the embedding R in another application is still reasonably recent
(at least on Unix), so the more we found out about what is needed, the better.

Here are some reasons I think we haven't needed to be able to access
the symbols in the host application.

Firstly, most C routines are not directly callable from R. Certainly
those accessed by .Call, .External require knowledge of R. Because of this
explicit dependency on libR.so, and the need to ensure that
they are called only after R has been initialized makes it more sensible
to load them as a regular R package as part of the post-initialization of R.

Routines accessed via .C and .Fortran typically need an extra layer
of indirection to handle arguments as they come from R to the native code.
For example, an S call
  .C("foo", x, length(x))
might map to the C routine
   void foo(double *x, Sint *len) {
      realFoo(x, *len);

The real routine is realFoo() and we have to convert the length
argument to a scalar rather than a pointer to a scalar.  In this
setup, R need never know about realFoo() explicitly. It will be
resolved by the dynamic loader (for better or worse).  Luke and I (at
the very least) are keen to avoid the dynamic loader and to have
people explicitly link against libraries as it avoids
platform-specific nuances of the loader that are very hard to control.

The examples where it is useful for R to be able to see symbols in the
host application are those that take no arguments and whose value is
ignored. Are there any interesting examples of this? 

Thanks for pointing out the idea of separating the two task currently
performed by AddDLL(). I'll separate them later today.


> Since I'm doing most of my work in Windows at the moment (all of the
> embedding apps I'm working on are Windows based so I've not really messed
> w/ the *NIX embedding stuff) I did a little experiment to see if I could
> bind my primary executable. Adding the code below to Rdynload.c seemed to
> work (in the Windows case). You'll note the remarkable resemblance to
> AddDLL. :-) My test code calls this to set up its function list just after
> R_ReplDllinit() just before entering the do1-loop--- though perhaps this
> should be integrated into some part of the setup procedure for embedding
> apps.
> DllInfo* R_RegisterEmbeddedExecutable(HINSTANCE handle,char* path)
> {
> 	char* dpath,*name,DLLname[PATH_MAX], *p;
> 	DeleteDLL(path);
> 	if(CountDLL == MAX_NUM_DLLS) {
> 		strcpy(DLLerror,"unable to register embedded executable.
> too many libraries");
> 		return 0;
> 	}
>     dpath = malloc(strlen(path)+1);
>     if(dpath == NULL) {
> 	strcpy(DLLerror,"Couldn't allocate space for 'path'");
> 	return 0;
>     }
>     strcpy(dpath, path);
>     if(R_osDynSymbol->fixPath)
> 	R_osDynSymbol->fixPath(dpath);
>     p = strrchr(dpath, R_DIR_SEPARATOR); 
>     if(!p) p = dpath; else p++;
>     strcpy(DLLname, p);
>     p = strchr(DLLname, '.');
>     if(p) *p = '\0';
>     name = malloc(strlen(DLLname)+1);
>     if(name == NULL) {
> 	strcpy(DLLerror,"Couldn't allocate space for 'name'");
> 	free(dpath);
> 	return 0;
>     }
>     strcpy(name, DLLname);
>     LoadedDLL[CountDLL].path = dpath;
>     LoadedDLL[CountDLL].name = name;
>     LoadedDLL[CountDLL].handle = handle;
>     LoadedDLL[CountDLL].numCSymbols = 0;
>     LoadedDLL[CountDLL].numCallSymbols = 0;
>     LoadedDLL[CountDLL].numFortranSymbols = 0;
>     LoadedDLL[CountDLL].CSymbols = NULL;
>     LoadedDLL[CountDLL].CallSymbols = NULL;
>     LoadedDLL[CountDLL].FortranSymbols = NULL;
> 	return LoadedDLL + (CountDLL++);
> }
> Byron Ellis (bellis@hsph.harvard.edu)
> -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-
> r-devel mailing list -- Read http://www.ci.tuwien.ac.at/~hornik/R/R-FAQ.html
> Send "info", "help", or "[un]subscribe"
> (in the "body", not the subject !)  To: r-devel-request@stat.math.ethz.ch
> _._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._
r-devel mailing list -- Read http://www.ci.tuwien.ac.at/~hornik/R/R-FAQ.html
Send "info", "help", or "[un]subscribe"
(in the "body", not the subject !)  To: r-devel-request@stat.math.ethz.ch