From Fedora Project Wiki
No edit summary
(Komplett überarbeitet.)
Line 3: Line 3:
== Einleitung ==
== Einleitung ==


Der Artikel beschreibt exemplarisch an Hand eines "Hallo-Welt"-Projekts wie
Der Artikel beschreibt exemplarisch an Hand eines "Hallo-Welt"-Projekts, wie eine Minimallösung aussehen kann, um eine Makefile ein rpm-Paket bauen zu lassen.
der Weg zu einem RPM ist.
 
Typische Szenarien sind: Kleinere Projekte mit wenigen Anwendern die das Problem haben, das es keine Maintainer gibt, die sich um den Paketbau kümmert. Oder wenn ''In-House-Lösungen'' in das RPM-Deployment gebracht werden sollen.


== Vorbereitung ==
== Vorbereitung ==


Für die folgenden Schritte werden volgende Tools benötigt.
Für die folgenden Schritte werden folgende Tools benötigt.


* GNU Make
* GNU Make
Line 14: Line 15:
* Ein Editor
* Ein Editor


Wie die die Software-Pakte der oben genannten Tools heißen ist Distrebutionsabhängig.  
Wie die die Software-Pakte der oben genannten Tools genau heißen ist von der Distribution abhängig.  


== Erstellen des eigentlichen Programms ==
== Erstellen des eigentlichen Programms ==
Line 23: Line 24:
   echo "Hallo `whoami`";
   echo "Hallo `whoami`";


Was tut dieses Programm? Beim Aufruf Gibt es einfach nur "Hallo" aus, gefolgt von dem Loginnahmen, der Person, die es aufruft. Das ist - zugegeben - wenig Sinn anstiftend aber für unseren Zweck reicht es.
Was tut dieses Programm? Beim Aufruf Gibt es einfach nur "Hallo" aus, gefolgt von dem Loginnahmen, der Person, die es aufruft. Das ist - zugegeben - wenig sinnstiftend aber für unseren Zweck reicht es.


Das Skript speichern wir in die Datei "rpm-uebung.sh". Diese Datei speichern wir - der Ordnung halber in das Verzeichnis "/src". "src" steht für Source-Code. Diesen Ordner, speichern wir in einem Projektordner. So das unsere Struktur (bisher) so aussieht:
Das Skript speichern wir in die Datei "rpm-uebung.sh". Diese Datei speichern wir - der Ordnung halber in das Verzeichnis "/src". "src" steht für Source-Code. Diesen Ordner, speichern wir in einem Projektordner. So das unsere Struktur (bisher) so aussieht:
Line 45: Line 46:
Darüber hinaus kann man GNU Make so einrichten das es Beliebige Parameter akzeptiert und dann definierte Aktionen ausführt. Zum Beispiel ein RPM erstellt. Und das ist der Grund, warum wir rpmbuild (das Tool zum erstellen von rpms) nicht direkt aufrufen, sondern über GNU Make. Wir versuchen die Komplexität vor dem User zu verstecken, in dem wir ihm eine definierte Schnittstellen geben. So muss er die Feinheiten von rpmbuild nicht verstehen.  
Darüber hinaus kann man GNU Make so einrichten das es Beliebige Parameter akzeptiert und dann definierte Aktionen ausführt. Zum Beispiel ein RPM erstellt. Und das ist der Grund, warum wir rpmbuild (das Tool zum erstellen von rpms) nicht direkt aufrufen, sondern über GNU Make. Wir versuchen die Komplexität vor dem User zu verstecken, in dem wir ihm eine definierte Schnittstellen geben. So muss er die Feinheiten von rpmbuild nicht verstehen.  


Für Fedora-Maintainer sieht die Situation anders aus. Doch bevor eine Software von einem Maintainer betreut wird, muss sich in der Regel der Entwickler bzw. der User mit dem RPM-Bau rumschlagen.
Für Fedora-Maintainer sieht die Situation anders aus. Er will die volle Kontrolle über den RPM-Bau. Es gibt Distributionsweite einheitliche Konvention, die darüber abgebildet werden. Sollte sich also ein Maintainer sich dieses Paketes annehmen, wird er höchstwahrscheinlich das Thema völlig anders angehen. Das nur als Randbemerkung.


