[X] Softwareinstallation unter Linux
-
1 Vorwort
1.1 Einleitung
Willkommen zu meinem zweiten Artikel, in dem es sich um Softwareinstallation unter Linux dreht. Wir werden ein Beispiel-Programm in ein installierbares Paket mit Menüeintrag verwandeln.
1.2 Voraussetzungen
Die verwendete IDE bzw. das verwendete Buildsystem sollte keine Rolle spielen. Auch sind keine Kenntnisse in gtkmm notwendig, da dies nur eine Nebenrolle spielt und das Beispiel auf andere Libraries übertragbar sein sollte.
Sie sollten einfache C- und C++-Kenntnisse mitbringen und bereits etwas Erfahrung mit der Bash, sowie mit Linux allgemein haben.
2 Das Beispielprogramm
Bei unserem Beispiel handelt es sich um ein einfaches Gtkmm-Programm, welches ein Bild anzeigen. Es besteht aus einer Source-Datei namens main.cpp mit folgendem Inhalt:
#include <gtkmm.h> int main(int argc, char** argv) { Gtk::Main kit(argc, argv); Gtk::Window win; Gtk::Image img("hallowelt.png"); win.add(img); win.show_all(); kit.run(win); }
Sowie der hallowelt.png, ein simples PNG-Bild, welches im selben Verzeichnis wie unser Beispiel liegt:
Kompilieren wir nun dieses Beispiel mit:
g++ `pkg-config gtkmm-2.4 --cflags --libs` main.cpp -o hallowelt
Anschließend starten wir das Programm mit:
./hallowelt
Oben links sollte ein Fenster erscheinen, welches das Bild darstellt:
Schauen wir uns nun die wichtige Zeile in diesem Programm an:
Gtk::Image img("hallowelt.png");
Hier wird die hallowelt.png geladen, welche im gleichen Verzeichnis wie die Binärdatei liegt. Es handelt sich um einen relativen Pfad, doch zu was ist er relativ? Leider nicht zum Ort der Binärdatei, wie angenommen, sondern zum Arbeitsverzeichnis.
Dies lässt sich leicht zeigen. Wir verändern das Arbeitsverzeichnis indem wir einen Ordner hoch springen:~/C++/hallowelt$ cd .. ~/C++$
Nun starten wir unser Programm nochmal:
~/C++$ ./hallowelt/hallowelt
Ein kleines Fenster erscheint, welches einen Platzhalter enthält, da das Bild nicht gefunden wurde. Es wurde versucht die Datei mit dem Pfad "~/C++/hallowelt.png" zu öffnen.
3 BinReloc
Um dieses Problem zu beheben, verwenden wir die C-Library "BinReloc", welche eine Funktion bereitstellt, um den Ort der Binärdatei herauszufinden. Unter ftp://ftp.sunsite.dk/projects/autopackage/tools/binreloc-2.0.tar.gz kann man sich den SourceCode herunterladen. Nach dem entpacken wechseln wir in der Konsole zu dem Verzeichniss und lassen uns Header und Source erstellen:
~/Desktop/binreloc-2.0$ ./generate.pl normal Source code written to 'binreloc.c' Header written to 'binreloc.h' ~/Desktop/binreloc-2.0$
Nun können wir binreloc.h und binreloc.c in unser hallowelt-Verzeichnis kopieren.
Wir binden die Header-Datei ein und erstellen eine Funktion die BinReloc initialisiert:#include <gtkmm.h> #include <iostream> #include "binreloc.h" void InitBinReloc() { BrInitError error; // Hier wird der Error-Code gespeichert if(!br_init(&error)) // Gibt true zurück wenn alles gut ging { std::cerr << "Warning: BinReloc failed to initialize (error code " << error << ")\n" << "Will fallback to hardcoded default path." << std::endl; } }
Nun benutzen wir die Funktion
char* br_find_exe_dir(const char* fallback)
, welche uns den Pfad als C-String zurück gibt. Sollte BinReloc nicht richtig initialisiert worden sein, bekommen wir eine Kopie von fallback. Den C-String müssen wir per Hand wieder freigaben, deswegen kapseln wir uns die Funktion:std::string ExeDir() { char* temp = br_find_exe_dir(""); std::string exe_dir(temp); free(temp); return exe_dir; }
In der main-Funktion ergänzen wir das Initialisieren von BinReloc:
int main(int argc, char** argv) { InitBinReloc(); Gtk::Main kit(argc, argv); Gtk::Window win;
Nun kommen wir zum Laden der Bilddatei. Hierbei verwenden wir jetzt einen absoluten Pfad, der mit dem Pfad der Binärdatei beginnt:
Gtk::Image img(ExeDir() + "/hallowelt.png"); win.add(img); win.show_all(); kit.run(win); }
Jetzt können wir unser Programm kompilieren und testen. Zuerst kompilieren wir die BinReloc-Library mit dem C-Compiler. Dabei muss die Variable ENABLE_BINRELOC gesetzt sein:
~/C++/hallowelt$ gcc -DENABLE_BINRELOC -o binreloc.o -c binreloc.c
Anschließend folgt unser Programm. Wir testen ob das Bild auch angezeigt wird, wenn wir das Arbeitsverzeichnis ändern:
~/C++/hallowelt$ g++ `pkg-config gtkmm-2.4 --cflags --libs` main.cpp binreloc.o -o hallowelt ~/C++/hallowelt$ ./hallowelt ~/C++/hallowelt$ cd .. ~/C++$ ./hallowelt/hallowelt ~/C++$
In beiden Fällen sollte das Bild angezeigt werden.
4 Die Linuxverzeichnisstruktur
Doch unter Linux liegen Dateien eines Programms nicht in einem Ordner. Stattdessen gibt es verschiedene Ordner, die entsprechende Typen der Programmdateien enthalten. Das einfachste Beispiel ist /usr/bin/. Hier wird die Binärdatei jedes Programms gespeichert. Daten, wie unser Bild, werden in /usr/share/<Programmname>/ abgelegt.
Da es auch unter Linux die Möglichkeit gibt, Programme nur für einen Benutzer zu installieren, können diese beiden Pfade auch wie folgt lauten:
/usr/bin/ -> [b]/home/<Benutzername>/.local/bin/[/b] /usr/share/<Programmname>/ -> [b]/home/<Benutzername>/.local/share/<Programmname>/[/b]
Der Ordner .local exisitiert bereits im Home-Verzeichnis, ist allerdings versteckt (Unter Linux werden alle Dateien versteckt die mit einem Punkt beginnen).
Eine weitere Möglichkeit wäre die Installation auf einer anderen Festplatte:/usr/bin/ -> [b]/media/sda2/usr/bin/[/b] /usr/share/<Programmname>/ -> [b]/media/sda2/usr/share/<Programmname>/[/b]
Alle diese Pfade sind gleich, bis auf den sogenannten Prefix, der in diesen drei Beispiel "/usr", "/home/jhasse/.local" und "/media/sda2/usr" wär. Um unser Programm richtig in Linux zu integrieren, müssen wir auch solch eine Struktur aufbauen. Dazu erstellen wir in unserem "hallowelt"-Ordner einen "bin"-Ordner und einen "share"-Ordner, der noch einen Ordner mit dem Namen "hallowelt" enthält. Zum Schluss verschieben wir die hallowelt.png nach share/hallowelt:
~/C++/hallowelt$ mkdir bin ~/C++/hallowelt$ mkdir share ~/C++/hallowelt$ cd share ~/C++/hallowelt/share$ mkdir hallowelt ~/C++/hallowelt/share$ cd .. ~/C++/hallowelt$ mv hallowelt.png share/hallowelt/ ~/C++/hallowelt$
Nun müssen wir unseren Quellcode anpassen. Eine neue Funktion muss her, die den Prefix des bin-Ordners zurück gibt, in der die Binärdatei liegt, und anschließend share/ dranhängt. Diese Funktion existiert bereits in BinReloc, wir müssen sie nur noch kapseln:
std::string DataDir() { char* temp = br_find_data_dir("/usr/share"); std::string data_dir(temp); free(temp); return data_dir; }
Nun rufen wir diese Funktion auf, wenn wir unsere Bilddatei laden und hängen "/hallowelt/hallowelt.png" an:
Gtk::Image img(DataDir() + "/hallowelt/hallowelt.png");
Was genau passiert hier? Die br_find_data_dir-Funktion findet den Pfad der exe-Datei heraus:
/home/jhasse/C++/beispiel/bin/
Sie erkennt, dass wir uns in einem bin-Ordner befinden und springt ein Verzeichniss nach oben, wir erhalten nun den Prefix:
/home/jhasse/C++/beispiel/
Als letztes hängt die Funktion noch share/ dran:
/home/jhasse/C++/beispiel/share/
Anschließend wird von uns "/hallowelt/hallowelt.png" hinzugefügt:
/home/jhasse/C++/beispiel/share/hallowelt/hallowelt.png
Damit wird unsere Datei richtig aufgespürt, dies würde auch funktionieren mit einem andern Prefix, wie z.B. "/usr". Wir können unser Programm jetzt kompilieren, müssen allerdings natürlich die Ausgabedatei in bin/ erstellen:
~/C++/hallowelt$ g++ `pkg-config gtkmm-2.4 --cflags --libs` main.cpp binreloc.o -o [b]bin/[/b]hallowelt
Unser Bild sollte nun auch angezeigt werden.
5 Menüeintrag
Nun wollen wir einen Menüeintrag (Startmenüeinträge unter Windows genannt) für unser Programm erstellen. Er soll in die Kategorie "Zubehör" eingordnet werden und unser eigenes Logo enthalten. Dazu verwende ich folgendes:
Icons sind unter Linux Sonderfälle, werden also nicht unter
share/<Programmname>
abgelegt. Da jedes Programm meistens nur ein Icon hat wird dies unter share/icons gespeichert. Außerdem können Sie mehrere Auflösungen eures Icons dort speichern, je nach angeforderter Größe im Menü wird das richtige gewählt.
Bei den Icons muss es sich nicht um ico-Dateien oder xpm-Dateien handelt, wie oft geglaubt. Sogar svg-Grafiken sind möglich.Menüeinträge sind unter Linux keine einfachen Verknüpfungen auf eine Binärdatei. Stattdessen handelt es sich um ein eigenes Dateiformat, welches verschiedene Parameter enthält, die verschiedene Eigenschaften des Eintrags beschreiben.
Es handelt sich um desktop-Dateien, welche wie ini-Dateien aufgebaut sind. Zu jedem Programm wird diese desktop-Datei unter share/applications gespeichert. Eine genaue Dokumentation findet sich in der Spezifikation von freedesktop.org.Legen wir nun eine hallowelt.desktop-Datei an. Der Ort ist eigentlich unwichtig, da sie sowieso erst nach der Installation vom System gefunden wird. Dier erste Zeile sieht wie folgt aus:
[Desktop Entry]
Da desktop-Dateien auch noch andere Sachen beinhalten können als einen Menüeintrag, legen wir hier fest, dass wir einen Menüeintrag meinen.
Version=1.0
Diese Zeile hat nichts mit der Version unseres Programms zu tun, sondern gibt die Version der Spezifikation der desktop-Datei an. Sie sollte immer auf 1.0 bleiben.
Name=Hallo Welt Type=Application
Hier wird der Name unseres Programms festgelegt und dass es sich um eine Anwendung handelt.
Als nächstes wollen wir den Tooltipp definieren, doch hier wollen wir, dass nicht-deutsche Computer eine verständliche Nachricht erhalten. Dazu definieren wir einen deutschen Text, der auch nur für deutschsprachige Computer angezeigt wird, und einen englischen, der für den Rest angezeigt wird:
Comment=Displays a picture Comment[de]=Zeichnet ein Bild
Um die eigene Sprache angezeigt zu kriegen muss man nur
echo $LANG
auf der Konsole eingeben.Fahren wir mit dem Befehl fort:
Exec=hallowelt
Hierbei handelt es sich um den Befehl der ausgeführt werden soll, wenn unser Menüeintrag ausgewählt wird. Wir können hier hallowelt eingeben, da alle Dateien die in /usr/bin liegen automatisch ohne Pfadangabe ausgeführt werden können. Sollte unser Programm unter einem anderen Prefix als /usr liegen, muss man hier natürlich anpassen, dazu aber später mehr.
Nun legen wir das Icon fest:
Icon=hallowelt.png
Für Icons gibt es viele Orte wo gesucht wird, unter anderem auch /usr/share/icons, deswegen wieder keine Pfadangabe.
Categories=Utility;
Mit dieser letzten Zeile legen wir noch die Kategorie fest, in die unser Programm einzuordnen ist. Ich hab "Zubehör" gewählt obwohl unser Programm ja eigentlich sinnlos ist. Eine Übersicht über alle Kategorien gibt's hier: http://standards.freedesktop.org/menu-spec/latest/apa.html
6 Installation-Skript
Da unsere hallowelt.desktop-Datei hier natürlich noch nutzlos ist, müssen wir uns ein Installations-Skript erstellen, welches unsere Dateien installiert. Wir erstellen eine Datei namens install.sh mit folgendem Inhalt:
#!/bin/sh prefix=$1 install -D bin/hallowelt $prefix/bin/hallowelt install -D share/icons/hallowelt.png $prefix/share/icons/hallowelt.png install -D share/hallowelt/hallowelt.png $prefix/share/hallowelt/hallowelt.png install -D hallowelt.desktop $prefix/share/applications/hallowelt.desktop
Dieses Skript verwendet seinen ersten Parameter als Prefix, erstellt die Ordner und kopiert die Dateien an die richtige Position. Nun müssen wir es noch ausführbar machen:
~/C++/hallowelt$ chmod +x install.sh
Führen wir das Skript aus um zu überprüfen ob alles geklappt hat. Hierbei verwenden wir den Prefix
/usr
, da wir es normal installieren wollen. Damit das Skript auf die Systemverzeichnisse zugreifen kann, muss es als root ausgeführt, entweder mitsudo
oder indem man sich vorher übersu
als root anmeldet:~/C++/hallowelt$ sudo ./install.sh /usr [sudo] password for jhasse: ~/C++/hallowelt$
Nun sollte unser Programm im Menü erscheinen:
7 Autopackage
Als nächsten wollen wir das eigentliche Installtionspaket erstellen. Hierzu verwende ich Autopackage, da es an keine Distribution gebunden ist. Um selber Pakete zu erstellen können, müssen wir uns die Development Environment von der Downloadseite herrunterladen. Die .package-Datei installieren wir anschließend nach der Anleitung auf der Autopackage-Seite.
Nun steht uns der neue Konsolen-Befehl
makepackage
zur Verfügung mit dem wir Autopackages erstellen können.
Mit dem Parameter --mkspec können wir eine Vorlage ausgeben lassen die wir in dem Ordner autopackage speichern:mkdir autopackage makepackage --mkspec > autopackage/default.apspec
Hierbei steht
apspec
für autopackagespecification. Öffnen wir nun die default.apspec Datei und verändern sie für unser Programm:# -*-shell-script-*- [Meta] RootName: @c-plusplus.net/hallowelt:$SOFTWAREVERSION DisplayName: Hallo-Welt-Programm ShortName: hallowelt Maintainer: Jan Niklas Hasse <jhasse@gmail.com> Packager: Jan Niklas Hasse <jhasse@gmail.com> Summary: Hallo-Welt zeichnet ein Bild
In diesen ersten Zeilen geben wir allgemeine Informationen zu unserem Paket an. Fangen wir mit dem
RootName
an: Er beschreibt das Paket mit einem eindeutigen Namen, damit es nicht zu Konflikten kommt. Der erste Teil sollte dabei aus der Internetseite bestehen, es ist allerdings nicht erforderlich, dass es sich um eine gültige handelt.
DisplayName
ist der eigentliche Name unseres Programmes.ShortName
dagegen ist eine Kurzform ohne Leerzeichen und meistens nur in Kleinbuchstaben.Maintainer
ist der Autor des Programmes undPackager
der Hersteller des Paketes.
Als letztes geben wir noch eine Zusammenfassung unseres Programms an.URL: http://www.c-plusplus.net/forum License: GNU General Public License, Version 3 SoftwareVersion: 1.0 AutopackageTarget: 1.2
Die URL setzten wir auf unsere Internetseite, erforderlich ist sie nicht. Bei Lizenz geben wir den Namen der verwendeten Softwarelizenz an und SoftwareVersion die Version, beides kann bei dem Hallo-Welt-Programm so bleiben.
Das Kommentar nach SoftwareVersion ist für Programme, die autotools verwenden wichtig, deswegen können wir die Zeile entfernen.
Ein Repository geben wir auch nicht an, dies wäre zum Beispiel wichtig wenn unser Programm von einer Library abhängt, die sich nicht in den normalen Paketquellen befindet.
EinePackageVersion
brauchen wir auch nicht angeben, da unser Paket zum ersten Mal erstellt wird. Sollten wir eine Änderung am Paket, aber nicht am Programm machen, können wir diese Nummer erhöhen, damit das Paket, trotz gleicher Programmversion, installiert werden kann. Als AutopackageTarget verwenden wir Version 1.2. Die InterfaceVersion brauchen wir nicht benutzen.In den folgenden BuildPrepare und BuildUnprepare geben wir die Befehle die fürs Kompilieren und fürs Aufräumen danach benutzt werden. Das sieht bei uns so aus:
[BuildPrepare] gcc -DENABLE_BINRELOC -o binreloc.o -c binreloc.c g++ `pkg-config gtkmm-2.4 --cflags --libs` main.cpp binreloc.o -o bin/hallowelt ./install.sh $build_root [BuildUnprepare] rm bin/hallowelt rm binreloc.o
Nun müssen wir bestimmen, welche Dateien mit in das Paket aufgenommen werden. Dazu rufen wir unser install.sh-Skript nochmal auf und geben dabei als Prefix ein temporäres Verzeichnis von autopackage an. Danach importieren wir alle Dateien mit dem
import
Befehl.[Imports] echo '*' | import
Bevor ein Paket installiert wird, müssen erst die benötigten Abhängigkeiten überprüft werden:
[Prepare] require @gtkmm.org/gtkmm2 3.0 removeOwningPackage $PREFIX/bin/hallowelt
Der
require
-Befehl sorgt dafür, dass ohne die angebenen Pakete eine Installation nicht möglich ist. Um zu überprüfen ob eine Abhängigkeit auf dem Rechner vorhanden ist, verwendet Autopackage shellscripte, die nach den Dateien suchen. Alle dieser sogenannten "skeleton files" befinden sich unter /usr/share/autopackage (oder unter einem anderen Prefix, je nachdem wohin autopackage installiert wurde). Wir binden in unserem Fall folgende Datei ein:/usr/share/autopackage/skeletons/@gtkmm.org/gtkmm2/skeleton.1
Anschließend sagen wir noch, dass alle vorherigen Versionen unseres Paketes vor der Installation gelöscht werden sollen.Nun kommen wir zum Code, der diese importierten Dateien installiert. Hierzu müssen wir die vorgefertigten Funktionen von autopackage verwenden. Eine Übersicht gibt's in der Autopackage-Dokumentation.
Die Funktionen haben meistens nur einen Parameter, der die importierte Datei angibt, so wie sie unter BuildPrepare installiert wurde.[Install] installExe bin/hallowelt installData share/hallowelt/ installIcon share/icons/hallowelt.png installMenuItem "Utility" share/applications/hallowelt.desktop
Außnahmen bilden hier die installData- und die installMenuItem-Funktionen: installData erwartet einen Ordner und kopiert diesen mit allen seinen Untervezeichnissen nach $PREFIX/share/. installMenuItem erwartet ersten Parameter noch eine Kategorie für ältere Desktop-Umgebungen. Anmerkung: Hier muss ich unbedingt noch etwas besser erklären oder einen Link mit diesen Kategorien posten. Kennt da jemand einen?
Zum deinstallieren reicht ein vorgefertiger Befehl:
[Uninstall] uninstallFromLog
Er deinstalliert alle Dateien, die vorher von den Autopackage-Funktionen installiert wurden.
Nun da unsere Datei fertig ist, rufen wir den makepackage Befehl ohne Parameter auf:
~/C++/hallowelt$ makepackage
Nun können wir unser Programm per Doppelklick auf die "Hallo-Welt-Programm 1.0.package"-Datei installieren:
8 Binärdatei
8.1 Abhängigkeiten
Als Abhängigkeit haben wir gtkmm angegeben, doch woher weiß man eigentlich was hier angegeben werden muss? Bei Abhängigkeiten handelt es sich um dynamische Bibliotheken ohne die unsere Binärdatei nicht gestartet werden kann. Um uns diese Abhängigkeiten an zuschauen gibt es den Befehl
ldd
:~/C++/hallowelt$ ldd bin/hallowelt
Die Ausgabe beinhaltet allerdings mehr Bibliotheken als notwendig. Einfaches Beispiel: GTK+ müssen wir nicht angeben, da es von GTKmm sowieso benötigt wird. Um diese Abhängigkeiten der Abhängigkeiten auszuschließen habe ich ein Python-Skript geschrieben, welches uns nur noch die wirklich notwendigen anzeigt. Wir laden uns das Skript herunter und führen es auf unser Programm aus:
~/C++/hallowelt$ python ldd.py bin/hallowelt '/usr/lib/libgtkmm-2.4.so.1' ~/C++/hallowelt$
Unsere Abhängigkeit ist also tatsächlich nur GTKmm.
Eine weitere Möglichkeit, sich die Abhängigkeiten anzuzeigen, ist der Visual Dependancy Walker.8.2 Doppeltes Kompilieren
Unter Linux gibt es verschiedene Probleme mit Binärkompatibilität. Dazu gehört zum Beispiel die GNU C Library, die von jedem Programm benötigt wird, aber häufig geändert wird. Auf Systemen mit älteren Versionen kann dann, die auf einem neuen System kompilierte Binärdatei nicht ausgeführt werden. Um dieses und andere Probleme zu beheben, gibt es das Tool apbuild. Es ist ein Wrapper für die GNU Compiler Collection, in unserem Fall dem g++-Befehl.
Ein weiteres Problem tritt nur bei C++ auf: Das ABI hat sich merhmals geändert. Genauere Infos gibt's in der Autopackage-Manual. Wichtig ist nur, dass Programme, die neuere C++-Libraries verwenden, nicht auf älteren Systemen laufen werden. Um das zu beheben kompilieren wir unser Programm zweimal, einmal mit der alten g++-Version (< 3.4), die das ältere ABI verwendet und einmal mit der neuen (>= 3.4). Autopackage entscheidet sich dann während der Installation für die richtige Version.
Als erstes müssen wir eine ältere g++-Version, entweder 3.2 oder 3.3 installieren. Nun definieren wir in unserer default.apspec-Datei den Befehl für diesen Compiler:
[BuildPrepare] export CXX2=g++-3.3 # Der Befehl für die alte g++-Version # Nun verwenden wir apbuild zum Kompilieren: apgcc -DENABLE_BINRELOC -o binreloc.o -c binreloc.c apg++ `pkg-config gtkmm-2.4 --cflags --libs` main.cpp binreloc.o -o bin/hallowelt ./install.sh $build_root
Wenn wir nun
makepackage
aufrufen, wird zweimal kompiliert, beim zweiten mal wird der Befehl verwendet, den wir in der CXX2-Variable definiert haben.9 Nachwort
Autopackage ist momentan das beste System um distributionsunspezifische Pakete zu erstellen. Doch in letzter Zeit wird es nicht mehr stark weiter entwickelt. Viele Distributionen verweigern die Aufnahme, da sie kein System wollen, dass am Paketmanager "vorbei" installiert. Doch das könnte sich in Zukunft ändern, dank PackageKit. Damit könnte Autopackage automatisch Abhängigkeiten mit dem Paketmanager nachladen oder sogar komplett integriert werden. Bis es soweit ist, bleibt es trotzdem noch die einfachste Möglichkeit für einen Entwickler, denn mehrere Pakete für die verschiedenen Distributionen zu erstellen, ist keine Alternative.
Für weitere Fragen zu Autopackage kann ich die Mailingliste empfehlen, näheres auf der Autopackage-Community-Seite, und natürlich die Linux/Unix-Abteilung dieses Forums.10 Links
BinReloc-Tutorial:
http://autopackage.org/docs/binreloc/Autopackage-Support:
http://autopackage.org/community.html
-
So ich bin fertig. Hoffe auf viel Kritik
-
Muss bei 6 Installation-Skript nicht noch ein #!/bin/sh rein?
-
Ben04 schrieb:
Muss bei 6 Installation-Skript nicht noch ein #!/bin/sh rein?
Hab's rein getan, ist bestimmt besser als ohne.
-
Hi,
guter Artikel, gefällt mir
Was mir aufgefallen ist, ist der zweite Satz gleich nach der Eröffnung von Kapitel 2 ("Wenn wir nun makepackage aufrufen, wird zweimal kompiliert, beim zweiten mal wird der Befehl verwendet, den wir in der CXX2-Variable definiert haben."). Macht da für mich irgendwie keinen Sinn?!
Cheers
GPC
-
Hi,
habs nur mal ueberflogen, aber eine Frage zu den "handgemachten" installationsskripten hab ich: Wieso verwendest du nicht /bin/install sondern cp? install bietet da ein paar interessante Sachen und wird i.d.R. auch fuer sowas verwendet (darum gibts es auch
-
Korbinian schrieb:
Hi,
habs nur mal ueberflogen, aber eine Frage zu den "handgemachten" installationsskripten hab ich: Wieso verwendest du nicht /bin/install sondern cp? install bietet da ein paar interessante Sachen und wird i.d.R. auch fuer sowas verwendet (darum gibts es auch
Den Befehl kannte ich noch gar nicht, scheint ja echt wesentlich praktischer zu sein. Danke, das werde ich heut abend mal einbauen und dann editieren.
-
GPC schrieb:
guter Artikel, gefällt mir
Danke
Was mir aufgefallen ist, ist der zweite Satz gleich nach der Eröffnung von Kapitel 2 ("Wenn wir nun makepackage aufrufen, wird zweimal kompiliert, beim zweiten mal wird der Befehl verwendet, den wir in der CXX2-Variable definiert haben."). Macht da für mich irgendwie keinen Sinn?!
Ups, da muss ich irgendwie strg+v im falschen moment gedrückt haben...
So das mit install hab ich jetzt eingebaut. Als Option verwende ich -D damit es mir die Verzeichnisse erstellt, echt praktisch! Danke nochmal für den Typ.
-
Hi. Schöner Artikel!
Bist du eigentlich so weit fertig oder willst du noch dran feilen? Wenn du fertig bist, kannst du ihn ruhig schon auf [R] stellen.
Btw, schau mal hier rein: http://www.c-plusplus.net/forum/viewtopic-var-p-is-1456869.html#1456869
-
michba schrieb:
Hi. Schöner Artikel!
Danke
Bist du eigentlich so weit fertig oder willst du noch dran feilen? Wenn du fertig bist, kannst du ihn ruhig schon auf [R] stellen.
Okay, mach ich gleich mal. (Wobei ich eigentlich dachte, dass noch mehr Kritik kommt )
Btw, schau mal hier rein: http://www.c-plusplus.net/forum/viewtopic-var-p-is-1456869.html#1456869
Okay, schon gemacht.
-
1 Vorwort
1.1 Einleitung
Willkommen zu meinem zweiten Artikel, in dem es sich um Softwareinstallation unter Linux dreht. Wir werden ein Beispiel-Programm in ein installierbares Paket mit Menüeintrag verwandeln.
1.2 Voraussetzungen
Die verwendete IDE bzw. das verwendete Buildsystem sollte keine Rolle spielen. Auch sind keine Kenntnisse über gtkmm notwendig, da dies nur eine Nebenrolle spielt und das Beispiel auf andere Libraries übertragbar sein sollte.
Sie sollten einfache C- und C++-Kenntnisse mitbringen und bereits etwas Erfahrung mit der Bash, sowie mit Linux allgemein haben.
2 Das Beispielprogramm
Bei unserem Beispiel handelt es sich um ein einfaches gtkmm-Programm, welches ein Bild anzeigt. Es besteht aus einer Source-Datei namens main.cpp mit folgendem Inhalt:
#include <gtkmm.h> int main(int argc, char** argv) { Gtk::Main kit(argc, argv); Gtk::Window win; Gtk::Image img("hallowelt.png"); win.add(img); win.show_all(); kit.run(win); }
sowie der hallowelt.png, ein simples PNG-Bild, welches im selben Verzeichnis wie unser Beispiel liegt:
Kompilieren wir nun dieses Beispiel mit:
g++ `pkg-config gtkmm-2.4 --cflags --libs` main.cpp -o hallowelt
Anschließend starten wir das Programm mit:
./hallowelt
Oben links sollte ein Fenster erscheinen, welches das Bild darstellt:
Schauen wir uns nun die wichtige Zeile in diesem Programm an:
Gtk::Image img("hallowelt.png");
Hier wird die hallowelt.png geladen, welche im gleichen Verzeichnis wie die Binärdatei liegt. Es handelt sich um einen relativen Pfad, doch zu was ist er relativ? Leider nicht zum Ort der Binärdatei, wie angenommen, sondern zum Arbeitsverzeichnis.
Dies lässt sich leicht zeigen. Wir verändern das Arbeitsverzeichnis, indem wir einen Ordner hoch springen:~/C++/hallowelt$ cd .. ~/C++$
Nun starten wir unser Programm nochmal:
~/C++$ ./hallowelt/hallowelt
Ein kleines Fenster erscheint, welches einen Platzhalter enthält, da das Bild nicht gefunden wurde. Es wurde versucht die Datei mit dem Pfad ~/C++/hallowelt.png zu öffnen.
3 BinReloc
Um dieses Problem zu beheben, verwenden wir die C-Library "BinReloc", welche eine Funktion bereitstellt, um den Ort der Binärdatei herauszufinden. Unter ftp://ftp.sunsite.dk/projects/autopackage/tools/binreloc-2.0.tar.gz kann man sich den Sourcecode herunterladen. Nach dem Entpacken wechseln wir in der Konsole zu dem Verzeichnis und lassen uns Header und Source erstellen:
~/Desktop/binreloc-2.0$ ./generate.pl normal Source code written to 'binreloc.c' Header written to 'binreloc.h' ~/Desktop/binreloc-2.0$
Nun können wir binreloc.h und binreloc.c in unser hallowelt-Verzeichnis kopieren.
Wir binden die Header-Datei ein und erstellen eine Funktion, die BinReloc initialisiert:#include <gtkmm.h> #include <iostream> #include "binreloc.h" void InitBinReloc() { BrInitError error; // Hier wird der Error-Code gespeichert if(!br_init(&error)) // Gibt true zurück, wenn alles gut ging { std::cerr << "Warning: BinReloc failed to initialize (error code " << error << ")\n" << "Will fallback to hardcoded default path." << std::endl; } }
Nun benutzen wir die Funktion
char* br_find_exe_dir(const char* fallback)
, welche uns den Pfad als C-String zurückgibt. Sollte BinReloc nicht richtig initialisiert worden sein, bekommen wir eine Kopie vonfallback
. Den C-String müssen wir per Hand wieder freigeben, deswegen kapseln wir uns die Funktion:std::string ExeDir() { char* temp = br_find_exe_dir(""); std::string exe_dir(temp); free(temp); return exe_dir; }
In der main-Funktion ergänzen wir das Initialisieren von BinReloc:
int main(int argc, char** argv) { InitBinReloc(); Gtk::Main kit(argc, argv); Gtk::Window win;
Nun kommen wir zum Laden der Bilddatei. Hierbei verwenden wir jetzt einen absoluten Pfad, der mit dem Pfad der Binärdatei beginnt:
Gtk::Image img(ExeDir() + "/hallowelt.png"); win.add(img); win.show_all(); kit.run(win); }
Jetzt können wir unser Programm kompilieren und testen. Zuerst kompilieren wir die BinReloc-Library mit dem C-Compiler. Dabei muss die Variable
ENABLE_BINRELOC
gesetzt sein:~/C++/hallowelt$ gcc -DENABLE_BINRELOC -o binreloc.o -c binreloc.c
Anschließend folgt unser Programm. Wir testen ob das Bild auch angezeigt wird, wenn wir das Arbeitsverzeichnis ändern:
~/C++/hallowelt$ g++ `pkg-config gtkmm-2.4 --cflags --libs` main.cpp binreloc.o -o hallowelt ~/C++/hallowelt$ ./hallowelt ~/C++/hallowelt$ cd .. ~/C++$ ./hallowelt/hallowelt ~/C++$
In beiden Fällen sollte das Bild angezeigt werden.
4 Die Linux-Verzeichnisstruktur
Doch unter Linux liegen Dateien eines Programms nicht in einem Ordner. Stattdessen gibt es verschiedene Ordner, die entsprechende Typen der Programmdateien enthalten. Das einfachste Beispiel ist /usr/bin/. Hier wird die Binärdatei jedes Programms gespeichert. Daten, wie unser Bild, werden in /usr/share/<Programmname>/ abgelegt.
Da es auch unter Linux die Möglichkeit gibt, Programme nur für einen Benutzer zu installieren, können diese beiden Pfade auch wie folgt lauten:
/usr/bin/ -> [b]/home/<Benutzername>/.local/bin/[/b] /usr/share/<Programmname>/ -> [b]/home/<Benutzername>/.local/share/<Programmname>/[/b]
Der Ordner .local existiert bereits im Home-Verzeichnis, ist allerdings versteckt (unter Linux werden alle Dateien versteckt, die mit einem Punkt beginnen).
Eine weitere Möglichkeit wäre die Installation auf einer anderen Festplatte:/usr/bin/ -> [b]/media/sda2/usr/bin/[/b] /usr/share/<Programmname>/ -> [b]/media/sda2/usr/share/<Programmname>/[/b]
Alle diese Pfade sind gleich, bis auf den so genannten Prefix, der in diesen drei Beispielen /usr, /home/jhasse/.local und /media/sda2/usr wäre. Um unser Programm richtig in Linux zu integrieren, müssen wir auch solch eine Struktur aufbauen. Dazu erstellen wir in unserem hallowelt-Ordner einen bin-Ordner und einen share-Ordner, der noch einen Ordner mit dem Namen hallowelt enthält. Zum Schluss verschieben wir die hallowelt.png nach share/hallowelt:
~/C++/hallowelt$ mkdir bin ~/C++/hallowelt$ mkdir share ~/C++/hallowelt$ cd share ~/C++/hallowelt/share$ mkdir hallowelt ~/C++/hallowelt/share$ cd .. ~/C++/hallowelt$ mv hallowelt.png share/hallowelt/ ~/C++/hallowelt$
Nun müssen wir unseren Quellcode anpassen. Eine neue Funktion muss her, die den Prefix des bin-Ordners zurückgibt, in dem die Binärdatei liegt, und anschließend "share/" anhängt. Diese Funktion existiert bereits in BinReloc, wir müssen sie nur noch kapseln:
std::string DataDir() { char* temp = br_find_data_dir("/usr/share"); std::string data_dir(temp); free(temp); return data_dir; }
Nun rufen wir diese Funktion auf, wenn wir unsere Bilddatei laden und hängen /hallowelt/hallowelt.png an:
Gtk::Image img(DataDir() + "/hallowelt/hallowelt.png");
Was genau passiert hier? Die
br_find_data_dir
-Funktion findet den Pfad der exe-Datei heraus:/home/jhasse/C++/beispiel/bin/
Sie erkennt, dass wir uns in einem bin-Ordner befinden und springt ein Verzeichnis nach oben, wir erhalten nun den Prefix:
/home/jhasse/C++/beispiel/
Als letztes hängt die Funktion noch "share/" an:
/home/jhasse/C++/beispiel/share/
Anschließend wird von uns "/hallowelt/hallowelt.png" hinzugefügt:
/home/jhasse/C++/beispiel/share/hallowelt/hallowelt.png
Damit wird unsere Datei richtig aufgespürt; dies würde auch mit einem andern Prefix, wie z.B. "/usr" funktionieren. Wir können unser Programm jetzt kompilieren, müssen allerdings natürlich die Ausgabedatei in bin/ erstellen:
~/C++/hallowelt$ g++ `pkg-config gtkmm-2.4 --cflags --libs` main.cpp binreloc.o -o [b]bin/[/b]hallowelt
Unser Bild sollte nun auch angezeigt werden.
5 Menüeintrag
Nun wollen wir einen Menüeintrag (Startmenüeinträge unter Windows genannt) für unser Programm erstellen. Er soll in die Kategorie "Zubehör" eingeordnet werden und unser eigenes Logo enthalten. Dazu verwende ich folgendes:
Icons sind unter Linux Sonderfälle, werden also nicht unter share/<Programmname> abgelegt. Da jedes Programm meistens nur ein Icon hat, wird dies unter share/icons gespeichert. Außerdem können Sie mehrere Auflösungen des Icons dort speichern, je nach angeforderter Größe im Menü wird das richtige gewählt.
Bei den Icons muss es sich nicht um ico- oder xpm-Dateien handeln, wie oft geglaubt. Sogar svg-Grafiken sind möglich.Menüeinträge sind unter Linux keine einfachen Verknüpfungen auf eine Binärdatei. Stattdessen handelt es sich um ein eigenes Dateiformat, welches verschiedene Parameter enthält, die verschiedene Eigenschaften des Eintrags beschreiben.
Es handelt sich um desktop-Dateien, welche wie ini-Dateien aufgebaut sind. Zu jedem Programm wird diese desktop-Datei unter share/applications gespeichert. Eine genaue Dokumentation findet sich in der Spezifikation von freedesktop.org.Legen wir nun eine hallowelt.desktop-Datei an. Der Ort ist eigentlich unwichtig, da sie sowieso erst nach der Installation vom System gefunden wird. Die erste Zeile sieht wie folgt aus:
[Desktop Entry]
Da desktop-Dateien auch noch andere Sachen beinhalten können als einen Menüeintrag, legen wir hier fest, dass wir einen Menüeintrag meinen.
Version=1.0
Diese Zeile hat nichts mit der Version unseres Programms zu tun, sondern gibt die Version der Spezifikation der desktop-Datei an. Sie sollte immer auf 1.0 bleiben.
Name=Hallo Welt Type=Application
Hier wird der Name unseres Programms festgelegt und dass es sich um eine Anwendung handelt.
Als nächstes wollen wir den Tooltipp definieren, doch hier wollen wir, dass nicht-deutsche Computer eine verständliche Nachricht erhalten. Dazu definieren wir einen deutschen Text, der auch nur für deutschsprachige Computer angezeigt wird, und einen englischen, der für den Rest angezeigt wird:
Comment=Displays a picture Comment[de]=Zeichnet ein Bild
Um die eigene Sprache angezeigt zu bekommen, muss man nur
echo $LANG
auf der Konsole eingeben.Fahren wir mit dem Befehl fort:
Exec=hallowelt
Hierbei handelt es sich um den Befehl, der ausgeführt werden soll, wenn unser Menüeintrag ausgewählt wird. Wir können hier hallowelt eingeben, da alle Dateien die in /usr/bin liegen, automatisch ohne Pfadangabe ausgeführt werden können. Sollte unser Programm unter einem anderen Prefix als /usr liegen, muss man hier natürlich anpassen, dazu aber später mehr.
Nun legen wir das Icon fest:
Icon=hallowelt.png
Für Icons gibt es viele Orte wo gesucht wird, unter anderem auch /usr/share/icons, deswegen wieder keine Pfadangabe.
Categories=Utility;
Mit dieser letzten Zeile legen wir noch die Kategorie fest, in die unser Programm einzuordnen ist. Ich habe "Zubehör" gewählt, obwohl unser Programm ja eigentlich sinnlos ist. Eine Übersicht über alle Kategorien gibt's hier: http://standards.freedesktop.org/menu-spec/latest/apa.html
6 Installationsskript
Da unsere hallowelt.desktop-Datei hier natürlich noch nutzlos ist, müssen wir uns ein Installationsskript erstellen, welches unsere Dateien installiert. Wir erstellen eine Datei namens install.sh mit folgendem Inhalt:
#!/bin/sh prefix=$1 install -D bin/hallowelt $prefix/bin/hallowelt install -D share/icons/hallowelt.png $prefix/share/icons/hallowelt.png install -D share/hallowelt/hallowelt.png $prefix/share/hallowelt/hallowelt.png install -D hallowelt.desktop $prefix/share/applications/hallowelt.desktop
Dieses Skript verwendet seinen ersten Parameter als Prefix, erstellt die Ordner und kopiert die Dateien an die richtige Position. Nun müssen wir es noch ausführbar machen:
~/C++/hallowelt$ chmod +x install.sh
Führen wir das Skript aus, um zu überprüfen ob alles geklappt hat. Hierbei verwenden wir den Prefix "/usr", da wir es normal installieren wollen. Damit das Skript auf die Systemverzeichnisse zugreifen kann, muss es als root ausgeführt werden, entweder mit
sudo
oder indem man sich vorher übersu
als root anmeldet:~/C++/hallowelt$ sudo ./install.sh /usr [sudo] password for jhasse: ~/C++/hallowelt$
Nun sollte unser Programm im Menü erscheinen:
7 Autopackage
Als nächstes wollen wir das eigentliche Installationspaket erstellen. Hierzu verwende ich Autopackage, da es an keine Distribution gebunden ist. Um selbst Pakete erstellen zu können, müssen wir uns die Development Environment von der Downloadseite herunterladen. Die .package-Datei installieren wir anschließend nach der Anleitung auf der Autopackage-Seite.
Nun steht uns der neue Konsolen-Befehl
makepackage
zur Verfügung, mit dem wir Autopackages erstellen können.
Mit dem Parameter--mkspec
können wir eine Vorlage ausgeben lassen die wir in dem Ordner autopackage speichern:mkdir autopackage makepackage --mkspec > autopackage/default.apspec
Hierbei steht
apspec
für autopackagespecification. Öffnen wir nun die default.apspec-Datei und verändern sie für unser Programm:# -*-shell-script-*- [Meta] RootName: @c-plusplus.net/hallowelt:$SOFTWAREVERSION DisplayName: Hallo-Welt-Programm ShortName: hallowelt Maintainer: Jan Niklas Hasse <jhasse@gmail.com> Packager: Jan Niklas Hasse <jhasse@gmail.com> Summary: Hallo-Welt zeichnet ein Bild
In diesen ersten Zeilen geben wir allgemeine Informationen zu unserem Paket an. Fangen wir mit dem
RootName
an: Er beschreibt das Paket mit einem eindeutigen Namen, damit es nicht zu Konflikten kommt. Der erste Teil sollte dabei aus der Internetseite bestehen, es ist allerdings nicht erforderlich, dass es sich um eine gültige handelt.
DisplayName
ist der eigentliche Name unseres Programms.ShortName
dagegen ist eine Kurzform ohne Leerzeichen und meistens nur in Kleinbuchstaben.Maintainer
ist der Autor des Programms undPackager
der Hersteller des Paketes.
Als letztes geben wir noch eine Zusammenfassung unseres Programms an.URL: http://www.c-plusplus.net/forum License: GNU General Public License, Version 3 SoftwareVersion: 1.0 AutopackageTarget: 1.2
Die URL setzen wir auf unsere Internetseite, erforderlich ist sie nicht. Bei Lizenz geben wir den Namen der verwendeten Softwarelizenz an und bei
SoftwareVersion
die Version, beides kann bei dem Hallo-Welt-Programm so bleiben.
Der Kommentar nachSoftwareVersion
ist für Programme, die autotools verwenden wichtig, deswegen können wir die Zeile entfernen.
Ein Repository geben wir auch nicht an, dies wäre zum Beispiel wichtig, wenn unser Programm von einer Library abhängt, die sich nicht in den normalen Paketquellen befindet.
EinePackageVersion
brauchen wir auch nicht angeben, da unser Paket zum ersten Mal erstellt wird. Sollten wir eine Änderung am Paket, aber nicht am Programm machen, können wir diese Nummer erhöhen, damit das Paket, trotz gleicher Programmversion, installiert werden kann. AlsAutopackageTarget
verwenden wir Version 1.2. DieInterfaceVersion
brauchen wir nicht benutzen.In
BuildPrepare
undBuildUnprepare
geben wir die Befehle an, die für's Kompilieren und für's Aufräumen danach benutzt werden. Das sieht bei uns so aus:[BuildPrepare] gcc -DENABLE_BINRELOC -o binreloc.o -c binreloc.c g++ `pkg-config gtkmm-2.4 --cflags --libs` main.cpp binreloc.o -o bin/hallowelt ./install.sh $build_root [BuildUnprepare] rm bin/hallowelt rm binreloc.o
Nun müssen wir bestimmen, welche Dateien mit in das Paket aufgenommen werden. Dazu rufen wir unser install.sh-Skript nochmal auf und geben dabei als Prefix ein temporäres Verzeichnis von autopackage an. Danach importieren wir alle Dateien mit dem
import
-Befehl.[Imports] echo '*' | import
Bevor ein Paket installiert wird, müssen erst die benötigten Abhängigkeiten überprüft werden:
[Prepare] require @gtkmm.org/gtkmm2 3.0 removeOwningPackage $PREFIX/bin/hallowelt
Der
require
-Befehl sorgt dafür, dass ohne die angegebenen Pakete eine Installation nicht möglich ist. Um zu überprüfen, ob eine Abhängigkeit auf dem Rechner vorhanden ist, verwendet Autopackage Shellskripte, die nach den Dateien suchen. Alle diese so genannten "skeleton files" befinden sich unter /usr/share/autopackage (oder unter einem anderen Prefix, je nachdem wohin autopackage installiert wurde). Wir binden in unserem Fall folgende Datei ein: /usr/share/autopackage/skeletons/@gtkmm.org/gtkmm2/skeleton.1.
Anschließend sagen wir noch, dass alle vorherigen Versionen unseres Paketes vor der Installation gelöscht werden sollen.Nun kommen wir zum Code, der diese importierten Dateien installiert. Hierzu müssen wir die vorgefertigten Funktionen von autopackage verwenden. Eine Übersicht gibt's in der Autopackage-Dokumentation.
Die Funktionen haben meistens nur einen Parameter, der die importierte Datei angibt, so wie sie unterBuildPrepare
installiert wurde.[Install] installExe bin/hallowelt installData share/hallowelt/ installIcon share/icons/hallowelt.png installMenuItem "Utility" share/applications/hallowelt.desktop
Ausnahmen bilden hier die
installData
- und dieinstallMenuItem
-Funktionen:installData
erwartet einen Ordner und kopiert diesen mit allen seinen Unterverzeichnissen nach $PREFIX/share/.installMenuItem
erwartet als ersten Parameter noch eine Kategorie für ältere Desktop-Umgebungen.Zum Deinstallieren reicht ein vorgefertigter Befehl:
[Uninstall] uninstallFromLog
Er deinstalliert alle Dateien, die vorher von den Autopackage-Funktionen installiert wurden.
Nun da unsere Datei fertig ist, rufen wir den
makepackage
-Befehl ohne Parameter auf:~/C++/hallowelt$ makepackage
Jetzt können wir unser Programm per Doppelklick auf die Hallo-Welt-Programm 1.0.package-Datei installieren:
8 Binärdatei
8.1 Abhängigkeiten
Als Abhängigkeit haben wir gtkmm angegeben, doch woher weiß man eigentlich, was hier angegeben werden muss? Bei Abhängigkeiten handelt es sich um dynamische Bibliotheken, ohne die unsere Binärdatei nicht gestartet werden kann. Um uns diese Abhängigkeiten anzuschauen gibt es den Befehl
ldd
:~/C++/hallowelt$ ldd bin/hallowelt
Die Ausgabe beinhaltet allerdings mehr Bibliotheken als notwendig. Einfaches Beispiel: GTK+ müssen wir nicht angeben, da es von gtkmm sowieso benötigt wird. Um diese Abhängigkeiten der Abhängigkeiten auszuschließen habe ich ein Python-Skript geschrieben, welches uns nur noch die wirklich notwendigen anzeigt. Wir laden uns das Skript herunter und führen es auf unser Programm aus:
~/C++/hallowelt$ python ldd.py bin/hallowelt '/usr/lib/libgtkmm-2.4.so.1' ~/C++/hallowelt$
Unsere Abhängigkeit ist also tatsächlich nur gtkmm.
Eine weitere Möglichkeit, sich die Abhängigkeiten anzuzeigen, ist der Visual Dependency Walker.8.2 Doppeltes Kompilieren
Unter Linux gibt es verschiedene Probleme mit Binärkompatibilität. Dazu gehört zum Beispiel die GNU C Library, die von jedem Programm benötigt wird, aber häufig geändert wird. Auf Systemen mit älteren Versionen kann dann die auf einem neuen System kompilierte Binärdatei nicht ausgeführt werden. Um dieses und andere Probleme zu beheben, gibt es das Tool apbuild. Es ist ein Wrapper für die GNU Compiler Collection, in unserem Fall dem g++-Befehl.
Ein weiteres Problem tritt nur bei C++ auf: Das ABI hat sich mehrmals geändert. Genauere Infos gibt's im Autopackage-Manual. Wichtig ist nur, dass Programme, die neuere C++-Libraries verwenden, nicht auf älteren Systemen laufen werden. Um das zu beheben, kompilieren wir unser Programm zweimal, einmal mit der alten g++-Version (< 3.4), die das ältere ABI verwendet und einmal mit der neuen (>= 3.4). Autopackage entscheidet sich dann während der Installation für die richtige Version.
Als erstes müssen wir eine ältere g++-Version, entweder 3.2 oder 3.3 installieren. Nun definieren wir in unserer default.apspec-Datei den Befehl für diesen Compiler:
[BuildPrepare] export CXX2=g++-3.3 # Der Befehl für die alte g++-Version # Nun verwenden wir apbuild zum Kompilieren: apgcc -DENABLE_BINRELOC -o binreloc.o -c binreloc.c apg++ `pkg-config gtkmm-2.4 --cflags --libs` main.cpp binreloc.o -o bin/hallowelt ./install.sh $build_root
Wenn wir nun
makepackage
aufrufen, wird zweimal kompiliert, beim zweiten Mal wird der Befehl verwendet, den wir in der CXX2-Variable definiert haben.9 Nachwort
Autopackage ist momentan das beste System um distributionsunspezifische Pakete zu erstellen. Doch in letzter Zeit wird es nicht mehr stark weiterentwickelt. Viele Distributionen verweigern die Aufnahme, da sie kein System wollen, das am Paketmanager "vorbei" installiert. Doch das könnte sich in Zukunft ändern, dank PackageKit. Damit könnte Autopackage automatisch Abhängigkeiten mit dem Paketmanager nachladen oder sogar komplett integriert werden. Bis es soweit ist, bleibt es trotzdem noch die einfachste Möglichkeit für einen Entwickler, denn mehrere Pakete für die verschiedenen Distributionen zu erstellen, ist keine Alternative.
Für weitere Fragen zu Autopackage kann ich die Mailingliste empfehlen, näheres auf der Autopackage-Community-Seite, und natürlich die Linux/Unix-Abteilung dieses Forums.10 Links
BinReloc-Tutorial:
http://autopackage.org/docs/binreloc/Autopackage-Support:
http://autopackage.org/community.html
-
Vielen Dank für die Korrektur!
-
Dieser Thread wurde von Moderator/in estartu aus dem Forum Die Redaktion in das Forum Archiv verschoben.
Im Zweifelsfall bitte auch folgende Hinweise beachten:
C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?Dieses Posting wurde automatisch erzeugt.