knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.path = "man/figures/README-", out.width = "100%" )
The goal of anrpackageusingc is to demonstrate the structure of calling a C function in a package. For a guide on actually writing C code using the R API, see the appropriate chapter of the R Packages book, the appropriate chapter of Avanced R and the r-internals collection of unofficial R API documentation.
You can install the development version from GitHub with:
# install.packages("remotes") remotes::install_github("paleolimbot/anrpackageusingc")
This package is designed so that you can fork, clone, and modify the C code.
This package contains one function that calls a C function.
library(anrpackageusingc) my_function("an input object")
The R function my_function()
lives in R/my-function.R
:
my_function <- function(input) { .Call(anrpackageusingc_c_my_function, input) }
The C function anrpackageusingc_c_my_function()
lives in src/my-function.c
. I use the prefix anrpackageusingc_c_...()
when I'm declaring a function that will get registered and called from R because I have a tool that generates src/init.c
using a regex and because I read something a long time ago that suggested that exported C functions might need unique names (I don't know if this is still true). You can call the functions anything you want but it's helpful if you have a naming convention for all the functions of this type in your package.
SEXP anrpackageusingc_c_my_function(SEXP input_sexp) { return R_NilValue; }
It's registered in src/init.c
. The 1
at the end of the registration line is because the function accepts one argument; the NULL, NULL, 0
is to signify the end of the array (kind of like how \0
signifies the end of a null-terminated string).
SEXP anrpackageusingc_c_my_function(SEXP input_sexp); static const R_CallMethodDef CallEntries[] = { {"anrpackageusingc_c_my_function", (DL_FUNC) &anrpackageusingc_c_my_function, 1}, {NULL, NULL, 0} }; void R_init_anrpackageusingc(DllInfo *dll) { R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); R_useDynamicSymbols(dll, FALSE); }
If you want to add a function, you'll have to copy the definition and a line to CallEntries
. The function can live in any .c
file of your choosing.
Finally, we need to add the useDynLib()
line in the NAMESPACE
. I use the automatically populated roxygen line that happens when you call usethis::use_package_doc()
and usethis::use_c("some-c-filename")
for this.
#' @useDynLib anrpackageusingc, .registration = TRUE
There are some variations on these components but this should get you started. From scratch, I created this package using a bunch of usethis helpers:
create_package("anrpackageusingc") # modify Title and Description in DESCRIPTION file use_package_doc() use_c("my-function") # write skeleton of anrpackageusingc_c_my_function() that returns R_NilValue use_c("init.c") # copy boilerplate from a previous package using C like this one use_r("my-function") # write wrapper using .Call() use_test("my-function") # write a test that calls my_function() use_git() use_github()
Modify the body of anrpackageusingc_c_my_function()
to (1) print something using Rprintf()
and (2) return an R object. The easiest R objects to create are strings (Rf_mkString("some text")
), integers (Rf_ScalarInteger(1234)
), and doubles (Rf_ScalarReal(1234)
).
Add a new C function called anrpackageusingc_c_my_new_function()
that accepts two parameters (SEXP item1, SEXP item2
) and returns the first one. Add the function to init.c
and create an R wrapper called my_new_function()
.
Add a new C function in a new file that adds 2 to a numeric vector (you can use the example from the "Accessing vector data" section of the appropriate chapter of Avanced R). Make sure you can call it from R!
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.