Skip to contents

Functions to call pre-compiled code with support for most C argument and return types.

Usage

dyncall( address, signature, ... , callmode = "default" )
dyncall.default      ( address, signature, ... )
dyncall.cdecl        ( address, signature, ... )
dyncall.stdcall      ( address, signature, ... )
dyncall.thiscall     ( address, signature, ... )
dyncall.thiscall.msvc( address, signature, ... )
dyncall.thiscall.gcc ( address, signature, ... )
dyncall.fastcall     ( address, signature, ... )
dyncall.fastcall.msvc( address, signature, ... )
dyncall.fastcall.gcc ( address, signature, ... )

Arguments

address

external pointer to foreign function.

signature

character string specifying the call signature that describes the foreign function type. See details.

callmode

character string specifying the calling convention. This argument has no effect on most platforms, but on Microsoft Windows 32-Bit Intel/x86 platforms. See details.

...

arguments to be passed to the foreign function. Arguments are converted from R to C values according to the call signature. See details.

Details

dyncall offers a flexible Foreign Function Interface (FFI) for the C language with support for calls to arbitrary pre-compiled C function types at run-time. Almost all C fundamental argument- and return types are supported including extended support for pointers. No limitations is given for arity as well. In addition, on the Microsoft Windows 32-Bit Intel/x86 platform, it supports multiple calling conventions to interoperate with System DLLs. Foreign C function types are specified via plain text type signatures. The foreign C function type of the target function is known to the FFI in advance, before preparation of the foreign call via plain text type signature information. This has several advantages: R arguments do not need to match exactly. Although R lacks some fundamental C value types, they are supported via coercion at this interface (e.g. C float and 64-bit integer). Arity and argument type checks help make this interface type-safe to a certain degree and encourage end-users to use interface from the interpreter prompt for rapid application development.

The foreign function to be called is specified by address, which is an external pointer that is obtained from dynsym or getNativeSymbolInfo.

signature is a character string that specifies the formal argument-and-return types of the foreign function using a call signature string. It should match the function type of the foreign function given by address, otherwise this can lead to a fatal R process crash.

The calling convention is specified explicitly via function dyncall using the callmode argument or implicitly by using .dyncall.* functions. See details below.

Arguments passed via ... are converted to C according to signature ; see below for details.

Given that the signature matches the foreign function type, the FFI provides a certain level of type-safety to users, when exposing foreign functions via call wrappers such as done in dynbind and dynport. Several basic argument type-safety checks are done during preparation of the foreign function call: The arity of formals and actual arguments must match and they must be compatible as well. Otherwise, the foreign function call is aborted with an error before risking a fatal system crash.

Value

Functions return the received C return value converted to an R value. See section ‘Call Signature’ below for details.

Type Signature

Type signatures are used by almost all other signature formats (call, library, structure and union signature) and also by the low-level (un)-packing functions.

The following table gives a list of valid type signatures for all supported C types.

Type SignatureC typevalid R argument typesR return type
'B'boolraw,logical,integer,doublelogical
'c'charraw,logical,integer,doubleinteger
'C'unsigned charraw,logical,integer,doubleinteger
's'shortraw,logical,integer,doubleinteger
'S'unsigned shortraw,logical,integer,doubleinteger
'i'intraw,logical,integer,doubleinteger
'I'unsigned intraw,logical,integer,doubledouble
'j'longraw,logical,integer,doubledouble
'J'unsigned longraw,logical,integer,doubledouble
'l'long longraw,logical,integer,doubledouble
'L'unsigned long longraw,logical,integer,doubledouble
'f'floatraw,logical,integer,doubledouble
'd'doubleraw,logical,integer,doubledouble
'p'C pointerany vector,externalptr,NULLexternalptr
'Z'char*character,NULLcharacter or NULL
'x'SEXPanyany
'v'voidinvalidNULL
'*' ...C type* (pointer)any vector,externalptr,NULLexternalptr
"*<" typename '>'typename* (pointer)raw,externalptrexternalptr

The last two rows of the table the above refer to typed pointer signatures. If they appear as a return type signature, the external pointer returned is a S3 struct object. See cdata for details.

Call Signatures

Call Signatures are used by dyncall and ccallback to describe foreign C function types. The general form of a call signature is as following:

(argument-type)*')'return-type

The calling sequence given by the argument types signature is specified in direct left-to-right order of the formal argument types defined in C. The type signatures are put in sequence without any white space in between. A closing bracket character ')' marks the end of argument types, followed by a single return type signature.