== Makefile erstellen ==
== Makefile erstellen ==


Zunächst legen wir eine neues Makefile an in unserem Projektordner. So das Unsere Struktur so aussieht:
Unser Ausgangspunkt ist gnu make. Also legen wir zunächst eine neues Makefile in unserem Projektordner an. So das Unsere Struktur so aussieht:


* rpm-uebung
* rpm-uebung
Line 56: Line 57:
** Makefile
** Makefile


Zunächst der Komplette Inhalt als Übersicht und zum kopieren (Ganz wichtig! Die Einrückungen müssen Tabs sein und dürfen keine leerzeichen sein. Sonst wird ''GNU Make'' die Arbeit verweigern):
Hier der Komplette Inhalt als Übersicht und zum kopieren (Ganz wichtig! Die Einrückungen müssen Tabs sein und dürfen keine Leerzeichen sein. Sonst wird ''GNU Make'' die Arbeit verweigern):
 
 
<!-- Code-Begin -->


  PREFIX=
PREFIX=
  RPM_ROOT=~/rpmbuild
VERSION=1
  RPM_BOUILD_ENV= $(RPM_ROOT)/BUILD $(RPM_ROOT)/RPMS $(RPM_ROOT)/SOURCES $(RPM_ROOT)/SPECS $(RPM_ROOT)/SRPMS
PROGNAME=rpm-uebung
  RPM_SOURCES=$(RPM_ROOT)/SOURCES
ARCHIV=$(PROGNAME)-$(VERSION).tar.gz
  VERSION=1
  PROGNAME=rpm-uebung
all:
  ARCHIV=$(PROGNAME)-$(VERSION).tar.gz
        echo "Es gibt nichts zu tun..."
 
  make:
install:
 
  install:
         [ -d $(PREFIX)/usr/bin/ ] || mkdir -p $(PREFIX)/usr/bin/
         [ -d $(PREFIX)/usr/bin/ ] || mkdir -p $(PREFIX)/usr/bin/
         cp ./src/$(PROGNAME).sh $(PREFIX)/usr/bin/
         cp ./src/$(PROGNAME).sh $(PREFIX)/usr/bin/
         chmod uoa+x $(PREFIX)/usr/bin/$(PROGNAME).sh
         chmod uoa+x $(PREFIX)/usr/bin/$(PROGNAME).sh
 
  dist-tar:
dist-tar:
         [ -d ./$(PROGNAME)-$(VERSION) ] ||  mkdir ./$(PROGNAME)-$(VERSION)  
         [ -d ./$(PROGNAME)-$(VERSION) ] ||  mkdir ./$(PROGNAME)-$(VERSION)  
         cp -r ./src ./$(PROGNAME)-$(VERSION)/
         cp -r ./src ./$(PROGNAME)-$(VERSION)/
         cp ./Makefile ./$(PROGNAME)-$(VERSION)
         cp ./Makefile ./$(PROGNAME)-$(VERSION)
         tar -cvzf $(ARCHIV) ./$(PROGNAME)-$(VERSION)
        cp $(PROGNAME).spec ./$(PROGNAME)-$(VERSION)/$(PROGNAME)-$(VERSION).spec
         tar -cvzf $(ARCHIV) $(PROGNAME)-$(VERSION)
         rm -rvf ./rpm-uebung-$(VERSION)
         rm -rvf ./rpm-uebung-$(VERSION)
 
  rpm-init:
dist-rpm:  
        [ -d $(RPM_ROOT) ] || mkdir $(RPM_ROOT) ; mkdir $(RPM_BOUILD_ENV)
         rpmbuild -ta $(ARCHIV)
 
  pre-rpm: dist-tar
.PHONY: dist-rpm dist-tar install
        cp ./$(ARCHIV) $(RPM_ROOT)/SOURCES
 
  dist-rpm: pre-rpm
         rpmbuild -ba --target=noarch $(PROGNAME).spec
 
  .PHONY: dist-rpm dist-tar install


<!-- Code-end -->


