Is it possible to call C (or C++) functions from an existing R package, within additional C code?
For example, the function marginTable()
in my package rje
uses a C function of the same name. I want to create a new package which contains more C code, some of which could make use of the C version of marginTable()
. Can I call that function from within the new C code, other than just by copying the C code to the new file and package?
Or is it just bad practice to use internal code like this?
[Various people have asked about calling the compiled code from another R package, but all want to do it within R, not with C code.]
The R_RegisterCCallable
/ R_GetCCallable
solution pointed to by @BrodieG is probably better than the one below, at least when one can modify the package where registration is required and where the choice of function to call is straight-forward (the example below came from more-or-less complicated R code that chooses one of several functions to pass to C, much like lapply's FUN argument, where choice of function is much easier to implement in R than C). Also relevant is Linking to other packages when wanting to expose / access many functions.
A related possibility is to register your C functions in the rje package, using something like, in R_init_rje.c
#include <Rinternals.h>
#include <R_ext/Rdynload.h>
SEXP rje(SEXP who) {
Rprintf("Hello %s\n", CHAR(STRING_ELT(who, 0)));
return R_NilValue;
}
static const R_CallMethodDef callMethods[] = {
{".rje", (DL_FUNC) &rje, 1},
{NULL, NULL, 0}
};
void R_init_rje(DllInfo * info)
{
R_registerRoutines(info, NULL, callMethods, NULL, NULL);
}
and in the NAMESPACE
useDynLib(rje, .registration=TRUE)
The address of the C-level entry point is then available in R as
rje_c = getNativeSymbolInfo(".rje", PACKAGE="rje")
and can be used in your other package by using this as an argument to a C function, e.g.,
.Call(.use_rje, rje_c$address, "A User")
with
#include <Rinternals.h>
#include <R_ext/Rdynload.h>
/* convenience definition of the function template */
typedef SEXP RJE_C_FUN(SEXP who);
SEXP use_rje(SEXP rje_c_fun, SEXP who) {
/* retrieve the function pointer, using an appropriate cast */
RJE_C_FUN *fun = (RJE_C_FUN *) R_ExternalPtrAddr(rje_c_fun);
return fun(who);
}
It's too clumsy to illustrate this in a package, but the principle is illustrated by the following file rje.c
#include <Rinternals.h>
#include <R_ext/Rdynload.h>
/* convenience definition of the function template */
typedef SEXP RJE_C_FUN(SEXP who);
SEXP rje(SEXP who) {
Rprintf("Hello '%s'\n", CHAR(STRING_ELT(who, 0)));
return R_NilValue;
}
SEXP use_rje(SEXP rje_c_fun, SEXP who) {
/* retrieve the function pointer, using an appropriate cast */
RJE_C_FUN *fun = (RJE_C_FUN *) R_ExternalPtrAddr(rje_c_fun);
return fun(who);
}
static const R_CallMethodDef callMethods[] = {
{".rje", (DL_FUNC) &rje, 1},
{".use_rje", (DL_FUNC) &use_rje, 2},
{NULL, NULL, 0}
};
void R_init_rje(DllInfo * info)
{
R_registerRoutines(info, NULL, callMethods, NULL, NULL);
}
Compile with R CMD SHLIB rje.c
, and use as
> dyn.load("rje.so")
> .Call(".use_rje", getNativeSymbolInfo("rje")$address, "A User")
Hello 'A User'
NULL
Yes it is possible, and yes there are simple examples.
See for example our (recent-ish)
RApiSerialize package
which provides serialize()
for use by other CRAN packages such as our
RcppRedis package.
Other packages do it as well:
In all examples does the exporter declares what is being made available, and the importer declares it as used.
In that setup, R can then do the rest -- without explicit linking.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With