Automatisches Filtern von „Provides“ und „Requires“
Zusammenfassung
Das in RPM enthaltene automatische „Requires“- und „Provides“-System ist sehr nützlich; es erkennt jedoch manchmal „private“ Paketfunktionen, die nicht als global beworben werden sollten, Dinge, die „einfach falsch„ sind, oder Dinge, die durch Richtlinien verboten sind (z. B. Abhängigkeiten aus dem Verzeichnis %{_docdir}).
Beispielsweise:
-
Diverse „Plugin“-Pakete (z. B. Pidgin, Perl, Apache, KDE) haben „Provides“ für private gemeinsam genutzte Bibliotheken außerhalb des Systempfads.
-
Dateien im Verzeichnis
%{_docdir}werden routinemäßig gescannt und können Provides/Requires auslösen, wenn dies durch die Richtlinien ausdrücklich verboten ist.
Diese Richtlinie beschreibt, wie man unter Fedora die Requires und Provides filtert.
-
MUSS: Pakete dürfen keine RPM-Abhängigkeitsinformationen bereitstellen, wenn diese Informationen nicht global verfügbar sind, oder anderweitig verarbeitet werden (z.B. über virtuelle „Provides“). Beispiel: Ein Plugin-Paket, das eine binäre gemeinsam genutzte Bibliothek enthält, darf diese Bibliothek nicht als „Provides“ bereitstellen, es sei denn, sie ist über die Systembibliothekspfade zugänglich.
-
MUSS: Beim Filtern automatisch generierter RPM-Abhängigkeiten muss das von Fedora implementierte Filtersystem verwendet werden, es sei denn, es gibt einen zwingenden Grund, davon abzuweichen.
Verwendung
Ort des Makro-Aufrufs
Es wird dringend empfohlen, diese Filtermakros vor %description, aber nach allen anderen Definitionen aufzurufen. Dadurch bleiben sie in allen Paketen an einem einheitlichen Ort und werden nicht mit anderen Abschnitten verwechselt.
Variante mit regulären Ausdrücken
Diese Filter verwenden reguläre Ausdrücke. Die für diese Filter verwendete Variante regulärer Ausdrücke entspricht dem POSIX.2-Standard (siehe die Handbuchseite regex(7)). In dieser Variante müssen die Zeichen`^.[$()|*+?{` mit Rückschrägstrichen maskiert werden. Da rpm Rückschrägstriche beim Parsen von Spec-Dateien interpretiert, müssen Sie für alle Maskierungen einen doppelten Rückschrägstrich verwenden. Ein einzelner Rückschrägstrich (\) wird durch vier Rückschrägstriche dargestellt.
Der Engine für reguläre Ausdrücke wird nur die endgültige Zeichenkette nach der RPM-Makro-Expansion übergeben. Daher können Sie keine nicht maskierten Daten über RPM-Makros verwenden. Wenn Sie beispielsweise eine Liste von Dateien generieren, die in einem Makro abgeglichen werden sollen, und diese Liste libfoo.so enthält, müssen Sie libfoo\\.so verwenden, um „.“ zu maskieren. Beispiel:
%global to_exclude libfoo\\.so
%global __requires_exclude_from ^%{_datadir}/%{to_exclude}$
Verhindern, dass Dateien/Verzeichnisse nach Abhängigkeiten durchsucht werden (Vorfilterung)
Die Makros %__requires_exclude_from und %__provides_exclude_from können in einer Spec-Datei definiert werden, um zu verhindern, dass der Abhängigkeitsgenerator bestimmte Dateien oder Verzeichnisse nach Abhängigkeiten durchsucht. Diese Makros sollten mit einem regulären Ausdruck definiert werden, der alle Verzeichnisse oder Dateien abdeckt. Zum Beispiel:
# Do not check any files in docdir for requires
%global __requires_exclude_from ^%{_docdir}/.*$
# Do not check .so files in an application-specific library directory
# or any files in the application's data directory for provides
%global __provides_exclude_from ^(%{_libdir}/%{name}/.*\\.so.*|%{_datadir}/myapp/.*)$
Beachten Sie, dass dieses Makro das Makro %filter_provides_in aus den alten Filterrichtlinien ersetzt, aber nicht dieselbe Funktion erfüllt. Insbesondere:
-
Das alte Makro konnte mehrfach aufgerufen werden. Dieses hier verwendet nur den zuletzt definierten regulären Ausdruck.
-
Das alte Makro riet davon ab, den Anfang des regulären Ausdrucks mit
^zu verankern. Dieses Makro empfiehlt die Verankerung, da es die Kompatibilitätsprobleme des alten Makros vermeidet. -
Beim alten Makro war es üblich, einen Verzeichnisnamen anzugeben, um rekursiv alle Elemente in einem Verzeichnis zu finden. Beim neuen Makro müssen Sie möglicherweise
.*angeben, da Sie Ihre regulären Ausdrücke verankern sollten.
„Provides“ und „Requires“ nach dem Einlesen filtern
Zusätzlich zur Verhinderung des automatischen Abhängigkeitsaufbaus durch Einlesen von Dateien und Verzeichnissen können Sie RPM anweisen, gefundene Abhängigkeiten zu verwerfen, bevor sie in den RPM-Metadaten gespeichert werden. Verwenden Sie dazu __requires_exclude und __provides_exclude. Diese Makros müssen als reguläre Ausdrücke definiert werden. Wenn ein vom automatischen Abhängigkeitsgenerator von RPM erstellter Eintrag mit dem regulären Ausdruck übereinstimmt, wird er aus den „Requires“ bzw. den „Provides“ herausgefiltert. Beispiel:
# This might be useful if plugins are being picked up by the dependency generator
%global __provides_exclude ^libfoo-plugin\\.so.*$
# Something like this could be used to prevent excess deps from an
# example python script in %doc
%global __requires_exclude ^/usr/bin/python$
Diese Makros erfüllen einen ähnlichen Zweck wie das alte Makro %filter_from_provides, sind aber anders implementiert. Insbesondere verwendete jenes Makro sed-Ausdrücke, während dieses einen regulären Ausdruck benötigt.
Vereinfachte Makros für gängige Anwendungsfälle
In manchen Fällen ist das Filtern überflüssiger Provides:-Einträge für alle Pakete, die ähnliche Funktionen bieten, recht allgemein gehalten. Es gibt einfache Makros, welche die Filter für diese Fälle korrekt einrichten, so dass Sie die Filterung mit nur einer Code-Zeile durchführen können. Falls Sie mehr filtern müssen, als das einfache Makro ermöglicht, können Sie weiterhin die oben genannten Makros verwenden.
Perl
Perl-Erweiterungsmodule können mithilfe dieses Makros gefiltert werden:
%{?perl_default_filter}
Im Wesentlichen filtert dies Abhängigkeiten heraus, die aus %doc-Dateien, aus Modulen, die nicht mit Linux zusammenhängen, und aus Fehlern im automatischen Abhängigkeitsgenerator entstehen.
Wenn Sie sowohl benutzerdefinierte Filter als auch %perl_default_filter verwenden möchten, definieren Sie zuerst Ihre Filter und rufen Sie anschließend %perl_default_filter auf. Das Standardfilter-Makro behält die zuvor definierten Filter bei. Zum Beispiel:
# Filter all provides from some directory
%global __provides_exclude_from %{_libexecdir}/autoinst
# Filter some specific requires by name
%global __requires_exclude ^perl\\((autotest|basetest)
# All of the default filters
%{?perl_default_filter}
Beispiele
Pidgin-Plugin-Paket
Auf einem x86_64-System stellt pidgin-libnotify die Bibliothek pidgin-libnotify.so()(64bit) bereit, was nicht korrekt ist, da sich diese Bibliothek nicht in den vom System durchsuchten Bibliothekspfaden befindet. Es handelt sich um ein privates, nicht globales „Provides“, das daher nicht global über RPM zugänglich gemacht werden darf.
Um es herauszufiltern, könnten wir Folgendes verwenden:
%global __provides_exclude_from ^%{_libdir}/purple-2/.*\\.so$
Private Bibliotheken
Das Filtern privater Bibliotheken ist derzeit nicht trivial. Der Grund dafür ist, dass die Symbole, die aus den privaten Bibliotheken herausgefiltert werden sollen, üblicherweise von den öffentlichen Anwendungen benötigt werden, die das Paket mitliefert. Um die Symbole zu filtern, müssen Sie herausfinden, welche Symbole RPM für die private Bibliothek extrahiert, und diese anschließend sowohl in %__provides_exclude als auch in %__requires_exclude entfernen.
Nehmen wir beispielsweise an, Sie paketieren eine Anwendung namens foo, die die Datei %{_libdir}/foo/libprivate.so erzeugt, welche Sie filtern möchten, sowie die Datei %{_bindir}/foobar, die diese private Bibliothek benötigt. Sie könnten Folgendes tun:
-
Bauen Sie zuerst das RPM-Paket:
$ rpmbuild -ba foo.spec -
Dann ermitteln Sie, was RPM als „Provides“ für die private Bibliothek gefunden hat:
$ rpm -qp foo-1.0-1.x86_64.rpm:
libprivate.so()(64bit) foo = 1.0-1.fc19 foo(x86-64) = 1.0-1.fc19
-
Beachten Sie, dass
libprivate.so()(64bit)anscheinend das einzige Symbol ist, das RPM für dieses Paket extrahiert hat. Auf 32-Bit-Systemen lautet das „Provides“libprivate.so, daher muss Ihr regulärer Ausdruck beide erfassen. -
Fügen Sie die Ausschlüsse zur Spec-Datei für sowohl „Requires“ als auch „Provides“ hinzu:
[...]
%global _privatelibs libprivate[.]so.*
%global __provides_exclude ^(%{_privatelibs})$
%global __requires_exclude ^(%{_privatelibs})$
[...]
Ein komplexeres Beispiel finden Sie auf der Mailingliste. Die Wartung kann aufwendig sein, wenn die privaten Upstream-Bibliotheken ihre Namen ändern, aber es ist derzeit die einzige Möglichkeit. Möglicherweise gibt es in Zukunft eine bessere Lösung, aber es gibt noch keine konkreten Pläne, wann diese implementiert werden soll.
Architekturspezifische Erweiterungen für Skriptsprachen
Um beispielsweise sicherzustellen, dass ein architekturspezifisches perl-*-Paket keine Dinge bereitstellt oder benötigt, was es nicht sollte, könnten wir einen Aufruf wie diesen verwenden:
# we don't want to provide private Perl extension libs
%{?perl_default_filter}
%{_docdir}-Filterung
Gemäß den Richtlinien darf nichts unter %{_docdir} etwas „Requires“ oder „Provides“ erzeugen. Wir können zu diesem Zweck verhindern, dass alles unter %{_docdir} gescannt wird:
# we don't want to either provide or require anything from _docdir, per policy
%global __provides_exclude_from ^%{_docdir}/.*$
%global __requires_exclude_from ^%{_docdir}/.*$
Zusätzliche Informationen
Weitere Informationen zum Abhängigkeitsgenerator von RPM finden Sie hier: https://rpm-software-management.github.io/rpm/manual/dependency_generators.html
Want to help? Learn how to contribute to Fedora Docs ›