Wrap-Abhängigkeitssystem-Handbuch

Eines der größten Probleme bei der plattformübergreifenden Entwicklung ist die Verwaltung all Ihrer Abhängigkeiten. Dies ist auf vielen Plattformen umständlich, insbesondere auf denen, die keinen integrierten Paketmanager haben. Letzteres Problem wurde durch die Verwendung von Drittanbieter-Paketmanagern umgangen. Sie sind keine wirkliche Lösung für die Endbenutzer-Bereitstellung, da Sie ihnen nicht befehlen können, einen Paketmanager zu installieren, nur um Ihre App zu verwenden. Auf diesen Plattformen müssen Sie eigenständige Anwendungen erstellen. Dasselbe gilt, wenn auf der Zielplattform (aktuelle Versionen) der Abhängigkeiten Ihrer Anwendung fehlen.

Der traditionelle Ansatz dafür war, Abhängigkeiten in Ihr eigenes Projekt zu bündeln. Entweder als vorkompilierte Bibliotheken und Header oder durch Einbetten des Quellcodes in Ihren Quellcodebaum und Umschreiben Ihres Build-Systems, um sie als Teil Ihres Projekts zu erstellen.

Dies ist sowohl mühsam als auch fehleranfällig, da es immer von Hand geschieht. Das Wrap-Abhängigkeitssystem von Meson zielt darauf ab, eine automatisierte Möglichkeit hierfür bereitzustellen.

Wie es funktioniert

Meson hat das Konzept von Subprojekten. Dies ist eine Möglichkeit, ein Meson-Projekt in ein anderes zu verschachteln. Jedes Projekt, das mit Meson erstellt wird, kann erkennen, dass es als Subprojekt erstellt wird, und sich so erstellen, dass es leicht zu verwenden ist (normalerweise bedeutet dies als statische Bibliothek).

Um diese Art von Projekt als Abhängigkeit zu verwenden, könnten Sie es einfach kopieren und in das Verzeichnis subprojects Ihres Projekts extrahieren.

Es gibt jedoch einen einfacheren Weg. Sie können eine Wrap-Datei angeben, die Meson mitteilt, wie es diese für Sie herunterladen soll. Wenn Sie dieses Subprojekt dann in Ihrem Build verwenden, lädt Meson es während des Builds automatisch herunter und extrahiert es. Dies macht die Einbettung von Subprojekten extrem einfach.

Alle Wrap-Dateien müssen den Namen im Format <project_name>.wrap haben und sich im Verzeichnis subprojects befinden.

Derzeit hat Meson vier Arten von Wraps

  • wrap-file
  • wrap-git
  • wrap-hg
  • wrap-svn

Wrap-Format

Wrap-Dateien werden im Ini-Format geschrieben, mit einer einzigen Kopfzeile, die den Typ des Wraps enthält, gefolgt von Eigenschaften, die beschreiben, wie die Quellen bezogen, validiert und bei Bedarf modifiziert werden. Eine Beispiel-Wrap-Datei für den Wrap namens libfoobar hätte den Dateinamen libfoobar.wrap und würde wie folgt aussehen

[wrap-file]
directory = libfoobar-1.0

source_url = https://example.com/foobar-1.0.tar.gz
source_filename = foobar-1.0.tar.gz
source_hash = 5ebeea0dfb75d090ea0e7ff84799b2a7a1550db3fe61eb5f6f61c2e971e57663

Ein Beispiel für wrap-git sieht so aus

[wrap-git]
url = https://github.com/libfoobar/libfoobar.git
revision = head
depth = 1

Akzeptierte Konfigurationseigenschaften für Wraps

  • directory - Name des Stammverzeichnisses des Subprojekts, standardmäßig der Name des Wraps.

