From simon.urbanek at r-project.org  Thu Nov 13 15:15:59 2008
From: simon.urbanek at r-project.org (Simon Urbanek)
Date: Thu, 13 Nov 2008 09:15:59 -0500
Subject: [Rd] Dynamic linking to binary code from other packages??
In-Reply-To: <e8e755250811122016m2659ad15p8c79c0fd29a4183c@mail.gmail.com>
References: <8adccabf0810251305o3ad8483x5de5009605fbdbe1@mail.gmail.com>
	<18691.32336.501605.415161@ron.nulle.part>
	<8adccabf0811101153w6a9e93bfvd7a24138f3c6b15b@mail.gmail.com>
	<e8e755250811122016m2659ad15p8c79c0fd29a4183c@mail.gmail.com>
Message-ID: <37726678-4F42-4AC0-98EC-4481DB69F4AA@r-project.org>

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



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