Paketbaurichtlinien für Mono
Dateiorte und Architekturen
Eine Zeit lang betrachtete Fedora Mono-Pakete als architekturspezifisch und installierte die Assemblies in %\{libdir}. Nach Rücksprache mit dem Entwicklerteam betrachten wir Mono-Pakete nun jedoch als architektur- (und plattform-)unabhängig. Das bedeutet, dass Mono-Pakete korrekt im GAC in %{_monogacdir} oder in _/usr/lib/PAKETNAME installiert werden sollten.
Eine erwähnenswerte Ausnahme bilden alle ELF-Binärbibliotheken, die in einem Mono-Paket generiert wurden und korrekt in %{_libdir} installiert werden müssen, da diese Dateien architekturspezifisch sind.
Auch wenn wir Mono-Pakete als architekturunabhängig betrachten, dürfen sie nicht als „noarch“ gekennzeichnet werden. Obwohl die Assemblies identisch sind, können sich die Dateien aufgrund von Zeichenketten, die auf die Bauarchitektur verweisen, unterscheiden.
Da manche Architekturen Mono schlichtweg nicht unterstützen, muss jedes Mono-Paket (sei es eine Bibliothek oder eine Mono-Anwendung) Folgendes enthalten:
ExclusiveArch: %{mono_arches}
Um Änderungen an der Architekturliste zu ermöglichen, muss %mono_arches anstelle einer Liste von Architekturen verwendet werden.
gacutil in einer Spec-Datei
gacutil wird verwendet, um DLLs bei Mono zu registrieren (man kann es sich wie die Installation einer Bibliothek vorstellen – was es ja auch ist!).
Beim Paketieren jeder Mono-Anwendung, die Bibliotheken generiert, welche dann von gacutil registriert werden (z. B. mysql-connector-net), benötigen Sie in der Spec-Datei etwa Folgendes:
%install
mkdir -p %{buildroot}/%{_monogacdir}
gacutil -i bin/mono-1.0/release/MySql.Data.dll -f -package mysql-connector-net -root %{buildroot}/usr/lib
%files
%{_monogacdir}/MySql.Data
%{_monodir}/mysql-connector-net/
gacutil-Format
-i = input dll -f = check references -package = package name -root = build root
RPMs und Quellen
Erstellen Sie RPMs nicht auf Basis von aus dem Quellcode kompilierten Mono-Versionen. Es mag bei Ihnen funktionieren, aber wahrscheinlich nicht bei anderen Benutzern!
Während es bei anderen Programmen noch möglich sein mag, den Quellcode für einen Teil des Gesamtpakets neu zu kompilieren (z.B. ist gnome-panel Teil von gnome oder evolution-data-server Teil von evolution), sollten Sie dies bei Mono nicht versuchen.
Wenn Sie den Quellcode verwenden möchten, MÜSSEN Sie vorher die RPMs entfernen.
Das Kompilieren von Mono ist keine triviale Angelegenheit und kann sogar fehlschlagen (wenn Sie den Quellcode herunterladen, müssen Sie auch make get-monolite-latest ausführen, welches eine Version der corelib und mcs herunterlädt, die zum Kompilieren der wichtigsten C#-Compiler benötigt werden - monolite-latest funktioniert nicht immer und Sie haben am Ende kein funktionierendes Mono).
rpmlint und Mono-Pakete
rpmlint ist ein Programm, das Pakete auf häufig auftretende Probleme überprüft. Bei Mono-Paketen können einige der rpmlint-Meldungen ignoriert werden.
Mono installiert Binärdateien in %\{libdir}//bin mit symbolischen Links zurück nach _/usr/bin. rpmlint akzeptiert dies nicht und erzeugt eine Fehlermeldung (was an sich korrekt wäre). Es erkennt außerdem nicht, dass Mono-Bibliotheken nicht im ELF-Format vorliegen und kann diesbezüglich ebenfalls Fehlermeldungen erzeugen.
rpmlint erkennt auch alle im rpm-Paket installierten .pc-Dateien (siehe unten).
-devel-Pakete
Mono-Pakete müssen .pc-Dateien in einem -devel-Paket unterbringen, selbst wenn dies die einzige enthaltene Datei ist. Würden wir .pc-Dateien in Nicht-Devel-Paketen zulassen, entstünden Nicht-Devel-Pakete, die von -devel-Paketen abhängen, was die Installation unnötig aufblähen würde.
Leere debuginfo-Pakete
Manchmal führt das Erstellen von Mono-Paketen zu einem leeren Teilpaket „debuginfo“, das keine zu installierenden Dateien enthält. Siehe Packaging/Debuginfo
Unkorrektes Verhalten
Verteilen vorkompilierter Assemblies
Da Mono-.dlls im Allgemeinen architekturunabhängig sind, können Upstream-Entwickler Tarballs ausliefern, die vorkompilierte .dll- und .exe-Dateien installieren. Alle Pakete müssen aus dem Quellcode erstellt werden, daher muss der Paketierer diese Tarballs im Auge behalten und sicherstellen, dass er sie nicht verwendet. (Dies kann auch bei Aktualisierungen unbemerkt passieren, daher muss der Paketierer jedes Mal sicherstellen, dass er aus dem Quellcode kompiliert, wenn der Tarball geändert wird.)
Verteilen von .DLLs aus anderen Projekten
Die Website des Mono-Projekts macht diesen Vorschlag
Manchmal möchten Entwickler eine Bibliothek an andere Entwickler weitergeben, verfügen aber möglicherweise nicht über eine API-stabile Bibliothek oder eine Bibliothek, die im Laufe der Zeit nicht ausreichend ausgereift ist, um die Abwärtskompatibilität zu gewährleisten. Alternativ möchten sie auch nicht mehrere Pakete mit verschiedenen Versionen für die Benutzer bereitstellen. [...] Um dieses Problem zu lösen, empfehlen wir Folgendes: * Der Bibliotheksentwickler liefert eine korrekt konfigurierte pkg-config-Datei aus. * Die Bibliotheksnutzer fügen ihrem Makefile ein „update-libraries“-Ziel hinzu, das die neueste Version einer Bibliothek aus einem Systemverzeichnis in ihre Anwendungsquellcodeverteilung importiert. * Die Bibliotheksnutzer liefern diese Bibliothek als Teil ihres Pakets aus.
Dieser Vorschlag mag zwar die Verwendung instabiler Bibliotheks-APIs vereinfachen, ist aber äußerst schlechte Praxis. Die Verwendung von Bibliotheken auf diese Weise birgt dieselben Probleme wie die Verknüpfung mit statischen Bibliotheken, insbesondere kann die Anwendung noch lange unter Sicherheitslücken in der Bibliothek leiden, selbst nachdem diese schon längst upstreamseitig behoben wurden. Mono-Anwendungen unter Fedora können keine DLLs aus dem Quellcode einbinden (selbst wenn diese aus dem Quellcode kompiliert wurden). Dies ist ein schwerwiegendes Problem und muss behoben werden.
Es gibt verschiedene Techniken, um das Vorhandensein dieser Bibliotheken nachzuweisen, aber keine davon ist absolut sicher. Wenn Sie eine bessere Methode kennen, fügen Sie sie bitte hinzu:
-
Der Upstream-Tarball enthält .dll-Dateien, die nicht aus dem im Paket enthaltenen Quellcode neu erstellt wurden.
-
Überprüfen Sie die installierten .dll-Dateien auf solche, die denselben Namen wie System-.dll-Dateien haben oder verdächtig fehl am Platz sind (das Paket heißt beispielsweise myDiary, aber enthält mysql.dll, sqlite.dll und gtk-sharp.dll)
-
Die Quellverzeichnisse sehen seltsam aus:
PAKETNAME/ src/ data/ libs/ gtk-sharp/ atk-sharp/
Neudefinition von _libdir
Paketierer sollten die Variable _libdir in ihrer Spec-Datei nicht neu definieren. Eine Neudefinition dieses Makros verschleiert Probleme, anstatt sie zu beheben. Paketierer sollten Folgendes beachten:
-
Ermitteln Sie anhand der Paketbaurichtlinien, in welche Verzeichnisse die Dateien installiert werden sollen.
-
Die Bauskripte des Pakets müssen so gepatcht werden, dass die Pakete an diesen Speicherorten installiert werden.
-
Identifizieren Sie Stellen, an denen im Paket die alten Speicherorte anstelle der neuen fest kodiert sind, und korrigieren Sie diese.
-
Melden Sie die Probleme entweder dem Upstream-Projekt oder reichen Sie Patches ein. Beachten Sie, dass Upstream-Projekte im Allgemeinen Patches begrüßen, die es Paketentwicklern ermöglichen, Installationsverzeichnisse während des Bauprozesses neu zu definieren – weniger jedoch Patches, die die fest kodierten Standardwerte des Upstream-Projekts in unsere fest kodierten Standardwerte ändern.
Ziel definieren
Dies wurde kurzzeitig praktiziert, als wir versuchten, Mono-Anwendungen als architekturunabhängig zu paketieren. Damals war es nicht notwendig (die eigentliche Lösung bestand darin, AC_CANONICAL_* in der configure.ac-Datei nicht mehr zu verwenden), und es ist definitiv nicht mehr erforderlich, da wir keine architekturunabhängigen Mono-Pakete mehr erstellen.
Glossar
-
AOT: Ahead Of Time (Vorzeitkompilierung). Dies bezeichnet üblicherweise die ELF-Datei mit der Endung .so, die durch die Vorabkompilierung einer Assembly entsteht. AOTs sind für bestimmte Daten von den Assemblies abhängig, aus denen sie generiert wurden (im Gegensatz zu ihren Entsprechungen in Python und Java). AOTs werden explizit und nicht automatisch erstellt.
-
Assembly: Eine Assembly ist die EXE- oder DLL-Datei, die beim Kompilieren einer Mono-Anwendung entsteht. Diese unterscheiden sich von den EXE- oder DLL-Dateien, die beim Kompilieren eines C- oder C++-Programms unter Windows erzeugt werden. Eine Assembly enthält CIL-Code anstelle von Maschinencode.
-
CIL: CIL steht für „Common Intermediate Language“ (Gemeinsame Zwischensprache). Sie ist im Wesentlichen äquivalent zu Java-Bytecode und im Allgemeinen architekturübergreifend portierbar. Bestimmte Programmierpraktiken (z.B. der Aufruf systemeigener Bibliotheken) können jedoch zu CIL-Code führen, der nicht auf allen Architekturen ausgeführt werden kann.
-
GAC: GAC steht für „Global Assembly Cache“ (Globaler Assembly-Cache). Es handelt sich um einen maschinenweiten .NET-Assembly-Cache.
-
Glue Libraries: Bibliotheken, die eine in C oder C++ geschriebene Systembibliothek mit Mono verbinden. Diese Wrapper sind separat und unterscheiden sich von AOTs.
Want to help? Learn how to contribute to Fedora Docs ›