Seit 0.55.0 können diese in allen Wrap-Typen verwendet werden, sie waren zuvor für wrap-file reserviert

  • patch_url - Download-URL zum Abrufen eines optionalen Overlay-Archivs
  • patch_fallback_url - Fallback-URL, die verwendet wird, wenn der Download von patch_url fehlschlägt Seit: 0.55.0
  • patch_filename - Dateiname des heruntergeladenen Overlay-Archivs
  • patch_hash - SHA256-Checksumme des heruntergeladenen Overlay-Archivs
  • patch_directory - Seit 0.55.0 Overlay-Verzeichnis, Alternative zu patch_filename, falls Dateien lokal und kein heruntergeladenes Archiv sind. Das Verzeichnis muss in subprojects/packagefiles abgelegt werden.
  • diff_files - Seit 0.63.0 Kommagetrennte Liste lokaler Diff-Dateien (siehe Diff-Dateien unten).
  • method - Seit 1.3.0 Das von diesem Subprojekt verwendete Build-System. Standardmäßig meson. Unterstützte Methoden
    • meson erfordert eine Datei meson.build.
    • cmake erfordert eine Datei CMakeLists.txt. Details siehe.
    • cargo erfordert eine Datei Cargo.toml. Details siehe.

Speziell für wrap-file

  • source_url - Download-URL zum Abrufen des Quellarchivs der Wrap-Datei
  • source_fallback_url - Fallback-URL, die verwendet wird, wenn der Download von source_url fehlschlägt Seit: 0.55.0
  • source_filename - Dateiname des heruntergeladenen Quellarchivs
  • source_hash - SHA256-Checksumme des heruntergeladenen Quellarchivs
  • lead_directory_missing - für wrap-file, um den Namen des führenden Verzeichnisses zu erstellen. Benötigt, wenn die Quelldatei kein führendes Verzeichnis hat.

Seit 0.55.0 ist es möglich, in einer .wrap-Datei nur die Werte source_filename und patch_filename (ohne source_url und patch_url) zu verwenden, um ein lokales Archiv im Verzeichnis subprojects/packagefiles anzugeben. Die Einträge *_hash sind bei dieser Methode optional. Diese Methode sollte gegenüber dem alten Ansatz packagecache, der unten beschrieben wird, bevorzugt werden.

Seit 0.49.0 wird die Datei source_filename oder patch_filename, wenn sie im Verzeichnis subprojects/packagecache des Projekts gefunden wird, anstelle des Herunterladens verwendet, selbst wenn die Option --wrap-mode auf nodownload gesetzt ist. Die Hash-Prüfung der Datei wird durchgeführt.

Seit 1.3.0 wird, wenn die Umgebungsvariable MESON_PACKAGE_CACHE_DIR gesetzt ist, diese anstelle von subprojects/packagecache des Projekts verwendet. Dies ermöglicht die gemeinsame Nutzung des Caches über mehrere Projekte hinweg. Zusätzlich kann sie einen bereits extrahierten Quellcodebaum enthalten, solange er denselben Verzeichnisnamen wie das Feld directory in der Wrap-Datei hat. In diesem Fall wird das Verzeichnis vor dem Anwenden von Patches nach subprojects/ kopiert.

Speziell für VCS-basierte Wraps

  • url - Name des zu klonenden Git-Repositorys. Erforderlich.
  • revision - Name der auszucheckenden Revision. Muss entweder ein gültiger Wert (wie ein Git-Tag) für den checkout-Befehl des VCS sein oder (für Git) head, um den Standardzweig des Upstreams zu verfolgen. Erforderlich.

Speziell für wrap-git

  • depth - klont das Repository flach mit X Commits. Dies spart Bandbreite und Speicherplatz und sollte normalerweise immer angegeben werden, es sei denn, der Commit-Verlauf wird benötigt. Beachten Sie, dass Git immer flaches Klonen von Branches erlaubt, aber um Commit-IDs flach zu klonen, muss der Server uploadpack.allowReachableSHA1InWant=true unterstützen. (seit 0.52.0)
  • push-url - alternative URL zur Konfiguration als Git-Push-URL. Nützlich, wenn das Subprojekt entwickelt und Änderungen an den Upstream gesendet werden. (seit 0.37.0)
  • clone-recursive - klont auch Submodule des Repositorys (seit 0.48.0)

