aboutsummaryrefslogtreecommitdiff
path: root/docs/markdown/Vala.md
blob: fdc4fbae47c32a1e4ba00a68983ab8b2c18ee091 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
---
title: Vala
short-description: Compiling Vala and Genie programs
...

# Compiling Vala applications and libraries
Meson supports compiling applications and libraries written in
[Vala](https://vala-project.org/) and
[Genie](https://wiki.gnome.org/Projects/Genie) . A skeleton `meson.build` file:

```meson
project('vala app', 'vala', 'c')

dependencies = [
    dependency('glib-2.0'),
    dependency('gobject-2.0'),
]

sources = files('app.vala')

executable('app_name', sources, dependencies: dependencies)
```

You must always specify the `glib-2.0` and `gobject-2.0` libraries as
dependencies, because all current Vala applications use them.
[GLib](https://developer.gnome.org/glib/stable/) is used for basic data types
and [GObject](https://developer.gnome.org/gobject/stable/) is used for the
runtime type system.


## Using libraries

Meson uses the [[dependency]]
function to find the relevant VAPI, C headers and linker flags when it
encounters a Vala source file in a build target. Vala needs a VAPI
file and a C header or headers to use a library. The VAPI file helps
map Vala code to the library's C programming interface. It is the
[`pkg-config`](https://www.freedesktop.org/wiki/Software/pkg-config/)
tool that makes finding these installed files all work seamlessly
behind the scenes. When a `pkg-config` file doesn't exist for the
library then the `find_library()`
method of the [[@compiler]] object
needs to be used. Examples are given later.

Note Vala uses libraries that follow the C Application Binary Interface (C ABI).
The library, however, could be written in C, Vala, Rust, Go, C++ or any other
language that can generate a binary compatible with the C ABI and so provides C
headers.


### The simplest case
This first example is a simple addition to the `meson.build` file because:

 * the library has a `pkg-config` file, `gtk+-3.0.pc`
 * the VAPI is distributed with Vala and so installed with the Vala compiler
 * the VAPI is installed in Vala's standard search path
 * the VAPI, `gtk+-3.0.vapi`, has the same name as the `pkg-config` file

Everything works seamlessly in the background and only a single extra line is
needed:

```meson
project('vala app', 'vala', 'c')

dependencies = [
    dependency('glib-2.0'),
    dependency('gobject-2.0'),
    dependency('gtk+-3.0'),
]

sources = files('app.vala')

executable('app_name', sources, dependencies: dependencies)
```

GTK+ is the graphical toolkit used by GNOME, elementary OS and other
desktop environments. The binding to the library, the VAPI file, is
distributed with Vala.

Other libraries may have a VAPI that is distributed with the library
itself. Such libraries will have their VAPI file installed along with
their other development files. The VAPI is installed in Vala's
standard search path and so works just as seamlessly using the
`dependency()` function.


### Targeting a version of GLib

Meson's [[dependency]] function
allows a version check of a library. This is often used to check a
minimum version is installed. When setting a minimum version of GLib,
Meson will also pass this to the Vala compiler using the
`--target-glib` option.

This is needed when using GTK+'s user interface definition files with
Vala's `[GtkTemplate]`, `[GtkChild]` and `[GtkCallback]` attributes.
This requires `--target-glib 2.38`, or a newer version, to be passed
to Vala. With Meson this is simply done with:

```meson
project('vala app', 'vala', 'c')

dependencies = [
    dependency('glib-2.0', version: '>=2.38'),
    dependency('gobject-2.0'),
    dependency('gtk+-3.0'),
]

sources = files('app.vala')

executable('app_name', sources, dependencies: dependencies)
```

Using `[GtkTemplate]` also requires the GTK+ user interface definition
files to be built into the binary as GResources. For completeness,
the next example shows this:

```meson
project('vala app', 'vala', 'c')

dependencies = [
    dependency('glib-2.0', version: '>=2.38'),
    dependency('gobject-2.0'),
    dependency('gtk+-3.0'),
]

sources = files('app.vala')

sources += import( 'gnome' ).compile_resources(
    'project-resources',
    'src/resources/resources.gresource.xml',
    source_dir: 'src/resources',
)

executable('app_name', sources, dependencies: dependencies)
```


### Adding to Vala's search path

So far we have covered the cases where the VAPI file is either
distributed with Vala or the library. A VAPI can also be included in
the source files of your project. The convention is to put it in the
`vapi` directory of your project.

This is needed when a library does not have a VAPI or your project
needs to link to another component in the project that uses the C ABI.
For example if part of the project is written in C.

The Vala compiler's `--vapidir` option is used to add the project
directory to the VAPI search path. In Meson this is done with the
`add_project_arguments()` function:

```meson
project('vala app', 'vala', 'c')

vapi_dir = meson.current_source_dir() / 'vapi'

add_project_arguments(['--vapidir', vapi_dir], language: 'vala')

dependencies = [
    dependency('glib-2.0'),
    dependency('gobject-2.0'),
    dependency('foo'), # 'foo.vapi' will be resolved as './vapi/foo.vapi'
]

sources = files('app.vala')

executable('app_name', sources, dependencies: dependencies)
```

If the VAPI is for an external library then make sure that the VAPI
name corresponds to the pkg-config file name.

The [`vala-extra-vapis`
repository](https://gitlab.gnome.org/GNOME/vala-extra-vapis) is a
community maintained repository of VAPIs that are not distributed.
Developers use the repository to share early work on new bindings and
improvements to existing bindings. So the VAPIs can frequently change.
It is recommended VAPIs from this repository are copied into your
project's source files.

This also works well for starting to write new bindings before they
are shared with the `vala-extra-vapis` repository.


### Libraries without pkg-config files

A library that does not have a corresponding pkg-config file may mean
`dependency()` is unsuitable for finding the C and Vala interface
files. In this case it is necessary to use the `find_library()` method
of the compiler object.

The first example uses Vala's POSIX binding. There is no pkg-config
file because POSIX includes the standard C library on Unix systems.
All that is needed is the VAPI file, `posix.vapi`. This is included
with Vala and installed in Vala's standard search path. Meson just
needs to be told to only find the library for the Vala compiler:

```meson
project('vala app', 'vala', 'c')

dependencies = [
    dependency('glib-2.0'),
    dependency('gobject-2.0'),
    meson.get_compiler('vala').find_library('posix'),
]

sources = files('app.vala')

executable('app_name', sources, dependencies: dependencies)
```

The next example shows how to link with a C library where no
additional VAPI is needed. The standard maths functions are already
bound in `glib-2.0.vapi`, but the GNU C library requires linking to
the maths library separately. In this example Meson is told to find
the library only for the C compiler:

```meson
project('vala app', 'vala', 'c')

dependencies = [
    dependency('glib-2.0'),
    dependency('gobject-2.0'),
    meson.get_compiler('c').find_library('m', required: false),
]

sources = files('app.vala')

executable('app_name', sources, dependencies: dependencies)
```

The `required: false` means the build will continue when using another
C library that does not separate the maths library. See [Add math
library (-lm) portably](howtox.md#add-math-library-lm-portably).

The final example shows how to use a library that does not have a
pkg-config file and the VAPI is in the `vapi` directory of your
project source files:

```meson
project('vala app', 'vala', 'c')

vapi_dir = meson.current_source_dir() / 'vapi'

add_project_arguments(['--vapidir', vapi_dir], language: 'vala')

dependencies = [
    dependency('glib-2.0'),
    dependency('gobject-2.0'),
    meson.get_compiler('c').find_library('foo'),
    meson.get_compiler('vala').find_library('foo', dirs: vapi_dir),
]

sources = files('app.vala')

executable('app_name', sources, dependencies: dependencies)
```
The `find_library()` method of the C compiler object will try to find the C
header files and the library to link with.

The `find_library()` method of the Vala compiler object needs to have the `dir`
keyword added to include the project VAPI directory. This is not added
automatically by `add_project_arguments()`.

### Working with the Vala Preprocessor

Passing arguments to [Vala's
preprocessor](https://wiki.gnome.org/Projects/Vala/Manual/Preprocessor)
requires specifying the language as `vala`. For example, the following
statement sets the preprocessor symbol `USE_FUSE`:

```meson
add_project_arguments('-D', 'USE_FUSE', language: 'vala')
```

If you need to pass an argument to the C pre-processor then specify
the language as c. For example to set FUSE_USE_VERSION to 26 use:

```meson
add_project_arguments('-DFUSE_USE_VERSION=26', language: 'c')
```

## Building libraries


### Changing C header and VAPI names

Meson's [[library]] target automatically
outputs the C header and the VAPI. They can be renamed by setting the
`vala_header` and `vala_vapi` arguments respectively:

```meson
foo_lib = shared_library('foo', 'foo.vala',
                  vala_header: 'foo.h',
                  vala_vapi: 'foo-1.0.vapi',
                  dependencies: [glib_dep, gobject_dep],
                  install: true,
                  install_dir: [true, true, true])
```

In this example, the second and third elements of the `install_dir`
array indicate the destination with `true` to use default directories
(i.e. `include` and `share/vala/vapi`).


### GObject Introspection and language bindings

A 'binding' allows another programming language to use a library
written in Vala. Because Vala uses the GObject type system as its
runtime type system it is very easy to use introspection to generate a
binding. A Meson build of a Vala library can generate the GObject
introspection metadata. The metadata is then used in separate projects
with [language specific
tools](https://wiki.gnome.org/Projects/Vala/LibraryWritingBindings) to
generate a binding.

The main form of metadata is a GObject Introspection Repository (GIR)
XML file. GIRs are mostly used by languages that generate bindings at
compile time. Languages that generate bindings at runtime mostly use a
typelib file, which is generated from the GIR.

Meson can generate a GIR as part of the build. For a Vala library the
`vala_gir` option has to be set for the `library`:

```meson
foo_lib = shared_library('foo', 'foo.vala',
                  vala_gir: 'Foo-1.0.gir',
                  dependencies: [glib_dep, gobject_dep],
                  install: true,
                  install_dir: [true, true, true, true])
```

The `true` value in `install_dir` tells Meson to use the default
directory (i.e. `share/gir-1.0` for GIRs). The fourth element in the
`install_dir` array indicates where the GIR file will be installed.

To then generate a typelib file use a custom target with the
`g-ir-compiler` program and a dependency on the library:

```meson
g_ir_compiler = find_program('g-ir-compiler')
custom_target('foo typelib', command: [g_ir_compiler, '--output', '@OUTPUT@', '@INPUT@'],
              input: meson.current_build_dir() / 'Foo-1.0.gir',
              output: 'Foo-1.0.typelib',
              depends: foo_lib,
              install: true,
              install_dir: get_option('libdir') / 'girepository-1.0')
```