I'd like to hack on an existing GLib based C project using Vala.
Basically what I'm doing is, at the beginning of my build process, using valac to generate .c and .h files from my .vala files and then just compiling the generated files the way I would any .c or .h file.
This is probably not the best way, but seems to be working alright for the most part.
My problem is that I'm having a hard time accessing my existing C code from my Vala code. Is there an easy way to do this?
I've tried writing my own .vapi files (I didn't have any luck with the tool that came with vala), but I can't find any decent documentation on how to write these.
Does any exist? Do I need one of these files to call existing C code?
Yes, to call a C function, you need to write a binding for it. The process is described in http://live.gnome.org/Vala/Tutorial#Binding_Libraries_with_VAPI_Files, however, this doesn't apply directly to custom functions or libraries written without GObject. You'll probably need help from #vala IRC channel if you have complex binding for non-GObject libraries.
However, most of the time, we use simple vapi files to bind some autoconf define or some functions written in plain C, for efficiency reason or broken vala, or whatever other reason. And this is the way that most people do:
myfunc.vapi
[CCode (cheader_filename = "myfunc.h")]
namespace MyFunc {
[CCode (cname = "my_func_foo")]
public string foo (int bar, Object? o = null);
}
myfunc.h (and corresponding implementation in a .c linked with your project)
#include <glib-object.h>
char* my_func_foo(int bar, GObject* o)
example.vala could be
using MyFunc;
void main() {
baz = foo(42);
}
When compiling with valac, use --vapidir=
to give the directory location of the myfunc.vapi. Depending on your build system, you may need to pass extra argument to valac or gcc CFLAGS in order to link everything together.
The only addition I would make to elmarco's answer is the extern
keyword. If you're trying to access a single C function that's already available in one of your packages or the standard C/Posix libraries, you can access it easily this way.
For GLib-based libraries written in C you can try to generate gir-files from your C-sources: Vala/Bindings.
Doing it manually is no problem too. Suppose you have a library which defines SomelibClass1 in C with a method called do_something which takes a string.
The name of the headerfile is "somelib.h". Then the corresponding vapi is as simple as the following:
somelib.vapi:
[CCode (cheader_filename="somelib.h")]
namespace Somelib {
public class Class1 {
public void do_something (string str);
}
}
Documentation for writing vapis for non-GLib libraries can be found here: Vala/LegacyBindings
This is actually really easy. Lets take an excerpt from posix.vapi:
[Compact]
[CCode (cname = "FILE", free_function = "fclose", cheader_filename = "stdio.h")]
public class FILE {
[CCode (cname = "fopen")]
public static FILE? open (string path, string mode);
[CCode (cname = "fgets", instance_pos = -1)]
public unowned string? gets (char[] s);
}
This implements the following C-Function:
FILE *fopen (const char *path, const char *mode);
char *fgets (char *s, int size, FILE *stream);
When discarding the instance_pos attribute vala assumes that the object is the first parameter to a method. This way it is possible to bind c-constructs that are roughly object-oriented. The free_method of the compact-class is called when the object is dereferenced.
The CCode(cname)-attribute of a method, class, struct, etc. has to be the name of it as it would be in C.
There is a lot more to this subject, but this should give you a general overview.
It would probably be easier to just access your vala code from c. As all you have to do is just compile to C.