wrap-file mit Meson Build-Patch

Leider bauen die meisten Softwareprojekte auf der Welt nicht mit Meson. Aus diesem Grund erlaubt Meson die Angabe einer Patch-URL.

Aus historischen Gründen wird dies als "Patch" bezeichnet, dient aber als Overlay, um Dateien hinzuzufügen oder zu ersetzen, anstatt sie zu ändern. Die Datei muss ein Archiv sein; sie wird heruntergeladen und automatisch in das Subprojekt extrahiert. Die extrahierten Dateien enthalten eine Meson-Build-Definition für das gegebene Subprojekt.

Dieser Ansatz macht es extrem einfach, Abhängigkeiten einzubetten, die Änderungen am Build-System erfordern. Sie können die Meson-Build-Definition für die Abhängigkeit völlig isoliert schreiben. Dies ist viel besser, als dies in Ihrem eigenen Quellcodebaum zu tun, insbesondere wenn dieser Hunderttausende von Codezeilen enthält. Sobald Sie eine funktionierende Build-Definition haben, packen Sie einfach die Meson-Build-Dateien (und andere, die Sie geändert haben) in ein Zip-Archiv und legen Sie sie irgendwo ab, wo Sie sie herunterladen können.

Vor 0.55.0 wurden Meson-Build-Patches nur für den wrap-file-Modus unterstützt. Bei Verwendung von wrap-git muss das Repository alle Meson-Build-Definitionen enthalten. Seit 0.55.0 werden Meson-Build-Patches für alle Wrap-Modi unterstützt, einschließlich wrap-git.

Diff-Dateien

Seit: 0.63.0

Sie können auch lokale Patch-Dateien im diff-Format bereitstellen. Aus historischen Gründen werden sie als "Diff-Dateien" bezeichnet, da der Name "Patch" bereits für Overlay-Archive verwendet wird.

Die Diff-Dateien werden durch die Eigenschaft diff_files (eine kommagetrennte Liste) beschrieben und müssen lokal im Verzeichnis subprojects/packagefiles verfügbar sein.

Meson wendet die Diff-Dateien nach dem Extrahieren oder Klonen des Projekts und nach dem Anwenden des Overlay-Archivs (patch_*) an. Für diese Funktion muss das patch- oder git-Kommandozeilenwerkzeug verfügbar sein.

Die Diff-Dateien werden mit -p1 angewendet, d.h. die erste Pfadkomponente wird als zu entfernendes Präfix behandelt. Dies ist der Standard für Diffs, die von Git erzeugt werden.

[wrap-file]
directory = libfoobar-1.0

source_url = https://example.com/foobar-1.0.tar.gz
source_filename = foobar-1.0.tar.gz
source_hash = 5ebeea0dfb75d090ea0e7ff84799b2a7a1550db3fe61eb5f6f61c2e971e57663

diff_files = libfoobar-1.0/0001.patch, libfoobar-1.0/0002.patch

provide-Abschnitt

*Seit 0.55.0

Wrap-Dateien können die von ihnen bereitgestellten Abhängigkeiten im Abschnitt [provide] definieren.

[provide]
dependency_names = foo-1.0

Wenn eine Wrap-Datei die Abhängigkeit foo-1.0 bereitstellt, wie oben, greift jeder Aufruf von dependency('foo-1.0') automatisch auf dieses Subprojekt zurück, auch wenn kein Schlüsselwortargument fallback angegeben ist. Eine Wrap-Datei namens foo.wrap stellt implizit die Abhängigkeit namens foo bereit, auch wenn der Abschnitt [provide] fehlt.

Optionale Abhängigkeiten, wie dependency('foo-1.0', required: get_option('foo_opt')), wobei foo_opt eine Feature-Option ist, die auf auto gesetzt ist, greifen aus zwei Gründen nicht auf das in der Wrap-Datei definierte Subprojekt zurück

  • Sie ermöglicht es, die Abhängigkeit zuerst auf andere Weise zu suchen, z.B. mit cc.find_library('foo'), und greift nur dann zurück, wenn dies fehlschlägt
