How do I use CCode attributes in Vala?
Asked Answered
S

1

6

I am trying to use a C macro from Vala. It seems to me that this should be possible with the CCode directive but I fail to find any meaningful documentation about how to use it.

There is a brief section about CCode arguments in "The Hacker's Guide to Vala" and a mailing list thread about calling a C macro from Vala with CCode.

But neither resource really helps me to understand what CCode really does. It obviously affects how Vala generates C code, from the Hackers' Guide to Vala I can deduce that the CCode directive probably gives me direct influence into how the CCode tree is created when traversing Valas AST.

Could anybody explain a little more what CCode does?

Shock answered 16/4, 2012 at 13:27 Comment(1)
I found more documentation: live.gnome.org/Vala/Manual/Attributes#CCode_AttributeShock
B
8

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 #included). 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.

Blaineblainey answered 17/4, 2012 at 3:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.