Jetzt noch mal zur Struktur. Im ersten Teil werden verschiedene Variablen gesetzt. Variablen aus zwei Gründen:
Jetzt noch mal zur Struktur. Im ersten Teil werden verschiedene Variablen gesetzt. Variablen aus zwei Gründen:
Line 97: Line 95:
* Zum anderen kann man bei''GNU Make'' über Parameter die Variablen setzen. Diese Eigenschaft werden wir später im Wechselspiel mit dem rpmbuild-tool brauchen.
* Zum anderen kann man bei''GNU Make'' über Parameter die Variablen setzen. Diese Eigenschaft werden wir später im Wechselspiel mit dem rpmbuild-tool brauchen.


Der zweite Teil sind die Definitionen der Kommandos die ''GNU Make'' kennen und ausführen können soll. Der Komando-Name steht immer links, am Anfang der Zeile und Endet mit einem Doppelpunkt. Alle darauf folgenden Zeilen, mit einem Tab eingerückt werden sind dann die Schritte die bei dem Befehlsaufruf abgearbeitet werden.  
Der zweite Teil sind die Definitionen der Kommandos die ''GNU Make'' kennen und ausführen können soll. Der Kommando-Name (bzw. "Ziel") steht immer links, am Anfang der Zeile und Endet mit einem Doppelpunkt. Alle darauf folgenden Zeilen, die mit einem Tab eingerückt werden, sind dann die Schritte die bei dem Befehlsaufruf abgearbeitet werden.  


Bei manchen Befehlsdefinitionen, steht noch ein Wort dahinter. So zum Beispiel in der Zeile...
Die letzte Zeile definiert, welche Funktionen/Befehle immer ausgeführt werden sollen. Normalerweise überprüft make nämlich ob die Quelle - die Source-Datei - neuer als das Ziel - die Binär-Datei - ist um zu entscheiden, ob ein Neubau nötig ist.  


  pre-rpm: dist-tar
Unser make-Skript ist nun fertig benutzbar. Wenn wir jetzt den Befehl...


Das sind Bedingungen oder Abhängigkeiten. Hier wird zum Beispiel ''GNU Make'' gesagt, das bevor der Befehl ''pre-rpm'' abgearbeitet wird, noch der Befehl ''dist-rpm'' abgearbeitet werden muss.
make


Die letzte Zeile definiert, welche Funktionen/Befehle  nach Außen sichtbar bzw. über Parameter aufrufbar sind.  
...aufrufen, bekommen wir die Meldung:


Oben haben wir schon gesagt, das vom Benutzer in der Regel erwartet wird das der Befehl...
"Es gibt nichts zu tun..."


  make
...Zurück. Wenn make ohne Parameter aufrufen, springt es automatisch in "all:". Bei einem Programm was kompiliert werden muss, würde das hier gemacht werden. Bei einem Bash-Skript ist das aber nicht nötig.


...unterstützt wird. In unserem Fall gibt es aber nichts zu übersetzen. Unser Skript ist fertig benutzbar. Deshalb ist da auch nichts definiert. Anders sieht es mit dem Befehl...
Anders sieht es mit dem Befehl...


   make install
   make install
Line 123: Line 121:
== Der RPM-Bau (Spec-File) ==
== Der RPM-Bau (Spec-File) ==


Jetzt kommen wir zum eigentlich RPM-Bau. Das wird ein recht komplexes Zusammenspiel zwischen ''GNU Make'' und ''rpmbuild''. Man könnte natürlich auch völlig ohne Makefile arbeiten. Oder ''GNU Make'' und ''rpmbuild'' völlig getrennt benutzen. Nur hat das Nachteile:
Jetzt kommen wir zum eigentlich RPM-Bau. Das wird ein Zusammenspiel zwischen ''GNU Make'' und ''rpmbuild''.  


* Keine einheitliche leicht benutzbare Schnittstelle für den Benutzer.
Zunächst das Spec-Fiel in der Übersicht zum zum kopieren:
* Redundante Daten (Informationen müssen in zwei Dateien gepflegt werden)


