{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.
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.
This package can be installed from CRAN
install.packages('callme')
You can install the latest development version from GitHub with:
# install.package('remotes')
remotes::install_github('coolbutuseless/callme')
Pre-built source/binary versions can also be installed from R-universe
install.packages('callme', repos = c('https://coolbutuseless.r-universe.dev', 'https://cloud.r-project.org'))
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)
#> [1] 100
mul(99.5, 0.5)
#> [1] 49.75
new_sqrt(c(1, 4, 25, 999))
#> [1] 1.00000 2.00000 5.00000 31.60696
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()
#> [1] "1.5.6"
- 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
- Writing R extensions Section 5 System and foreign language interfaces
- R internals