[Rd] Dynamic linking to binary code from other packages??

Jeff Ryan jeff.a.ryan at gmail.com
Thu Nov 13 05:16:56 CET 2008


Charles,

> I've looked through the "Writing R Extensions" manual, and can't find
> this documented very clearly.  A previous question to the list gave me
> the very kind response pasted below.  I've looked at the suggested
> examples (lme4 using C functions from Matrix).

It isn't really "clearly" explained.  I will give it a try though.

You can't use compiled/packaged functions from within _your_ compiled
code unless the package that you are referring to (affxparser) makes
them available for export.

If affxparser doesn't do this you are back to Dirk's method.

For the sake of others who have gone down this road I will explain
what I know, and probably in the process learn what I may be doing
wrong. (all of this I learned by reading the sources for R and lme4
and Matrix).

Matrix has a copy of the Matrix.h header in its /inst directory,
specifically /inst/include/Matrix.h

This gets installed as /include/Matrix.h, which is where LinkingTo
links to during compilation.

You (or the affxparser author) will also need a handful of C calls
that are complementary to ones in the package you are getting the
functions from.

An example from Matrix:

/include/Matrix_stubs.c contains

...
CHM_DN attribute_hidden
M_as_cholmod_dense(CHM_DN ans, SEXP x)
{
    static CHM_DN(*fun)(CHM_DN,SEXP) = NULL;
    if(fun == NULL)
	fun = (CHM_DN(*)(CHM_DN,SEXP))
	    R_GetCCallable("Matrix", "as_cholmod_dense");
    return fun(ans, x);
}
...

The above is far from obvious, so I will try my best to explain.

With respect to the R_GetCCallable call, Writing R Extensions says:

"     p_myCfun = R_GetCCallable("packA", "myCfun");
The author of packB is responsible for ensuring that p_myCfun has an
appropriate declaration. What exactly that means was hard to determine
at first."

Taking the first line, the first CHM_DN is the function return type
(could be int, SEXP, etc), and the second (along with the SEXP) is the
argument type(s).

Generalized you'd have something like:

SEXP attribute_hidden
FUNNAME(SEXP ans, SEXP x)
{
    static SEXP(*fun)(SEXP,SEXP) = NULL;
    if(fun == NULL)
	fun = (SEXP(*)(SEXP,SEXP))
	    R_GetCCallable("PACKAGE", "FUNCTION");
    return fun(ans, x);
}

lme4 then simply "#include"s this .c file in a file
/src/local_stubs.c, which is compiled right along side of the src code
in lme4.

At this point you can then use the functions that are
'exported/registered' as you would a C function defined in your own
package.

The other side of this is what the Matrix (affxparser?) package needs
to do.  It needs a registration routine that specifically registers
the routines as callable using:
  R_RegisterCCallable  (which is documented in Writing R Extensions)

In Matrix this is in /src/init.c via a macro.

A simpler in-progress bit of code can be found in the /dev branch of
xts on R-forge.  Take a look at

http://r-forge.r-project.org/scm/?group_id=118

/dev/src/init.c
/dev/inst/include/xts.h
/dev/inst/include/xts_stubs.c

As far as C++ goes, I would suspect the Matrix package again has all
the bits you are looking for.

HTH
Jeff




-- 
Jeffrey Ryan
jeffrey.ryan at insightalgo.com

ia: insight algorithmics
www.insightalgo.com



More information about the R-devel mailing list