Improved Foreign Function Interface (FFI) and Dynamic Bindings to C Libraries (e.g. OpenGL)
rdyncall.Rd
The package provides a cross-platform framework for dynamic binding of C libraries using a flexible Foreign Function Interface (FFI). The FFI supports almost all fundamental C types, multiple calling conventions, symbolic access to foreign C struct/union data types and wrapping of R functions as C callback function pointers. Dynamic bindings to shared C libraries are data-driven by cross-platform binding specification using a compact plain text format ; an initial repository of bindings to a couple of common C libraries (OpenGL, SDL, Expat, glew, CUDA, OpenCL, ODE, R) comes with the package. The package includes a variety of technology demos and OS-specific notes for installation of shared libraries.
Details
rdyncall offers a stack of interoperability technologies for working with foreign compiled languages using cross-platform portable abstraction methods.
For R application development, the package facilitates direct access from R to the C Application Programming Interface (API) of common libraries. This enables a new style of development: R applications can use low-level services of portable C libraries. System-level code can be implemented in R without leaving the language. C APIs can be explored from within the R interpreter. Moving the R code from one platform to the other does not involve recompilation. Ofcourse, the run-time libraries need to be installed using a standard procedure of the target Operating-System Distribution. See rdyncall-demos for details on this.
For R core development and research, the package provides an improved Foreign Function Interface (FFI) that can be used to call arbitrary foreign precompiled C code without the need for additional compilation of wrapper code. The back-end library is extendable with new calling conventions (such as Fortran,Pascal,COM,etc.. - which has not been the focus as of this release, but might be supported officially in the near futurue). Basic type-safety checks for argument passing and framework support for working with foreign C data types such as pointers, arrays, structs and wrapping of R functions into first-level C callback function pointers round up this framework.
Overview
Flexible FFI with support for almost all C types, type-safety checks and multiple calling conventions. See
dyncall
.Loading of shared libraries with automatic unload management and using direct access to OS linker. See
dynload
.Cross-platform naming and loading of shared libraries. See
dynfind
.Binding C library functions via thin call wrappers. See
dynbind
.Handling of foreign C pointer, array and struct/union data types. See
packing
andstruct
.Dynamic wrapping of R functions as C function pointers to be used in C callbacks. See
ccallback
.Dynamic bindings to standard and common C libraries and APIs (functions, variables, macro constants, enums, struct and union types). See
dynport
.
Getting Started
Several demos ranging from simple FFI calls to the C standard math library up to more complex 3D OpenGL/SDL Applications are available.
See demos(package="rdyncall")
for an overview.
Some demos require shared C libraries to be installed in the system. Please read rdyncall-demos for details.
Supported Platforms
The low-level implementation is mainly based on libraries from the DynCall Project (https://dyncall.org). The library suite is distributed as part of the package source tree.
The dyncall and dyncallback libraries implement generic low-level services with the help of a small amount of hand-written assembly code and careful modeling of the target machine's calling sequence for each platform to support.
As of version 0.6, the following processor architectures are supported:
Intel i386 32-bit and AMD 64-bit Platforms
ARM 32-bit (OABI, EABI and ARMHF ABI with support for Thumb)
PowerPC 32-bit (support for callbacks not implemented for Linux/BSD)
MIPS 32- and 64-bit (support for callbacks not yet implemented)
SPARC 32- and 64-bit (support for callbacks not yet implemented)
The DynCall libraries are tested on Linux, Mac OS X, Windows, BSD derivates and more exotic platforms such as game consoles and Plan9. Please see the details on portability for dyncall, dyncallback and dynload and the official DynCall manual for full details of the back-end. The R Package has been tested on several major R platforms. The following gives a list of comments on platforms about the status of this package.
Linux Debian 4/ppc32 , R-2.4.0 : ok, but no callbacks. |
Linux Debian 5/arm , R-2.7.0 : ok, SDL not tested. |
Linux Debian 6/x86 , R-2.12.2: ok. |
Linux Debian 6/x64 , R-2.12.2: ok. |
Linux Ubuntu 10/armv7, R-2.14 : ok. |
Linux Fedora 14/x86 : ok. |
Linux Ubuntu 12/i386 , R-2.15.1: ok. |
Mac OS X 10.4/ppc , R-2.10.0: ok. |
Mac OS X 10.6/x86 , R-2.12.2: ok. |
Mac OS X 10.6/x64 , R-2.12.2: ok. |
Mac OS X 10.7/x64 , R-2.15.1: ok. |
NetBSD 5.0/x86 : ok. |
NetBSD 5.1/x64 : ok. |
OpenBSD 4.8/x64 , R-2.7.0 : SDL failed. |
Windows XP/x86 , R-2.12.2: ok. |
Windows 7/x86 , R-2.12.2: ok. |
Windows 7/x64 , R-2.12.2: ok, use correct 64-bit SDL DLL, SDL extension not tested - see rdyncall-demos) |
FreeBSD 8.2/x86 : build ok, no tests made for X11. |
References
Adler, D. (2012) “Foreign Library Interface”, The R Journal, 4(1), 30--40, June 2012. https://journal.r-project.org/articles/RJ-2012-004/
Adler, D., Philipp, T. (2008) DynCall Project. https://dyncall.org
Examples
if (FALSE) {
# multimedia example
# load dynports for OpenGL, Simple DirectMedia library
# globals:
surface <- NULL
# init SDL and OpenGL
init <- function()
{
dynport(SDL)
dynport(GL)
if ( SDL_Init(SDL_INIT_VIDEO) != 0 ) stop("SDL_Init failed")
surface <<- SDL_SetVideoMode(320,240,32,SDL_DOUBLEBUF+SDL_OPENGL)
cat("surface dimension:", surface$w, "x",surface$h,sep="")
}
# draw blue screen
updateSurface <- function(t)
{
glClearColor(0,0,t %% 1,0)
glClear(GL_COLOR_BUFFER_BIT+GL_DEPTH_BUFFER_BIT)
SDL_GL_SwapBuffers()
}
# wait till close
mainloop <- function()
{
quit <- FALSE
evt <- cdata(SDL_Event)
base <- SDL_GetTicks() / 1000
t <- 0
while(!quit) {
updateSurface(t)
while(SDL_PollEvent(evt)) {
if ( evt$type == SDL_QUIT ) quit <- TRUE
}
now <- SDL_GetTicks() / 1000
t <- now - base
}
}
init()
mainloop()
}