Zunächst das Spec-Fiel in der Übersicht zund zum kopieren:
<!-- Code-Begin -->


  BuildRoot: %(echo $HOME)/rpmbuild/
Summary: Eine rpm uebung
  Summary: GNU rpm-uebung
License: GPL
  License: GPL
Name: rpm-uebung
  Name: rpm-uebung
Version: 1
  Version: 1
Release: 1
  Release: 1
Source: rpm-uebung-1.tar.gz
  Source: rpm-uebung-1.tar.gz
Group:  Development/Tools
  Group:  Development/Tools
BuildArch: noarch
 
BuildRoot: /var/tmp/%{name}-buildroot
  %description
  create a Hello RPM.
%description
 
Kleine Programm, das den Benutzer mit seinem Loginnamen begruesst.
  %prep
  %setup -q
%prep
  make PREFIX=$RPM_BUILD_ROOT pre-rpm
%setup
 
  %build
%build
 
  %install
%install
  rm -rf $RPM_BUILD_ROOT
make PREFIX=$RPM_BUILD_ROOT install
  make PREFIX=$RPM_BUILD_ROOT install
 
%files
  %files
%defattr(0755,root,root)
  %defattr(0755,root,root)
/usr/bin/rpm-uebung.sh
  /usr/bin/rpm-uebung.sh
 
<!-- Code-end -->


...Der Aufbau ist syntaktisch völlig anders. Am Anfang stehen wieder die Definition von Variablen. Hier ist das ":" eine Zuweisung und keine Bedingung wie bei ''GNU Make''. Die Variablen Namen und Bedeutungen sind hier Fix gesetzt.  
...Der Aufbau ist syntaktisch völlig anders als beim Makefile. Am Anfang stehen wieder die Definition von Variablen. Hier ist das ":" eine Zuweisung und keine Bedingung wie bei ''GNU Make''.  


Bevor ich ins Detail gehe, speichern wir die Datei als ''"rpm-uebung.spec"''. Unser Verzeichnis sollte nun so aussehen:
Bevor ich ins Detail gehe, speichern wir die Datei als ''"rpm-uebung.spec"''. Wichtig ist, das dass File wie das Projekt heißt. Unser Verzeichnis sollte nun so aussehen:


* rpm-uebung
* rpm-uebung
Line 168: Line 166:
Noch mal ins Detail...
Noch mal ins Detail...


  BuildRoot: %(echo $HOME)/rpmbuild/
   Summary: Eine rpm uebung
 
Das ist das Verzeichnis, was die Build-Umgebung beherbergt.
 
   Summary: GNU rpm-uebung


Kurze Zusammenfassung was das für ein Programm ist.
Kurze Zusammenfassung was das für ein Programm ist.
Line 188: Line 182:


Die Versions- und Release-Nummer
Die Versions- und Release-Nummer
  Source: rpm-uebung-1.tar.gz
Dies ist der Name den das Tar-File hat, das rpmbuild benutzen soll.


   Group:  Development/Tools
   Group:  Development/Tools
Line 198: Line 188:


   %description
   %description
   create a Hello RPM.
   Kleine Programm, das den Benutzer mit seinem Loginnamen begruesst.


Hier kommt die etwas ausführliche Beschreibung (die bei uns aber nicht sehr ausführlich ist). Dann folgen die Regeln für den Build und die Installation, auf die wir gleich im Detail eingehen.  
Hier kommt die etwas ausführliche Beschreibung (die bei uns aber nicht sehr ausführlich ist). Dann folgen die Regeln für den Build und die Installation, auf die wir gleich im Detail eingehen.  
Line 208: Line 198:
In den letzten Zeilen wird festgehalten, welche Dateien bei der Installation angelegt werden. Und (mit ''%defattr(0755,root,root)'') wird festgelegt, welche Rechte die Dateien bekommen. Da es sich um eine Ausführbare Datei handelt, muss es 0755 sein.
In den letzten Zeilen wird festgehalten, welche Dateien bei der Installation angelegt werden. Und (mit ''%defattr(0755,root,root)'') wird festgelegt, welche Rechte die Dateien bekommen. Da es sich um eine Ausführbare Datei handelt, muss es 0755 sein.