# this won't use fallback defined in foo.wrap
foo_dep = dependency('foo-1.0', required: false)
if not foo_dep.found()
  foo_dep = cc.find_library('foo', has_headers: 'foo.h', required: false)
  if not foo_dep.found()
    # This will use the fallback
    foo_dep = dependency('foo-1.0')
    # or
    foo_dep = dependency('foo-1.0', required: false, fallback: 'foo')
  endif
endif
  • Manchmal ist eine nicht gefundene Abhängigkeit einer Rückfallebene vorzuziehen, wenn das Feature nicht explizit vom Benutzer angefordert wurde. In diesem Fall greift dependency('foo-1.0', required: get_option('foo_opt')) nur zurück, wenn der Benutzer foo_opt auf enabled anstatt auf auto setzt. Seit 0.58.0 greift eine optionale Abhängigkeit wie oben auf das in der Wrap-Datei definierte Subprojekt zurück, wenn wrap_mode auf forcefallback gesetzt ist oder force_fallback_for das Subprojekt enthält.

Wenn es gewünscht ist, für eine optionale Abhängigkeit zurückzufallen, müssen die Schlüsselwortargumente fallback oder allow_fallback explizit übergeben werden. Seit 0.56.0 verwendet dependency('foo-1.0', required: get_option('foo_opt'), allow_fallback: true) den Fallback, auch wenn foo_opt auf auto gesetzt ist. In Version 0.55.0 konnte dasselbe erreicht werden mit dependency('foo-1.0', required: get_option('foo_opt'), fallback: 'foo').

Dieser Mechanismus geht davon aus, dass das Subprojekt meson.override_dependency('foo-1.0', foo_dep) aufruft, damit Meson weiß, welches Abhängigkeitsobjekt als Fallback verwendet werden soll. Da diese Methode in Version 0.54.0 eingeführt wurde, können als Übergangshilfe für Projekte, die sie noch nicht nutzen, der Variablenname in der Wrap-Datei mit Einträgen im Format foo-1.0 = foo_dep angegeben werden.

Zum Beispiel, wenn eine ausreichend aktuelle Version von GLib verwendet wird, die meson.override_dependency() verwendet, um glib-2.0, gobject-2.0 und gio-2.0 zu überschreiben, würde eine Wrap-Datei so aussehen

[wrap-git]
url=https://gitlab.gnome.org/GNOME/glib.git
revision=glib-2-62
depth=1

[provide]
dependency_names = glib-2.0, gobject-2.0, gio-2.0

Bei älteren GLib-Versionen müssen die Abhängigkeitsvariablennamen angegeben werden

[wrap-git]
url=https://gitlab.gnome.org/GNOME/glib.git
revision=glib-2-62
depth=1

[provide]
glib-2.0=glib_dep
gobject-2.0=gobject_dep
gio-2.0=gio_dep

Programme können auch über Wrap-Dateien mit dem Schlüssel program_names bereitgestellt werden

[provide]
program_names = myprog, otherprog

Mit einer solchen Wrap-Datei greift find_program('myprog') automatisch auf das Subprojekt zurück, vorausgesetzt, es verwendet meson.override_find_program('myprog').

CMake-Wraps

Hinweis: Dies ist experimentell und hat keine Rückwärts- oder Vorwärtskompatibilitätsgarantien. Siehe Meson's Regeln zum Mischen von Build-Systemen.

Da das CMake-Modul den öffentlichen Namen der bereitgestellten Abhängigkeiten nicht kennt, kann eine CMake-.wrap-Datei nicht die Syntax dependency_names = foo verwenden. Stattdessen sollte die Syntax dep_name = <target_name>_dep verwendet werden, wobei <target_name> der Name einer CMake-Bibliothek ist, bei der alle nicht-alphanumerischen Zeichen durch Unterstriche _ ersetzt wurden.

