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

Charles Danko dankoc at gmail.com
Thu Nov 13 20:42:53 CET 2008


Dear list,

Thanks very much for all of the detailed responses!  I am beginning to
understand how all of this can work, and learning quite a bit about
the C language in the process!

Can this be applied to either C++ classes or to member functions of a
class?   Please forgive my lack of general C/C++ knowledge, which may
be abundantly clear in my specific questions:

It seems pretty clear that one may not register a pointer to a class
declaration and share it in this way?!

Will it work to register a pointer to a class' member functions, using
the code described by either Jeff or Simon?  I looked into this, and
am pretty sure that it can not work.  (Here is a good article on
registering a pointer to a class' member function:
http://www.goingware.com/tips/member-pointers.html).

So, is there any way to share either C++ classes or class member
functions with another package in R?

Again, please do forgive my inexperience.

Best,
Charles

On Thu, Nov 13, 2008 at 9:15 AM, Simon Urbanek
<simon.urbanek at r-project.org> wrote:
> On Nov 12, 2008, at 23:16 , Jeff Ryan wrote:
>
>> 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);
>> }
>> ...
>>
>
> FWIW this is not exactly the most efficient way to do it. It's much easier
> to do it the commonly used way of setting the function pointers directly
> (taking the situation above):
>
> CHM_DN(*M_as_cholmod_dense)(CHM_DN,SEXP);
>
> in the initialization function of the package populate all the pointers:
>
> M_as_cholmod_dense = (CHM_DN(*)(CHM_DN,SEXP)) R_GetCCallable("Matrix",
> "as_cholmod_dense");
>
> By setting the functions right away you save yourself the trouble of
> checking it on every call and using a function call twice. This allows you
> to use the function transparently in your code, so you don' t need any
> function wrappers:
>
> x = M_as_cholmod_dense(a, b);
>
> This is pretty much standard C programming, so the above should be quite
> obvious (I hope).
>
> The only reason to do it the complicated way above is if you want to do some
> extra processing in the wrapper function so your function pointer is not
> visible from outside the function.
>
> Cheers,
> Simon
>
>
>> 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
>>
>> ______________________________________________
>> R-devel at r-project.org mailing list
>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>
>>
>
>



More information about the R-devel mailing list