'''Erläuterung/Benutzung:'''


An dieser Stelle ein kurzer Zwischenstopp für eine Übersicht.
Der User ruft zunächst den Befehl ''"dist-tar"'' auf. Das erstellt ein Tar-Archiv unseres Programmst. Dann ruft der Benutzer Befehl ''"make dist-rpm"'' auf. In unserem Makefile wird nun der rpmbuild-Befehl parametisiert aufgerufen...
 
[[File:Rpmbuild-ablauf-diagramm.svg|thumb|left|Übersicht über die Interaktionen der beiden Tools ''GNU Make'' und ''rpmbuild''.]]
 
'''Erläuterung:'''
 
Der User ruft dem Befehl ''"make dist-rpm"'' auf und dann folgt eine reihe gegenseitiger zum Teil parametrisierter aufrufe, die dem User zum Glück verborgen bleiben...
 
  rpmbuild -ba --target=noarch $(PROGNAME).spec
 
...hier wird rpmbuid aufgerufen und der Name des Spec-File mitgegeben und mitgeteilt das es sich um ein Paket ohne Architekturabhängigkeiten handelt (noarch), da bash-Skripte unter allen Systemen laufen ohne neu übersetzt zu werden.
 
Im Spec-File geht es dann weiter...
 
  %build
  make PREFIX=$RPM_BUILD_ROOT pre-rpm
 
...Die Build-Sektion ruft ihrerseits wiederum das Makefile (bzw. make) auf und gibt ihm als Parameter das Verzeichnis mit, was rpmbuild benutzt um das rpm zu bauen. Das weiß make nicht von alleine.
 
Im Makefile wird dann - wie übergeben - die Funktion pre-rpm aufgerufen...


  pre-rpm: dist-tar
dist-rpm:  
         cp ./$(ARCHIV) $(RPM_ROOT)/SOURCES
         rpmbuild -ta $(ARCHIV)


...Hier ist eine Abhängigkeit zu Funktion ''"dist-tar"'' definiert. Das ist auch der Grund, warum das Spec-File die Arbeit an Make delegiert! Weil man könnte es auch dort definieren, aber das wäre Redundant...
Will man den ersten Befehl implezieren um dem User ein Schritt zu erspahren, kann man die Zeile wie Folgt abwandeln.
 
  dist-tar:
        [ -d ./$(PROGNAME)-$(VERSION) ] ||  mkdir ./$(PROGNAME)-$(VERSION)
        cp -r ./src ./$(PROGNAME)-$(VERSION)/src/
        cp ./Makefile ./$(PROGNAME)-$(VERSION)
        tar -cvzf $(ARCHIV) ./$(PROGNAME)-$(VERSION)
        rm -rvf ./rpm-uebung-$(VERSION)


In dem Abschnitt wird überprüft ob es schon ein Verzeichnis gibt, das so heißt wie das Projekt. Das wird nämlich von rpmbuild so erwartet. Wenn nicht, wird es angelegt und mit allen nötigen Dateien befüllt. Dann wird ein Tar-Archiv daraus erstellt und die temporären Dateien wieder gelöscht.
dist-rpm: dist-tar
        rpmbuild -ta $(ARCHIV)


Zurück in der Funktion ''"pre-rpm"'' wird das zuvor erstellte Tar-Archiv in die Build-Umgebung in das Verzeichnis ''"SOURCES"'' verschoben.  
...Nun weiß make von alleine, das es vorher ''"dist-tar:"'' ausführen muss.


Im Speck-File wird dann die Funktion ''"%install"'' aufgerufen, die wiederum die die Makefile-Funktion ''"install"'' parametrisiert aufruft...
Das rpmbuild wird nun seinerseits das Makefile bzw make aufrufen um sich den Installationsprozess anzusehen. Mit dies nicht im root-Verzeichnis geschieht, wird das wieder parametrisiert. Deshalb haben wir auch oben Variablen im Makefile benutzt...


   make PREFIX=$RPM_BUILD_ROOT install
   make PREFIX=$RPM_BUILD_ROOT install


