Jitao David Zhang, 2021.01.06
How to use C codes in another R package? A demo.
The package pkgIn links to native routines pkgOut_func and pkg_version exported by pkgOut. Please check both packages out to see the details.
The examples were built by following the instructions given in the Writing R Extensions manual.
A few details, however, may need highlighting, because I stumbled upon them on the first attempts.
Keep in mind that we use pkgOut to refer to the package that exports a native routine and pkgIn to refer to the package that uses a foreign routine.
- Use
R_RegisterCCallableto register the function in the pkgOut package. They do not have to be registered routines called by .C/.Call/.Fortran/.External. Rather, they can be any C function. importorimportFrom(or@importin roxygen2) must be called in the pkgIn package so that the exported function from the pkgOut package can be found.- Add
LinkingTo: pkgOutin theDESCRIPTIONfile in the incoming package. This will allow linking native routines. - Use
(TYPE(\*)(PARAMETER TYPE)) R_GetCCallable("pkgOut", "pkgOut_func")inR_init_pkgInto retrieve the function in the pkgIn package. - DO NOT include the header file of outgoing package in the init file of incoming package. Otherwise, an error message complaining left-hand expression assignment will be raised.
- Only functions returning
SEXPcan be called by.Call, otherwise the memory will not be mapped and the R session will die ugly. This also apply tovoidfunctions. - Check
NAMESPACEin case a.Callfunction cannot be found. Particularly whenpackage.skeletonwas used to generate the package structure and then roxygen2 was used, in which case the NAMESPACE file is not overwritten by default. - Use
SET_STRING_ELT(SEXP object, 0, mkChar(char \*))to convert C strings to R strings, andCHAR(STRING_ELT(SEXP object, 0))to do the reverse, namely to convert R strings to constant (const) C strings.
This is not the first attempt to create a minimalistic example of linking native
routines in R for teaching and demonstration purposes. For instance, a project
with similar purposes was created by Davis Vaughan and can be found here:
https://github.com/DavisVaughan/cexport. Canonical examples that can be found in
the Writing R Extensions and other online resources that demonstrate
between-package native-routine linking include packages zoo and xts, xts
and RcppXts (with a write-up from 2013 available
here), lme4 and Matrix, as well
as expm and Matrix.
This piece of work is different from real-life packages, because it uses
minimalistic examples to demonstrate the purpose and the basic techniques,
without involving non-essential commands relevant for native routine linking.
Compared with the cexport package created by Davis Vaughan, the demo packages
here are more recent (compatible with R-4.0), arguably more compact (because
both packages are stored in the same directory), and come with a visual element
that help readers appreciate the issue.
I thank David Vaughan, Dirk Eddelbuettel, and Jan Gorecki for providing resources, highlighting previous work and art, and offering alternative views to improve this piece of work.