Skip to content

Dynamic C Symbols and Embedding Suggestion

3 messages · Byron Ellis, Duncan Temple Lang

#
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. 

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
_._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._
#
Byron Ellis wrote:
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.

 D.
-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-
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
_._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._
#
On Mon, 14 May 2001, Duncan Temple Lang wrote:

            
I'm not thinking so much in terms of random C functions that we may want
to call from R--- but rather functions which are intended to be called
from R but need to be in the host application for one reason or another.
Two immediate examples come to my mind (at least on the Windows
platform--you should be able to get around this first one in X and the
second doesn't apply to *NIX platforms :-)):

1. GUI interfaces a la S-Plus. That is to say the ability to add menus or
other things (graphics devices, etc.) to the primary GUI interface from R.
For instance, I have a piece of code that lets me attach arbitrary R
expressions to menu items which are then executed by taking over the
console interface temporarily (with the option to suppress output). In the
case of the official R GUI obviously you don't have this problem since it
is relatively tightly coupled to the core engine and the executable itself
doesn't really do anything.

2. An ActiveX control (see, doesn't apply ;-)). In this situation
(specifically embedding R in Internet Explorer to match the SNetscape
control since IE has something like 97% of the Windows desktop
marketshare) I can't use the hack described in my original email since
GetModuleHandle(NULL) returns IEXPLORE.EXE not a handle to the COM DLL
(unfortunate, but true). In this case I'd like to add some links between
the Javascript event model and R so I need to expose the fire*
functionality.
Nifty.
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
_._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._