Wird dem make nicht der Prefix übergeben, würde das Skript versuchen tatsächlich das
Wird dem make nicht der Prefix übergeben, würde das Skript versuchen tatsächlich das
Programm im System zu installieren. Das schlägt ohme root-Rechte fehl. Mit root-Rechten wäre das Programm am rpm-System vorbeiinstaliert worden. rpmbuild muss die Installation ein mal ausgeführt haben um zu überprüfen, welche Dateien tatsächlich wo in System hinein kopiert werden.  
Programm im System zu installieren. Das schlägt ohme root-Rechte fehl.  


Wenn nichts schief gelaufen ist, sollte jetzt ein installierbares rpm-Paket da sein und zwar im Verzeichnis /RPMS unterhalb der rpm-Build-Umgebung, die auf jedem System wo anders sein kann.
Wenn nichts schief gelaufen ist, sollte jetzt ein installierbares rpm-Paket da sein und zwar im Verzeichnis /RPMS unterhalb der rpm-Build-Umgebung, die auf jedem System in aller Regel im Verzeichnis /home/USERNAME/rpmbuild/ liegt.

Revision as of 09:32, 6 March 2012

Einleitung

Der Artikel beschreibt exemplarisch an Hand eines "Hallo-Welt"-Projekts, wie eine Minimallösung aussehen kann, um eine Makefile ein rpm-Paket bauen zu lassen.

Typische Szenarien sind: Kleinere Projekte mit wenigen Anwendern die das Problem haben, das es keine Maintainer gibt, die sich um den Paketbau kümmert. Oder wenn In-House-Lösungen in das RPM-Deployment gebracht werden sollen.

Vorbereitung

Für die folgenden Schritte werden folgende Tools benötigt.

  • GNU Make
  • rpmbuild
  • Ein Editor

Wie die die Software-Pakte der oben genannten Tools genau heißen ist von der Distribution abhängig.

Erstellen des eigentlichen Programms

Zunächst das (Beispiel-)Programm. Es handelt sich in unserem Falle um ein Bash-Skript das aus einer einzigen Zeile Code besteht (Die erste Zeile bestimmt nur den Interpreter):

 #!/bin/bash
 echo "Hallo whoami";

Was tut dieses Programm? Beim Aufruf Gibt es einfach nur "Hallo" aus, gefolgt von dem Loginnahmen, der Person, die es aufruft. Das ist - zugegeben - wenig sinnstiftend aber für unseren Zweck reicht es.

Das Skript speichern wir in die Datei "rpm-uebung.sh". Diese Datei speichern wir - der Ordnung halber in das Verzeichnis "/src". "src" steht für Source-Code. Diesen Ordner, speichern wir in einem Projektordner. So das unsere Struktur (bisher) so aussieht:

  • rpm-uebung
    • src
      • rpm-uebung.sh

Warum ein Makefile?

In aller Regel wird in Unix- und Linux-Umgebungen gern und viel mit Makefiles gearbeitet. Das macht Sinn! Denn es abstrahiert den Umgang mit dem Programm. In der Regel ist Derjenige, der das Programm installiert nicht der selbe der das Programm programmiert. Die Idee hinter Makefiles ist, das der User nicht viel wissen muss über das Programm um es installieren zu können. Makefiles sind auch nur Skripte die etwas automatisch tun. Die Konvention ist, das der Benutzer erwarten darf, das es mindestens zwei Befehle gibt, die ihm zur Verfügung stehen:

 make

und

 make install

Der Benutzer erwartet, das der erste Befehl das Programm zusammenbaut und zweite, es auf seinem System installiert.

Darüber hinaus kann man GNU Make so einrichten das es Beliebige Parameter akzeptiert und dann definierte Aktionen ausführt. Zum Beispiel ein RPM erstellt. Und das ist der Grund, warum wir rpmbuild (das Tool zum erstellen von rpms) nicht direkt aufrufen, sondern über GNU Make. Wir versuchen die Komplexität vor dem User zu verstecken, in dem wir ihm eine definierte Schnittstellen geben. So muss er die Feinheiten von rpmbuild nicht verstehen.

