rdyncall provides an R interface to the DynCall libraries. It is a low-level
Foreign Function Interface (FFI) for loading shared C libraries,
resolving symbols, calling C functions from R by signature, working with
C struct and union data, and exposing R
functions as C callback pointers.
The package is intended for developers who already know the C API they want to call and need an exploratory or dynamic binding layer from R without writing a compiled wrapper for every function.
rdyncall can call into native libraries directly from R:
generate an SDL3 binding package from DynPort metadata, open a real SDL3
window, or bind raylib drawing calls and drive a rotating 3D scene.
| SDL3 generated binding package | raylib 3D rendering from R |
|---|---|
|
|
|
|
|
remotes::install_github("hongyuanjia/rdyncall")rdyncall was previously archived on CRAN. This
repository contains the active modernization work toward a maintainable
package and current R toolchains.
Generated DynPort packages can be called through ordinary package namespaces:
dynport(SDL3, package = "SDL3")
SDL3::SDL_GetPlatform()## [1] "macOS"
You can also call a C function directly by loading a library, resolving a symbol, and providing a call signature:
library(rdyncall)
mathlib <- dynfind(c("msvcrt", "m", "m.so.6"))
sqrt_addr <- dynsym(mathlib, "sqrt")
dyncall(sqrt_addr, "d)d", 144)The signature "d)d" means one C double
argument and a C double return value. Signatures must match
the target C function type.
R functions can also be wrapped as C callback pointers:
add <- ccallback("ii)i", function(x, y) x + y)
dyncall(add, "ii)i", 20L, 3L)Foreign aggregate layouts are described once and then used through raw-backed objects:
cstruct("Rect{ssSS}x y w h;")
rect <- cdata(Rect)
rect$x <- 40
rect$y <- 60
rect$w <- 10
rect$h <- 15
rect$w * rect$h## [1] 150
The pkgdown articles are the main documentation path:
dynload(), dynunload(),
dynsym(), dynpath(), dyncount()
and dynlist() load shared libraries and inspect
symbols.dynfind() resolves common short library names across
platforms and package manager locations.dyncall() and dyncall_variadic() call C
functions using compact type signatures.dynbind() creates thin R wrappers for a group of C
functions.cstruct(), cunion(), cdata()
and as.ctype() describe and access C aggregate data.pack() and unpack() read and write
low-level C values in raw vectors or memory referenced by external
pointers.ccallback() turns an R function into a C function
pointer.dynport() builds and loads generated R packages from
DCF .dynport binding specifications.rdyncall can model ordinary C struct and
union layouts and supports several layout features needed
by real C APIs:
type[N], such as
C[4];flags:3;@packed,
@pack(n) and @align(n);For callbacks, ccallback() supports aggregate by-value
arguments and returns on the implemented x86_64 and ARM64 dyncallback
backends.
dynport() is the package-level mechanism for binding a C
API from a data file. The current implementation supports DCF
.dynport files and generates ordinary on-disk R packages
whose namespace is populated from the DynPort metadata.
The package ships one maintained DynPort example,
inst/dynports/SDL3.dynport, generated from SDL3 headers
with porter.
See the generated-binding articles for how to create DynPort metadata
for a C library, load it with dynport(), and run a non-GUI
SDL3 smoke test.
Run demo(package = "rdyncall") to list installed demos.
The package includes small examples for direct FFI calls, callbacks,
qsort, stdio, GLPK, libxml2, SDL3 and
raylib.
Some demos require system shared libraries or open GUI windows. For non-interactive environments, see the Non-GUI demos article.
See the Non-GUI demos article for XML parsing, C sorting, GLPK optimization, and stdio examples. The GUI demos article shows SDL3 and raylib examples with release-hosted media clips.
This is a low-level FFI. A wrong function address, call signature, calling convention, pointer lifetime or struct layout can crash the R process. Keep the C declaration beside the R signature when writing bindings, and hold an R reference to callback objects for as long as foreign code may call them. Read the FFI safety boundaries article before binding APIs that allocate memory, store pointers, register callbacks, or run event loops.
This repository is the active maintenance branch for modern R. Recent work has restored compilation on current toolchains, refreshed the bundled DynCall source, modernized CI, added variadic calls, improved dynamic library discovery, and expanded aggregate layout support.
rdyncall builds on the DynCall project. The DynCall libraries
make portable dynamic calls, callback bridges, and low-level library
loading possible across platforms.
This package was originally created by Daniel Adler. The current repository continues that work for modern R toolchains and expands the package with updated documentation, demos, and binding workflows.
The optional Rtinycc package by
Sounkou Mahamane Toure is also a strong companion for
rdyncall. It makes it possible to compile small C kernels
at runtime from R, while rdyncall can bind the surrounding
native libraries and call through function pointers.