callme compiles inline C code and generates wrappers so that the C code can be easily called from R.
Features:
- Compile inline C code (or code from a file) and makes it immediately (and easily!) available to R.
- Accepts complete C code - including function declaration and header
#include
directives. - Explicit handling for
CFLAGS
,PKG_CPPFLAGS
andPKG_LIBS
for setting compiler flags, C pre-processor flags, and library linking flags, respectively. - Generates R functions to call the compiled C functions.
- Multiple function definitions allowed in a single code block.
What’s in the box
-
compile(code, CFLAGS, PKG_CPPFLAGS, PKG_LIBS, env, verbosity)
compile the Ccode
and assign R functions into the nominatedenv
in R. C code could be as a string or in a file. -
cflags_default()
the default C compiler flags R uses on your system
Installation
You can install from GitHub with:
# install.package('remotes')
remotes::install_github('coolbutuseless/callme')
Example
The following example compiles a code snippet into a C library and creates a wrapper function in R (of the same name) which can be used to call the compiled code.
library(callme)
code <- "
#include <R.h>
#include <Rinternals.h>
// Add 2 numbers
SEXP add(SEXP val1, SEXP val2) {
return ScalarReal(asReal(val1) + asReal(val2));
}
// Multiply 2 numbers
SEXP mul(SEXP val1, SEXP val2) {
return ScalarReal(asReal(val1) * asReal(val2));
}
// sqrt elements in a vector
SEXP new_sqrt(SEXP vec) {
SEXP res = PROTECT(allocVector(REALSXP, length(vec)));
double *res_ptr = REAL(res);
double *vec_ptr = REAL(vec);
for (int i = 0; i < length(vec); i++) {
res_ptr[i] = sqrt(vec_ptr[i]);
}
UNPROTECT(1);
return res;
}
"
# compile the code
compile(code)
# Call the functions
add(99.5, 0.5)
mul(99.5, 0.5)
new_sqrt(c(1, 4, 25, 999))
Linking against an installed library
In this example we want to get the version of the zstd
library (which has already been installed on the computer), and return it as a character string.
We need to tell R when compiling the code:
- to look in the
/opt/homebrew/include
directory forzstd.h
. - to look for the actual
zstd
library in/opt/homebrew/lib
. - to link to the
zstd
library (-lzstd
)
Note: This code works for zstd
installed via homebrew
on macOS. Paths will be different for other operating systems.
code <- r"(
#include <R.h>
#include <Rinternals.h>
#include "zstd.h"
SEXP zstd_version() {
return mkString(ZSTD_versionString());
}
)"
# Compile the code
compile(code,
PKG_CPPFLAGS = "-I/opt/homebrew/include",
PKG_LIBS = "-L/opt/homebrew/lib -lzstd")
# Call the function
zstd_version()
References
- Hadley’s R internals.
- Advanced R Book has a specfic chapter or R’s interface to C.
- Ella Kay’s UserR2024 conference presentation: “C for R users”
- Book: Deep R Programming
- Davis Vaughan’s Now you C me
- c3po
- R Native API
R project official documentation
- Writing R extensions Section 5 System and foreign language interfaces
- R internals