bind

Usage

Requirements

Documentation

This extension provides a parser for a restricted subset of C and C++ that allows the easy generation of foreign variable declarations, procedure bindings and C++ class wrappers. The parser is invoked via the bind form, which extracts binding information and generates the necessary code. An example:

Provided the file foo.o contains the implementation of the class Foo, the given example could be compiled like this (assuming a UNIX like environment):

% csc test-foo.scm foo.o -c++

To use the C++ interface, the coops extension is needed. Additionally, the class <c++-object> must be available, which is provided in the cplusplus-object extension.

To use this facility, you can either use the syntactic forms provided by the bind extension or run the chicken-bind standalone program to process a C/C++ file and generate a file containing wrapper code which then can be compiled with the CHICKEN compiler.

As a debugging aid, you can pass -debug F to the Scheme compiler to see the generated wrapper code.

chicken-bind accepts a number of command-line options to enable/disable various options, enter

% chicken-bind -help

for more information.

General operation

The parser will generally perform the following functions:

Translate macro, enum-definitions and constants into define-foreign-variable or define-constant forms

Basic token-substitution of macros defined via #define is performed. The preprocessor commands #ifdef, #ifndef, #else, #endif, #undef and #error are handled. The preprocessor commands #if and #elif are not supported and will signal an error when encountered by the parser, because C expressions (even if constant) are not parsed. The preprocessor command #pragma is allowed but will be ignored.

During processing of C code, the macro CHICKEN is defined (similar to the C compiler option -DCHICKEN).

Macro- and type-definitions are available in subsequent bind declarations. C variables declared generate a procedure with zero or one argument with the same name as the variable. When called with no arguments, the procedure returns the current value of the variable. When called with an argument, then the variable is set to the value of that argument. C and C++ style comments are supported. Variables declared as const will generate normal Scheme variables, bound to the initial value of the variable.

Function-, member-function and constructor/destructor definitions may be preceded by the ___safe qualifier, which marks the function as (possibly) performing a callback into Scheme. If a wrapped function calls back into Scheme code, and ___safe has not been given very strange and hard to debug problems will occur.

Functions and member functions prefixed with ___discard and a result type that maps to a Scheme string (c-string), will have their result type changed to c-string* instead.

