Dynamic linking to binary code from other packages??
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