Unfortunately, there isn't a great deal of documentation about CCode that makes sense alone. What you need to do is use it in conjunction with the VAPI files that comes with Vala. At its most basic, you will probably use your macro something like this:
[CCode(cname = "FOO", cheader_filename = "blah.h")]
public extern void foo();
Here we are setting the cname
(i.e., the name that will be emitted into the C code), and the cheader_filename
(i.e., the header file that should be #include
d). Most of the other CCode attributes control how arrays are handled. array_length = false
indicates that an array is of unknown length. This can be applied to a parameter or to the method, indicating that is applies to the return type. For instance:
[CCode(array_length = false)] public int[] x();
[CCode(array_null_terminated = true)] public FileStream[] y();
public int[] z();
In this example, x
will have unknown array length and have an expected C prototype of int *x(void)
, while y
is assumed to have a null-terminated array with the expected C prototype of FILE **y(void)
. Finally, z
is assumed to have an array length out parameter (i.e., a prototype of int *z(int *length)
, where length
is a pointer to where to store the length of the returned array.
All of these can be applied to parameters too. It's also useful to specify array_length_pos
if there is an array length but it is not the argument immediately after the array. If a parameter is a delegate, target_pos
specifies where the user data is passed (i.e., the void*
that goes with the function pointer).
There's also a variety of CCode attributes for use with delegates, classes, and structs. instance_pos
specifies where the class/struct instance or delegate user data goes. All of the position arguments are specified with a floating point number. This allows multiple positions to be encoded. For instance, suppose we had a C prototype:
void foo(void* userdata, int length, double *dbl_array, void(*handler)(double,void*));
then we might write this:
[CCode(cname = "foo")]
public void foo([CCode(array_length_pos = 0.2)] double[] array, [CCode(target_pos = 0.1)] Handler func);
Given Handler
is defined as a delegate elsewhere, you can see that the pos
values put the arguments after argument 0 (i.e., the start) and then in a particular order.
Classes and structs have functions to handle initialisation, destruction, and reference counting, but those are fairly straight forward. Handling generics is also a bit complicated. Again, the VAPIs are the best source of insight. However, that's enough to get you started on your basic C functions and macros.