Derived pointer types can be specified as untyped pointers via 'p' or via prefix '*' following the underlying base type (e.g. '*d' for double *) which is more type-safe. For example, this can prevent users from passing a numeric R atomic as int* if using '*i' instead of 'p'.

Dervied pointer types to aggregate union or struct types are supported in combination with the framework for handling foreign data types. See cdata for details. Once a C type is registered, the signature *<typename> can be used to refer to a pointer to an aggregate C object type*. If typed pointers to aggregate objects are used as a return type and the corresponding type information exists, the returned value can be printed and accessed symbolically.

Here are some examples of C function prototypes and corresponding call signatures:

C Function PrototypeCall Signature
doublesqrt(double);"d)d"
doublednorm(double,double,double,int);"dddi)d"
voidR_isort(int*,int);"pi)v" or "*ii)v"
voidrevsort(double*,int*,int);"ppi)v" or "*d*ii)v"
intSDL_PollEvents(SDL_Event *);"p)i" or "*<SDL_Event>)i"
SDL_Surface*SDL_SetVideoMode(int,int,int,int);"iiii)p" or "iiii)*<SDL_Surface>"

Calling convention

Calling Conventions specify ‘how’ sub-routine calls are performed, and, ‘how’ arguments and results are passed, on machine-level. They differ significantly among families of CPU Architectures as well as OS and Compiler implementations.

On most platforms, a single "default" C Calling Convention is used. As an exception, on the Microsoft Windows 32-Bit Intel/x86 platform several calling conventions are common. Most of the C libraries still use a "default" C ( also known as "cdecl" ) calling convention, but when working with Microsoft System APIs and DLLs, the "stdcall" calling convention must be used.

It follows a description of supported Win32 Calling Conventions:

"cdecl"

Dummy alias to default

"stdcall"

C functions with stdcall calling convention. Useful for all Microsoft Windows System Libraries (e.g. KERNEL32.DLL, USER32.DLL, OPENGL32.DLL ...). Third-party libraries usually prefer the default C cdecl calling convention.

"fastcall.msvc"

C functions with fastcall calling convention compiled with Microsoft Visual C++ Compiler. Very rare usage.

"fastcall.gcc"

C functions with fastcall calling convention compiled with GNU C Compiler. Very rare usage.

"thiscall"

C++ member functions.

"thiscall.gcc"

C++ member functions compiled with GNU C Compiler.

"thiscall.msvc"

C++ member functions compiled with Microsoft Visual C++ Compiler.

As of the current version of this package and for practical reasons, the callmode argument does not have an effect on almost all platforms, except that if R is running on Microsoft Windows 32-Bit Intel/x86 platform, dyncall uses the specified calling convention. For example, when loading OpenGL across platforms, "stdcall" should be used instead of "default", because on Windows, OpenGL is a System DLL. This is very exceptional, as in most other cases, "default" (or "cdecl", the alias) need to be used for normal C shared libraries on Windows.

At this stage of development, support for C++ calls should be considered experimental. Support for Fortran is planed but not yet implemented in dyncall.

Portability

The implementation is based on the dyncall library (part of the DynCall project).

The following processor architectures are supported: X86 32- and 64-bit, ARM v4t-v7 oabi/eabi (aapcs) and armhf including support for Thumb ISA, PowerPC 32-bit, MIPS 32- and 64-Bit, SPARC 32- and 64-bit; The library has been built and tested to work on various OSs: Linux, Mac OS X, Windows 32/64-bit, BSDs, Haiku, Nexenta/Open Solaris, Solaris, Minix and Plan9, as well as embedded platforms such as Linux/ARM (OpenMoko, Beagleboard, Gumstix, Efika MX, Raspberry Pi), Nintendo DS (ARM), Sony Playstation Portable (MIPS 32-bit/eabi) and iOS (ARM - armv6 mode ok, armv7 unstable). In the context of R, dyncall has currently no support for PowerPC 64-Bit.

Note

The target address, calling convention and call signature MUST match foreign function type, otherwise the invocation could lead to a fatal R process crash.

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

See also

dynsym and getNativeSymbolInfo for resolving symbols, dynbind for binding several foreign functions via thin call wrappers, .C for the traditional FFI to C.

Examples

# \donttest{
mathlib <- dynfind(c("msvcrt","m","m.so.6"))
x <- dynsym(mathlib,"sqrt")
dyncall(x, "d)d", 144L)
#> [1] 12
# }