docs: make clearer difference between using and building libraries in Vala [skip ci]

pull/4666/head
Alistair Thomas 6 years ago committed by Jussi Pakkanen
parent c1e416ff61
commit d54daf6e59
  1. 251
      docs/markdown/Vala.md

@ -3,25 +3,147 @@ title: Vala
short-description: Compiling Vala and Genie programs
...
# Compiling Vala applications
# 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 has support for compiling Vala and Genie programs. A skeleton `meson.build` file for Vala looks like this:
```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()`](Reference-manual.md#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()`](Reference-manual.md#find_library) method of the [compiler
object](Reference-manual.md#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 has the same name as the `pkg-config` file, `gtk+-3.0.vapi`
Everything works seamlessly in the background and only a single extra line is
needed:
```meson
project('valaprog', 'vala', 'c')
project('vala app', 'vala', 'c')
glib_dep = dependency('glib-2.0')
gobject_dep = dependency('gobject-2.0')
dependencies = [
dependency('glib-2.0'),
dependency('gobject-2.0'),
dependency('gtk+-3.0'),
]
executable('valaprog', 'prog.vala',
dependencies : [glib_dep, gobject_dep])
sources = files('app.vala')
executable('app_name', sources, dependencies : dependencies)
```
You must always specify `glib-2.0` and `gobject-2.0` as dependencies, because all Vala applications use them.
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.
### Targetting a version of GLib
Meson's [`dependency()`](Reference-manual.md#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]` annotations. 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')
## Using a custom VAPI
executable('app_name', sources, dependencies : dependencies)
```
When dealing with libraries that are not providing Vala bindings, a `--vapidir` flag can be added to extend the search path for the current project.
Using `[GtkTemplate]` also requires the GTK+ user interface definition files to
be built in to 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', 'c', 'vala')
@ -29,53 +151,113 @@ project('vala app', 'c', 'vala')
add_project_arguments(['--vapidir', join_paths(meson.current_source_dir(), 'vapi')],
language: 'vala')
glib_dep = dependency('glib-2.0')
gobject_dep = dependency('gobject-2.0')
foo_dep = dependency('foo') # 'foo.vapi' will be resolved in './vapi/foo.vapi'
dependencies = [
dependency('glib-2.0'),
dependency('gobject-2.0'),
dependency('foo'), # 'foo.vapi' will be resolved as './vapi/foo.vapi'
]
executable('app', 'app.vala', dependencies: [glib_dep, gobject_dep, foo_dep])
sources = files('app.vala')
executable('app_name', sources, dependencies : dependencies)
```
In this case, make sure that the VAPI name corresponds to the pkg-config file.
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://github.com/nemequ/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 in to 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.
If no pkg-config file is provided, you must use `find_library`. Using`declare_dependency` is cleaner because it does not require passing both dependency objects to the target.
### 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 `find_library()`.
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
foo_lib = meson.get_compiler('c').find_library('foo') # assuming libfoo.so is installed
foo_vapi = meson.get_compiler('vala').find_library('foo', dirs: join_paths(meson.current_source_dir(), 'vapi'))
foo_dep = declare_dependency(dependencies: [foo_lib, foo_vapi])
project('vala app', 'vala', 'c')
executable('app', 'app.vala', dependencies: [glib_dep, gobject_dep, foo_dep])
```
dependencies = [
dependency('glib-2.0'),
dependency('gobject-2.0'),
meson.get_compiler('vala').find_library('posix'),
]
## VAPI without pkg-config file
sources = files('app.vala')
Some Vala bindings do not need a corresponding pkg-config file and `dependency` is unsuitable for resolving them. It's necessary to use `find_library` in this case.
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
posix_dep = meson.get_compiler('vala').find_library('posix')
project('vala app', 'vala', 'c')
dependencies = [
dependency('glib-2.0'),
dependency('gobject-2.0'),
meson.get_compiler('c').find_library('m', required: false),
]
executable('app', 'app.vala', dependencies: [glib_dep, gobject_dep, posix_dep])
sources = files('app.vala')
executable('app_name', sources, dependencies : dependencies)
```
## Custom output names
If a library target is used, Meson automatically outputs the C header and the VAPI. They can be renamed by setting the `vala_header` and `vala_vapi` arguments respectively. In this case, the second and third elements of the `install_dir` array indicate the destination with `true` to indicate default directories (i.e. `include` and `share/vala/vapi`).
## Building libraries
### Changing C header and VAPI names
Meson's [`library`](Reference-manual.md#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 = library('foo', 'foo.vala',
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
### 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.
To generate GObject Introspection metadata, the `vala_gir` option has to be set with the desired name.
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.
The fourth element in the `install_dir` array indicate where the GIR file will be installed. The `true` value tells Meson to use the default directory (i.e. `share/gir-1.0`).
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 = library('foo', 'foo.vala',
@ -85,7 +267,12 @@ foo_lib = library('foo', 'foo.vala',
install_dir: [true, true, true, true])
```
For the typelib, use a custom target depending on the library:
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')

Loading…
Cancel
Save