Definition macro
Describes a C function to the c-ffi.
define C-function name [parameter-spec; ...] [result-spec;] [function-option, ...;] end [C-function] [name]
c-ffi
c-ffi
Describes a C function to the C-FFI. In order for a C function to be called correctly by Dylan, the same information about the function must be given as is needed by C callers, typically provided by extern declarations for the function in a C header file: the function's name and the types of its parameters and results.
The result of processing a define C-function definition is a Dylan function which is bound to name. This function takes Dylan objects as arguments, converting them to their C representations according to the types declared for the parameters of the C function before calling the C function with them. If the C function returns results, these results are converted to Dylan representations according to the declared types of those results before being returned to the Dylan caller of the function. By default the function created is a raw method, not a generic function. A generic function method can defined by using the generic-function-method: option.
Either the c-name: function option must be supplied, or the indirect: option must be supplied with a value other than #f, but not both.
A parameter-spec has the following syntax:
[adjectives] parameter name :: c-type #key c-name
If no parameters are specified, the C function is taken to have no arguments.
The adjectives can be either output, input, or both. The calling discipline is specified by the input and output adjectives.
By itself, input indicates that the argument is passed into the function by value. This option is the default and is used primarily to document the code. There is a parameter to the generated Dylan function corresponding to each input parameter of the C function.
The output adjective specifies that the argument value to the C function is used to identify a location into which an extra result of the C function will be stored. There is no parameter in the generated Dylan function corresponding to an output parameter of the C function. The C-FFI generates a location for the extra return value itself and passes it to the C function. When the C function returns, the value in the location is accessed and returned as an extra result from the Dylan function. The C-FFI allocates space for the output parameter's referenced type, passes a pointer to the allocated space, and returns pointer-value of that pointer. A struct or union type may not be used as an output parameter.
Example of output parameter definition:
define C-function mix-it-up
output parameter out1 :: <some-struct*>;
output parameter out2 :: <C-int*>;
result value :: <C-int>;
c-name: "mix_it_up";
end C-function mix-it-up;Example transaction:
? mix-it-up();
1
{<some-struct> pointer #xfefe770}
42
If both input and output are supplied, they specify that the argument value to the C function is used to identify a location from which a value is accessed and into which an extra result value is placed by the C function. There is a parameter to the generated Dylan function corresponding to each input output parameter of the C function that is specialized as the union of the export type of the referenced type of the type given for the parameter in define c-function, and #f. When the C function returns, the value in the location is accessed and returned as an extra result from the Dylan function. If an input output parameter is passed as #f from Dylan then a NULL pointer is passed to the C function, and the extra value returned by the Dylan function will be #f.
Example of input output parameter definition:
define C-function mix-it-up
input output parameter inout :: <C-int*>;
result value :: <C-int>;
c-name: "mix_it_up";
end C-function mix-it-up;Example transaction:
? mix-it-up(7); 1 14
Note that neither output nor input output affects the declared type of an argument: it must have the same type it has in C and so, because it represents a location, must be a pointer type.
A result-spec has the following syntax:
result [name :: c-type]
If no result is specified, the Dylan function does not return a value for the C result, and the C function is expected to have a return type of void.
Each function-option is a keyword-value pair. The generic-function-method: option may be either #t or #f, indicating whether to add a method to the generic function name or to bind a bare constant method directly to name. The default value for generic-function-method: is #f. The option C-modifiers: can be used to specify platform dependent modifiers for the C function being called. For example, on Windows, use C-modifiers: "__stdcall" if the C function to be called is defined to be a __stdcall function.
The c-name: option is used to specify the name of the C function as it is defined in the object or shared library file. The c-name must be a constant string.
The indirect: #t option defines a function that accepts a C function pointer as its first argument and calls the function given with the signature described by the parameters and result given. In this case the Dylan function defined accepts one more argument than if c-name was given. The type specified for the first parameter of the Dylan function is <c-function-pointer>. One of c-name or indirect: #t must be supplied, but not both.
Example C declarations:
/* Compute the length of a string */ int strlen(char *string); /* Set the given locations to values, returning an error code */ int fill_locations(int *loc1, int* loc2); /* Read at most as far as indicated in max_then_read, updating it to contain how much was actually read */ void read_stuff(int *max_then_read);
define C-function strlen parameter string :: <C-char*>; result value :: <C-int>; c-name: "strlen"; end C-function; define C-function fill-locations output parameter loc1 :: <C-int*>; output parameter loc2 :: <C-int*>; result return-code :: <C-int>; c_name: "fill_locations"; end C-function; define C-function read-stuff input output parameter :: <C-int*>; c-name: "read_stuff"; end C-function;
Example transactions:
? strlen($my-c-string); 44 ? fill-locations(); 0 101 // extra output value 102 // extra output value ? read-stuff(100); 50 // extra output value
In effect, a define C-function such as:
define C-function foo parameter string :: <C-char*>; parameter count :: <C-int>; result value :: <C-int>; c-name: "foo"; end C-function;
expands into something like:
define constant foo =
method (string, count)
let c-string = %as-c-representation(<C-char*>,
string);
let c-count = %as-c-representation(<C-int>, count);
let c-result = %call-c-function("foo", c-string,
c-count);
%as-dylan-representation(<C-int>, c-result);
end;