Kompilieren von Vala-Anwendungen und -Bibliotheken

Meson unterstützt das Kompilieren von Anwendungen und Bibliotheken, die in Vala und Genie geschrieben sind. Eine rudimentäre meson.build-Datei

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

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

sources = files('app.vala')

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

Sie müssen immer die Bibliotheken glib-2.0 und gobject-2.0 als Abhängigkeiten angeben, da alle aktuellen Vala-Anwendungen diese verwenden. GLib wird für grundlegende Datentypen verwendet und GObject wird für das Laufzeit-Typsystem verwendet.

Verwenden von Bibliotheken

Meson verwendet die Funktion dependency(), um die relevanten VAPI-, C-Header- und Linker-Flags zu finden, wenn es auf eine Vala-Quelldatei in einem Build-Ziel trifft. Vala benötigt eine VAPI-Datei und einen C-Header oder Header, um eine Bibliothek zu verwenden. Die VAPI-Datei hilft, Vala-Code auf die C-Programmierschnittstelle der Bibliothek abzubilden. Es ist das pkg-config-Werkzeug, das das nahtlose Auffinden dieser installierten Dateien im Hintergrund ermöglicht. Wenn keine pkg-config-Datei für die Bibliothek existiert, muss die Methode find_library() des compiler-Objekts verwendet werden. Beispiele folgen später.

Hinweis: Vala verwendet Bibliotheken, die der C Application Binary Interface (C ABI) folgen. Die Bibliothek kann jedoch in C, Vala, Rust, Go, C++ oder einer anderen Sprache geschrieben sein, die eine binärkompatible Version mit der C ABI erzeugt und somit C-Header bereitstellt.

Der einfachste Fall

Das erste Beispiel ist eine einfache Ergänzung der meson.build-Datei, da

  • die Bibliothek eine pkg-config-Datei hat, gtk+-3.0.pc
  • die VAPI mit Vala verteilt und somit mit dem Vala-Compiler installiert wird
  • die VAPI im Standard-Suchpfad von Vala installiert ist
  • die VAPI, gtk+-3.0.vapi, den gleichen Namen wie die pkg-config-Datei hat

Alles funktioniert nahtlos im Hintergrund und es ist nur eine einzige zusätzliche Zeile erforderlich

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+ ist das grafische Toolkit, das von GNOME, elementary OS und anderen Desktop-Umgebungen verwendet wird. Die Bindung an die Bibliothek, die VAPI-Datei, wird mit Vala vertrieben.

Andere Bibliotheken können eine VAPI haben, die mit der Bibliothek selbst vertrieben wird. Solche Bibliotheken haben ihre VAPI-Datei zusammen mit ihren anderen Entwicklungsdateien installiert. Die VAPI wird im Standard-Suchpfad von Vala installiert und funktioniert daher ebenso nahtlos mit der Funktion dependency().

Zielversion von GLib

Die Funktion dependency() von Meson erlaubt eine Versionsprüfung einer Bibliothek. Dies wird oft verwendet, um eine Mindestversion zu überprüfen. Beim Festlegen einer Mindestversion von GLib übergibt Meson dies auch an den Vala-Compiler mit der Option --target-glib.

Dies ist erforderlich, wenn GTK+-UI-Definitionsdateien mit den Vala-Attributen [GtkTemplate], [GtkChild] und [GtkCallback] verwendet werden. Dies erfordert, dass --target-glib 2.38 oder eine neuere Version an Vala übergeben wird. Mit Meson wird dies einfach mit

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)

Die Verwendung von [GtkTemplate] erfordert auch, dass die GTK+-UI-Definitionsdateien als GResources in die Binärdatei kompiliert werden. Der Vollständigkeit halber zeigt das nächste Beispiel dies

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)

Hinzufügen zum Suchpfad von Vala

Bisher haben wir die Fälle behandelt, in denen die VAPI-Datei entweder mit Vala oder der Bibliothek vertrieben wird. Eine VAPI kann auch in die Quelldateien Ihres Projekts aufgenommen werden. Die Konvention ist, sie im Verzeichnis vapi Ihres Projekts zu platzieren.

Dies ist erforderlich, wenn eine Bibliothek keine VAPI hat oder Ihr Projekt sich mit einer anderen Komponente im Projekt verbinden muss, die die C ABI verwendet. Zum Beispiel, wenn ein Teil des Projekts in C geschrieben ist.

Die Option --vapidir des Vala-Compilers wird verwendet, um das Projektverzeichnis zum VAPI-Suchpfad hinzuzufügen. In Meson geschieht dies mit der Funktion add_project_arguments()

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)

Wenn die VAPI für eine externe Bibliothek bestimmt ist, stellen Sie sicher, dass der VAPI-Name mit dem Namen der pkg-config-Datei übereinstimmt.

Das Repository vala-extra-vapis ist ein gemeinschaftlich gepflegtes Repository von VAPIs, die nicht vertrieben werden. Entwickler nutzen das Repository, um frühe Arbeiten an neuen Bindungen und Verbesserungen bestehender Bindungen zu teilen. Daher können sich die VAPIs häufig ändern. Es wird empfohlen, VAPIs aus diesem Repository in die Quelldateien Ihres Projekts zu kopieren.