Constants (as declared by #define or enum) are not visible outside of the current Compilation units unless the export-constants option has been enabled. Only numeric or character constants are directly supported.

Function-arguments may be preceded by ___in, ___out and ___inout qualifiers to specify values that are passed by reference to a function, or returned by reference. Only basic types (booleans, numbers and characters) can be passed using this method. During the call a pointer to a temporary piece of storage containing the initial value (or a random value, for ___out parameters) will be allocated and passed to the wrapped function. This piece of storage is subject to garbage collection and will move, should a callback into Scheme occur that triggers a garbage collection. Multiple __out and ___inout parameters will be returned as multiple values, preceded by the normal return value of thhe function (if not void). Here is a simple example:

(bind* #<<EOF
#ifndef CHICKEN
#include <math.h>
#endif

double modf(double x, ___out double *iptr);
EOF
)

(let-values ([(frac int) (modf 33.44)])
...)

Function-arguments may be preceded by ___length(ID), where ID designates the name of another argument that must refer to a number vector or string argument. The value of the former argument will be computed at run-time and thus can be omitted:

The length variable may be positioned anywhere in the argument list. Length markers may only be specified for arguments passed as SRFI-4 byte-vectors, byte-vectors (as provided by the lolevel library unit) or strings.

Structure and union definitions containing actual field declarations generate getter procedures (and SRFI-17 setters when declared ___mutable or the mutable-fields option has been enabled) The names of these procedures are computed by concatenating the struct (or union) name, a hyphen ("-") and the field name. Structure definitions with fields may not be used in positions where a type specifier is normally expected. The field accessors operate on struct/union pointers only. Additionally a zero-argument procedure named make-<structname> will be generated that allocates enough storage to hold an instance of the structure (or union). Prefixing the definition with ___abstract will omit the creation procedure.

Nested structs or unions are not supported (but pointers to nested structs/unions are).

All specially handled tokens preceded with ___ are defined as C macros in the headerfile chicken.h and will usually expand into nothing, so they don't invalidate the processed source code.

C++ namespace declarations of the form namespace NAME @{... @} recognized but will be completely ignored.

Keep in mind that this is not a fully general C/C++ parser. Taking an arbitrary headerfile and feeding it to bind will in most cases not work or generate riduculuous amounts of code. This FFI facility is for carefully written headerfiles, and for declarations directly embedded into Scheme code.

Syntactic forms

bind

[syntax](bind STRING ...)

Parses the C code in STRING ... and expands into wrapper code providing access to the declarations defined in it.

bind*

[syntax](bind* STRING ...)

Similar to bind, but also embeds the code in the generated Scheme expansion using foreign-declare.

bind-type

Declares a foreign type transformation, similar to define-foreign-type. There should be two to four arguments: a C typename, a Scheme foreign type specifier and optional argument- and result-value conversion procedures.

;;;; foreign type that converts to unicode (assumes 4-byte wchar_t):
;
; - Note: this is rather kludgy and is only meant to demonstrate the `bind-type'
; syntax

bind-opaque-type

Similar to bind-type, but provides automatic argument- and result conversions to wrap a value into a structure:

(bind-opaque-type myfile (pointer "FILE"))

(bind "myfile fopen(char *, char *);")

(fopen "somefile" "r") ==> <myfile>

(bind-opaque-type TYPENAME TYPE) is basically equivalent to (bind-type TYPENAME TYPE TYPE->RECORD RECORD->TYPE) where TYPE->RECORD and RECORD->TYPE are compiler-generated conversion functions that wrap objects of type TYPE into a record and back.

bind-file

[syntax](bind-file FILENAME ...)

Reads the content of the given files and generates wrappers using bind. Note that FILENAME ... is not evaluated.

bind-file*

[syntax](bind-file* FILENAME ...)

Reads the content of the given files and generates wrappers using bind*.

bind-rename

[syntax](bind-rename CNAME SCHEMENAME)

Defines to what a certain C/C++ name should be renamed. CNAME specifies the C/C++ identifier occurring in the parsed text and SCHEMENAME gives the name used in generated wrapper code.

bind-rename/pattern

[syntax](bind-rename/pattern REGEX REPLACEMENT)

Declares a renaming pattern to be used for C/C++ identifiers occuring in bound code. REGEX should be a string or SRE and replacement a string, which may optionally contain back-references to matched sub-patterns.

bind-options

[syntax](bind-options OPTION VALUE ...)

Enables various translation options, where OPTION is a keyword and VALUE is a value given to that option. Note that VALUE is not evaluated.

Possible options are:

export-constants

export-constants: BOOLEAN

Define global variables for constant-declarations (with #define or enum), making the constant available outside the current compilation unit.

class-finalizers

class-finalizers: BOOLEAN

Automatically generates calls to set-finalizer! so that any unused references to instances of subsequently defined C++ class wrappers will be destroyed. This should be used with care: if the embedded C++ object which is represented by the reclaimed coops instance is still in use in foreign code, unpredictable things will happen.

mutable-fields

mutable-fields: BOOLEAN

Specifies that all struct or union fields should generate setter procedures (the default is to generate only setter procedures for fields declared ___mutable).

constructor-name

constructor-name: STRING

Specifies an alternative name for constructor methods (the default is constructor), a default-method for which is defined in the cplusplus-object extension.

destructor-name

destructor-name: STRING

Specifies an alternative name for destructor methods (the default is destructor), a default-method for which is defined in the cplusplus-object extension.

exception-handler

exception-handler: STRING

Defines C++ code to be executed when an exception is triggered inside a C++ class member function. The code should be one or more catch forms that perform any actions that should be taken in case an exception is thrown by the wrapped member function:

full-specialization

full-specialization: BOOLEAN

Enables full specialization mode. In this mode all wrappers for functions, member functions and static member functions are created as fully specialized coops methods. This can be used to handle overloaded C++ functions properly. Only a certain set of foreign argument types can be mapped to coops classes, as listed in the following table:

Type

Class

char

<char>

bool

<bool>

c-string

<string>

unsigned-char

<exact>

byte

<exact>

unsigned-byte

<exact>

[unsigned-]int

<exact>

[unsigned-]short

<exact>

[unsigned-]long

<integer>

[unsigned-]integer

<integer>

float

<inexact>

double

<inexact>

number

<number>

(enum _)char

<exact>

(const T)char

(as T)

(function ...)

<pointer>

c-pointer

<pointer>

(pointer _)

<pointer>

(c-pointer _)

<pointer>

u8vector

<u8vector>

s8vector

<s8vector>

u16vector

<u16vector>

s16vector

<s16vector>

u32vector

<u32vector>

s32vector

<s32vector>

f32vector

<f32vector>

f64vector

<f64vector>

All other foreign types are specialized as #t.

Full specialization can be enabled globally, or only for sections of code by enclosing it in

(bind-options full-specialization: #t)

(bind #<<EOF
...
int foo(int x);
int foo(char *x);
...
EOF
)

(bind-options full-specialization: #f)

Alternatively, member function definitions may be prefixed by ___specialize for specializing only specific members.

prefix

prefix: STRING

Sets a prefix that should be be added to all generated Scheme identifiers. For example

(bind-options prefix: "mylib:")

(bind "#define SOME_CONST 42")

would generate the following code:

(define-constant mylib:SOME_CONST 42)

To switch prefixing off, use the value #f. Prefixes are not applied to Class names.

default-renaming

default_renaming: STRING

Chooses a standard name-transformation, converting underscores (_) to hyphens (-) and transforming CamelCase into camel-case. All uppercase characters are also converted to lowercase. The result is prefixed with the argument STRING (equivalent to the prefix ption).

bind-include-path

[syntax](bind-include-path STRING ...)

Appends the paths given in STRING ... to the list of available include paths to be searched when an #include ... form is processed by bind.

The ___pointer argument marker disables automatic simplification of pointers to number-vectors: normally arguments of type int * are handled as SRFI-4 s32vector number vectors. To force treatment as a pointer argument, precede the argument type with ___pointer.

C notes

Foreign variable definitions for macros are not exported from the current compilation unit, but definitions for C variables and functions are.

bind does not embed the text into the generated C file, use bind* for that.

Functions with variable number of arguments are not supported.

C++ notes

Each C++ class defines a coops class, which is a subclass of <c++-object>. Instances of this class contain a single slot named this, which holds a pointer to a heap-allocated C++ instance. The name of the coops class is obtained by putting the C++ classname between angled brackets (<...>). coops classes are not seen by C++ code.

The C++ constructor is invoked by the constructor generic, which accepts as many arguments as the constructor. If no constructor is defined, a default-constructor will be provided taking no arguments.

To release the storage allocated for a C++ instance invoke the delete generic (the name can be changed by using the destructor-name option).

Static member functions are wrapped in a Scheme procedure named <class>::<member>.

Member variables and non-public member functions are ignored.

Virtual member functions are not seen by C++ code. Overriding a virtual member function with a coops method will not work when the member function is called by C++.

Operator functions and default arguments are not supported.

Exceptions must be explicitly handled by user code and may not be thrown beyond an invocation of C++ by Scheme code.

Generally, the following interface to the creation and destruction of wrapped C++ instances is provided:

constructor

[procedure](constructor CLASS INITARGS)

A generic function that, when invoked will construct a C++ object represented by the class CLASS, which should inherit from <c++-object>. INITARGS is a list of arguments that should be passed to the constructor and which must match the argument types for the wrapped constructor.

destructor

[procedure](destructor OBJECT)

A generic function that, when invoked will destroy the wrapped C++ object OBJECT.

new

[procedure](new CLASS ARG1 ...)

A convenience procedure that invokes the constructor generic function for CLASS.

delete

[procedure](delete OBJECT)

A convenience procedure that invokes the destructor generic method of OBJECT.