Für Fedora-Maintainer sieht die Situation anders aus. Er will die volle Kontrolle über den RPM-Bau. Es gibt Distributionsweite einheitliche Konvention, die darüber abgebildet werden. Sollte sich also ein Maintainer sich dieses Paketes annehmen, wird er höchstwahrscheinlich das Thema völlig anders angehen. Das nur als Randbemerkung.

Makefile erstellen

Unser Ausgangspunkt ist gnu make. Also legen wir zunächst eine neues Makefile in unserem Projektordner an. So das Unsere Struktur so aussieht:

  • rpm-uebung
    • src
      • rpm-uebung.sh
    • Makefile

Hier der Komplette Inhalt als Übersicht und zum kopieren (Ganz wichtig! Die Einrückungen müssen Tabs sein und dürfen keine Leerzeichen sein. Sonst wird GNU Make die Arbeit verweigern):


PREFIX=
VERSION=1
PROGNAME=rpm-uebung
ARCHIV=$(PROGNAME)-$(VERSION).tar.gz

all:
       echo "Es gibt nichts zu tun..."

install:
       [ -d $(PREFIX)/usr/bin/ ] || mkdir -p $(PREFIX)/usr/bin/
       cp ./src/$(PROGNAME).sh $(PREFIX)/usr/bin/
       chmod uoa+x $(PREFIX)/usr/bin/$(PROGNAME).sh

dist-tar:
       [ -d ./$(PROGNAME)-$(VERSION) ] ||  mkdir ./$(PROGNAME)-$(VERSION) 
       cp -r ./src ./$(PROGNAME)-$(VERSION)/
       cp ./Makefile ./$(PROGNAME)-$(VERSION)
       cp $(PROGNAME).spec ./$(PROGNAME)-$(VERSION)/$(PROGNAME)-$(VERSION).spec
       tar -cvzf $(ARCHIV) $(PROGNAME)-$(VERSION)
       rm -rvf ./rpm-uebung-$(VERSION)

dist-rpm: 
       rpmbuild -ta $(ARCHIV)

.PHONY: dist-rpm dist-tar install


Jetzt noch mal zur Struktur. Im ersten Teil werden verschiedene Variablen gesetzt. Variablen aus zwei Gründen:

  • Zum einen, muss man deren Werde nur an einer Stelle ändern, falls sie geändert werden müssen. Und es ist zu erwarten, das sie sich ändern. So zum Beispiel die Versionsnummer.
  • Zum anderen kann man beiGNU Make über Parameter die Variablen setzen. Diese Eigenschaft werden wir später im Wechselspiel mit dem rpmbuild-tool brauchen.

Der zweite Teil sind die Definitionen der Kommandos die GNU Make kennen und ausführen können soll. Der Kommando-Name (bzw. "Ziel") steht immer links, am Anfang der Zeile und Endet mit einem Doppelpunkt. Alle darauf folgenden Zeilen, die mit einem Tab eingerückt werden, sind dann die Schritte die bei dem Befehlsaufruf abgearbeitet werden.

Die letzte Zeile definiert, welche Funktionen/Befehle immer ausgeführt werden sollen. Normalerweise überprüft make nämlich ob die Quelle - die Source-Datei - neuer als das Ziel - die Binär-Datei - ist um zu entscheiden, ob ein Neubau nötig ist.

Unser make-Skript ist nun fertig benutzbar. Wenn wir jetzt den Befehl...

make

...aufrufen, bekommen wir die Meldung:

"Es gibt nichts zu tun..."

...Zurück. Wenn make ohne Parameter aufrufen, springt es automatisch in "all:". Bei einem Programm was kompiliert werden muss, würde das hier gemacht werden. Bei einem Bash-Skript ist das aber nicht nötig.

Anders sieht es mit dem Befehl...

 make install

...aus. Hier kopieren wir unser Skript die richtige stelle in das System. Die Variable $(PREFIX) kommt hier in Spiel. Die ist für uns wichtig, mit wir später das rpm ohne root-Rechte bauen können. Oder mit der Benutzer, das Skript an eine Stelle installieren kann, wo er es lieber hat. Das macht er dann so...

 make PREFIX=opt install 