Dies funktioniert auch gut, um mit dem Schreiben neuer Bindungen zu beginnen, bevor sie mit dem Repository vala-extra-vapis geteilt werden.

Bibliotheken ohne pkg-config-Dateien

Eine Bibliothek, die keine entsprechende pkg-config-Datei hat, kann bedeuten, dass dependency() für das Auffinden der C- und Vala-Schnittstellendateien ungeeignet ist. In diesem Fall ist es notwendig, die Methode find_library() des Compiler-Objekts zu verwenden.

Das erste Beispiel verwendet die POSIX-Bindung von Vala. Es gibt keine pkg-config-Datei, da POSIX unter Unix-Systemen die Standard-C-Bibliothek umfasst. Alles, was benötigt wird, ist die VAPI-Datei posix.vapi. Diese ist bei Vala enthalten und im Standard-Suchpfad von Vala installiert. Meson muss nur mitgeteilt werden, die Bibliothek nur für den Vala-Compiler zu finden

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)

Das nächste Beispiel zeigt, wie man mit einer C-Bibliothek verknüpft, für die keine zusätzliche VAPI benötigt wird. Die Standard-Mathematikfunktionen sind bereits in glib-2.0.vapi gebunden, aber die GNU C-Bibliothek erfordert eine separate Verknüpfung mit der Mathematikbibliothek. In diesem Beispiel wird Meson angewiesen, die Bibliothek nur für den C-Compiler zu finden

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)

required: false bedeutet, dass der Build fortgesetzt wird, wenn eine andere C-Bibliothek verwendet wird, die die Mathematikbibliothek nicht separat behandelt. Siehe Mathematikbibliothek (-lm) portabel hinzufügen.

Das letzte Beispiel zeigt, wie eine Bibliothek verwendet wird, die keine pkg-config-Datei hat und die VAPI sich im Verzeichnis vapi Ihrer Projektquellendateien befindet

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)

Die Methode find_library() des C-Compiler-Objekts versucht, die C-Header-Dateien und die zu verknüpfende Bibliothek zu finden.

Die Methode find_library() des Vala-Compiler-Objekts muss das Schlüsselwort dir hinzugefügt bekommen, um das VAPI-Verzeichnis des Projekts einzubeziehen. Dies wird nicht automatisch von add_project_arguments() hinzugefügt.

Arbeiten mit dem Vala-Präprozessor

Das Übergeben von Argumenten an den Präprozessor von Vala erfordert die Angabe der Sprache als vala. Zum Beispiel setzt die folgende Anweisung das Präprozessorsymbol USE_FUSE

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

Wenn Sie ein Argument an den C-Präprozessor übergeben müssen, geben Sie die Sprache als c an. Um zum Beispiel FUSE_USE_VERSION auf 26 zu setzen, verwenden Sie

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

Erstellen von Bibliotheken

Ändern von C-Header- und VAPI-Namen

Das Ziel library() von Meson gibt automatisch den C-Header und die VAPI aus. Sie können umbenannt werden, indem Sie die Argumente vala_header bzw. vala_vapi setzen

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 diesem Beispiel geben die zweite und dritte Elemente des Arrays install_dir das Ziel mit true an, um Standardverzeichnisse (d. h. include und share/vala/vapi) zu verwenden.

GObject Introspection und Sprachbindungen

Eine "Bindung" ermöglicht es einer anderen Programmiersprache, eine in Vala geschriebene Bibliothek zu verwenden. Da Vala das GObject-Typsystem als Laufzeit-Typsystem verwendet, ist es sehr einfach, Introspection zu verwenden, um eine Bindung zu generieren. Ein Meson-Build einer Vala-Bibliothek kann die GObject-Introspection-Metadaten generieren. Die Metadaten werden dann in separaten Projekten mit sprachenspezifischen Werkzeugen verwendet, um eine Bindung zu generieren.

Die Hauptform der Metadaten ist eine GObject Introspection Repository (GIR) XML-Datei. GIRs werden meist von Sprachen verwendet, die Bindungen zur Kompilierzeit generieren. Sprachen, die Bindungen zur Laufzeit generieren, verwenden meist eine Typelib-Datei, die aus der GIR generiert wird.

Meson kann als Teil des Builds eine GIR generieren. Für eine Vala-Bibliothek muss die Option vala_gir für die library gesetzt werden

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])

Der Wert true in install_dir weist Meson an, das Standardverzeichnis (d. h. share/gir-1.0 für GIRs) zu verwenden. Das vierte Element im Array install_dir gibt an, wo die GIR-Datei installiert wird.

Um dann eine Typelib-Datei zu generieren, verwenden Sie ein benutzerdefiniertes Ziel mit dem Programm g-ir-compiler und einer Abhängigkeit von der Bibliothek

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')

Die Ergebnisse der Suche sind