Zum Beispiel hätte ein CMake-Projekt, das add_library(foo-bar ...) in seiner CMakeList.txt enthält und das Anwendungen normalerweise über den Abhängigkeitsnamen foo-bar-1.0 (z.B. über pkg-config) finden würden, eine Wrap-Datei wie diese

[wrap-file]
...
method = cmake
[provide]
foo-bar-1.0 = foo_bar_dep

Cargo-Wraps

Hinweis: Dies ist experimentell und hat keine Rückwärts- oder Vorwärtskompatibilitätsgarantien. Siehe Meson's Regeln zum Mischen von Build-Systemen.

Cargo-Subprojekte überschreiben automatisch den Abhängigkeitsnamen <package_name>-<version>-rs

  • package_name ist in der Sektion [package] name = ... von Cargo.toml definiert.
  • version ist die API-Version, die aus [package] version = ... wie folgt abgeleitet wird
    • x.y.z -> 'x'
    • 0.x.y -> '0.x'
    • 0.0.x -> '0' Dies ermöglicht unterschiedliche Abhängigkeiten für inkompatible Versionen desselben Crates.
  • Das Suffix -rs wird hinzugefügt, um es von regulären Systemabhängigkeiten zu unterscheiden, z.B. gstreamer-1.0 ist eine systemweite Pkg-Config-Abhängigkeit und gstreamer-0.22-rs ist eine Cargo-Abhängigkeit.

Das bedeutet, die .wrap-Datei sollte in ihrem [provide]-Abschnitt dependency_names = foo-1-rs haben, wenn Cargo.toml den Paketnamen foo und die Version 1.2 hat.

Beachten Sie, dass die Versionskomponente in Meson 1.4 hinzugefügt wurde, frühere Versionen verwendeten das Format <package_name>-rs.

Cargo-Subprojekte erfordern einen TOML-Parser. Python >= 3.11 hat einen eingebauten, ältere Python-Versionen erfordern entweder das externe Modul tomli oder das Programm toml2json.

Zum Beispiel würde ein Cargo-Projekt mit dem Paketnamen foo-bar eine Wrap-Datei wie diese haben

[wrap-file]
...
method = cargo
[provide]
dependency_names = foo-bar-0.1-rs

Zusätzlich, wenn die Datei meson/meson.build existiert, ruft Meson subdir('meson') auf, wo das Projekt manuelle Logik hinzufügen kann, die normalerweise Teil von build.rs wäre. Einige Namenskonventionen müssen beachtet werden

  • Die Variable extra_args ist vordefiniert und kann verwendet werden, um beliebige Rust-Argumente hinzuzufügen. Dies wird typischerweise als extra_args += ['--cfg', 'foo'] verwendet.
  • Die Variable extra_deps ist vordefiniert und kann verwendet werden, um zusätzliche Abhängigkeiten hinzuzufügen. Dies wird typischerweise als extra_deps += dependency('foo') verwendet.

Seit 1.5.0 können Cargo-Wraps auch mit einer Cargo.lock-Datei im Stammverzeichnis des (Sub-)Projektquellbaums bereitgestellt werden. Meson lädt diese Datei automatisch und wandelt sie in eine Reihe von Wrap-Definitionen um.

Verwendung von gewrappten Projekten

Wraps bieten eine bequeme Möglichkeit, ein Projekt in Ihr Subprojektverzeichnis zu erhalten. Dann verwenden Sie es als reguläres Subprojekt (siehe Subprojekte).

Wraps erhalten

Normalerweise möchten Sie Ihre Wraps nicht von Hand schreiben.

Es gibt ein Online-Repository namens WrapDB, das viele gebrauchsfertige Abhängigkeiten bereitstellt. Sie können mehr über WrapDB hier lesen.

Es gibt auch einen Meson-Unterbefehl zum Abrufen und Verwalten von Wraps (siehe Verwendung von wraptool).

Die Ergebnisse der Suche sind