...in diesem Fall würde das Skript nach /opt/usr/bin/ installiert werden. Soweit erst mal. Auf die anderen Teile kommen wir noch zu sprechen.

Der RPM-Bau (Spec-File)

Jetzt kommen wir zum eigentlich RPM-Bau. Das wird ein Zusammenspiel zwischen GNU Make und rpmbuild.

Zunächst das Spec-Fiel in der Übersicht zum zum kopieren:


Summary: Eine rpm uebung
License: GPL
Name: rpm-uebung
Version: 1
Release: 1
Source: rpm-uebung-1.tar.gz
Group:  Development/Tools
BuildArch: noarch
BuildRoot: /var/tmp/%{name}-buildroot 

%description
Kleine Programm, das den Benutzer mit seinem Loginnamen begruesst.

%prep
%setup

%build

%install
make PREFIX=$RPM_BUILD_ROOT install

%files
%defattr(0755,root,root)
/usr/bin/rpm-uebung.sh


...Der Aufbau ist syntaktisch völlig anders als beim Makefile. Am Anfang stehen wieder die Definition von Variablen. Hier ist das ":" eine Zuweisung und keine Bedingung wie bei GNU Make.

Bevor ich ins Detail gehe, speichern wir die Datei als "rpm-uebung.spec". Wichtig ist, das dass File wie das Projekt heißt. Unser Verzeichnis sollte nun so aussehen:

  • rpm-uebung
    • src
      • rpm-uebung.sh
    • Makefiles
    • rpm-uebung.spec

Noch mal ins Detail...

 Summary: Eine rpm uebung

Kurze Zusammenfassung was das für ein Programm ist.

 License: GPL

Klar, die Lizenz.

 Name: rpm-uebung

Der Name unseres Programms.

 Version: 1
 Release: 1

Die Versions- und Release-Nummer

 Group:  Development/Tools

Die Software-Gruppe. Gut, für unseren Fall gibt es hier kein wirklich sinnvollen Wehr.

 %description
 Kleine Programm, das den Benutzer mit seinem Loginnamen begruesst.

Hier kommt die etwas ausführliche Beschreibung (die bei uns aber nicht sehr ausführlich ist). Dann folgen die Regeln für den Build und die Installation, auf die wir gleich im Detail eingehen.

%files %defattr(0755,root,root) /usr/bin/rpm-uebung.sh

In den letzten Zeilen wird festgehalten, welche Dateien bei der Installation angelegt werden. Und (mit %defattr(0755,root,root)) wird festgelegt, welche Rechte die Dateien bekommen. Da es sich um eine Ausführbare Datei handelt, muss es 0755 sein.

Erläuterung/Benutzung:

Der User ruft zunächst den Befehl "dist-tar" auf. Das erstellt ein Tar-Archiv unseres Programmst. Dann ruft der Benutzer Befehl "make dist-rpm" auf. In unserem Makefile wird nun der rpmbuild-Befehl parametisiert aufgerufen...

dist-rpm: 
       rpmbuild -ta $(ARCHIV)

Will man den ersten Befehl implezieren um dem User ein Schritt zu erspahren, kann man die Zeile wie Folgt abwandeln.

dist-rpm: dist-tar
       rpmbuild -ta $(ARCHIV)

...Nun weiß make von alleine, das es vorher "dist-tar:" ausführen muss.

Das rpmbuild wird nun seinerseits das Makefile bzw make aufrufen um sich den Installationsprozess anzusehen. Mit dies nicht im root-Verzeichnis geschieht, wird das wieder parametrisiert. Deshalb haben wir auch oben Variablen im Makefile benutzt...

 make PREFIX=$RPM_BUILD_ROOT install

Wird dem make nicht der Prefix übergeben, würde das Skript versuchen tatsächlich das Programm im System zu installieren. Das schlägt ohme root-Rechte fehl.

Wenn nichts schief gelaufen ist, sollte jetzt ein installierbares rpm-Paket da sein und zwar im Verzeichnis /RPMS unterhalb der rpm-Build-Umgebung, die auf jedem System in aller Regel im Verzeichnis /home/USERNAME/rpmbuild/ liegt.