This is a very simple example. Save the following C code as a file called a.c
#include <stdio.h>
void my_function() {
printf("I am a function written in a C file\n");
}
Save the following Vala code as a file called b.vala
extern void my_function ();
void main() {
my_function();
}
Then compile with:
valac a.c b.vala --output demo
There is a lot going on behind the scenes here. valac
gets the job done, but a build system, like Meson, would be more appropriate for a project that will grow.
First valac
recognises the Vala file in the list and compiles that to C. The extern void my_function ();
tells the Vala compiler that my_function
is defined externally and not in any of the Vala source files given. The Vala compiler just needs the function signature for type checking any calls from Vala and declaring the function in the generated C file. Instead of placing extern
every where an interface file could be written. In Vala this ia a VAPI file. The VAPI keeps the translation information of the Vala symbols to the C symbols in one place and so helps project maintainability and readability.
Second valac
passes the given C file and the generated C file to the C compiler. The C compiler compiles the files to object files then calls the linker to build a single binary. This might be clearer if you look at the generated C file. Use:
valac a.c b.vala --output demo --save-temps
The generated C file, b.c
, looks like this:
/* b.c generated by valac 0.43.6.15-63bd-dirty, the Vala compiler
* generated from b.vala, do not modify */
void my_function (void);
void _vala_main (void);
void
_vala_main (void)
{
my_function ();
}
int
main (int argc,
char ** argv)
{
_vala_main ();
return 0;
}
There is no #include
C pre-processor directive used. Instead my_function
is declared in the C file itself. Again an interface file could be written, a C header file this time instead of a VAPI file. You would then have to use [CCode(cheader_filename = "my_header.h")]
in the VAPI so Vala then generates the #include
.