[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