Spec

Questa è una guida per la creazione di pacchetti rpm generici. Per i file di spec specifici per la creazione di pacchetti per openSUSE Build Service vedere la pagina apposita.

La "ricetta" per la creazione di una pacchetto rpm é un file "spec". Questi file terminano con l'estensione ".spec" e contengono il nome del pacchetto, la versione, il numero di revisione RPM, i passi per costruire, installare, e "pulire" il pacchetto, e un log dei cambiamenti. Molti pacchetti (destinati a diversi sistemi operativi e processori) possono essere costruiti da un singolo file spec, se lo si desidera, e soprattutto se si ha la capacità di crearne uno annidato. I pacchetti rpm vengono creati dai file spec, utilizzando il comando "rpmbuild". Ma vediamo ora come preparare il nostro sistema a pacchettizzare da utente e non do root evitando quindi spiacevoli sorprese, per poi analizzare in dettaglio il file spec.

Preparare il nostro sistema

Teoricamente un pacchetto per essere compilato necessita di essere costruito con i diritti di root, questa situazione però può provocare errori inattesi..una errata configurazione del file spec infatti può portare all'installazione del pacchetto, che se compilato erroneamente potrebbe alterare la stabilità del sistema. Vediamo quindi come rendere possibile la compilazione da utente evitando quindi ogni tipo di problema.

Di default gli rpm vengono pacchettizzati in /usr/src/packages/ oppure in /usr/src/rpms/ in base alle distro, il nostro obbiettivo è quello di ricreare la struttura di queste cartelle nella nostra home!

Il testo evidenziato nei riquadri è case sensitive vuol dire che c'è differenza tra lettere MAIUSCOLE o minuscole. BAR è diverso da bar che a sua volta è diverso da bAr ecc, ecc.

Questo è un messaggio di attenzione


La struttura che vogliamo ricreare è la seguente:

/usr/src/packages/RPMS/noarch 
    (In questa cartella vengono creati pacchetti multi-archittettura)

/usr/src/packages/RPMS/i586
    (In questa cartella vengono creati pacchetti con architettura i586)

/usr/src/packages/RPMS/i686
    (In questa cartella vengono creati pacchetti con architettura i686)

/usr/src/packages/RPMS/i486
    (In questa cartella vengono creati pacchetti con architettura i486)

/usr/src/packages/RPMS/i386
    (In questa cartella vengono creati pacchetti con architettura i386)

/usr/src/packages/RPMS/athlon
    (In questa cartella vengono creati pacchetti con architettura athlon)

/usr/src/packages/BUILD
    (In questa cartella vengono decompressi ed elaborati i sorgenti)

/usr/src/packages/SRPMS
    (In questa cartella vengono creati gli rpm dei sorgenti, con estensione .src.rpm)

/usr/src/packages/SOURCES
    (In questa cartella vengono "depositati" i sorgenti da elaborare)

/usr/src/packages/SPECS
    (In questa cartella vengono "depositati" i file spec)

/usr/src/tmp
    (se esiste, è la cartella in cui si salvano temporaneamente i file prima di essere pacchettizzati, in altri casi si usa la cartella /tmp)

Ora che abbiamo preso conoscenza di quello con cui andremo a lavorare, apriamo una shell e digitiamo da utente e NON DA ROOT quanto segue: (poichè tutti i comandi andranno digitati da utente non verrà utilizzata la convenzione dei segni, $ utente, # root).

cd ~
mkdir -p src/rpm/RPMS/i386
mkdir -p src/rpm/RPMS/i486
mkdir -p src/rpm/RPMS/i586
mkdir -p src/rpm/RPMS/i686
mkdir -p src/rpm/RPMS/noarch
mkdir -p src/rpm/RPMS/athlon
mkdir -p src/rpm/SRPMS
mkdir -p src/rpm/SOURCES
mkdir -p src/rpm/BUILD
mkdir -p src/tmp

Adesso bisognerà creare nella nostra home 2 file di testo conteneti alcune configurazioni. Il primo chiamato .rpmrc il secondo .rpmmacros. Ricordatevi il punto (.) in quanto i file saranno nascosti.

Nel primo (.rpmrc) incolliamo questo testo:

buildarchtranslate: i386: i586
buildarchtranslate: i486: i586
buildarchtranslate: i586: i586
buildarchtranslate: i686: i586

Questo file è necessario inquanto la maggior parte delle distro utilizzano solamente architettura i586, ed alcuni prorammatori potrebbero aver creato il file spec per architetture differenti.

Nel secondo file (.rpmmacros), invece scriviamo quanto segue:

 %_topdir     /home/anubis/src/rpm
 %_tmppath    /home/anubis/src/tmp
 
 %distribution  SUSE
 %vendor        SUSE
 %distsuffix    anubisg1

ovviamente modificando alle prime 2 righe /home/anubis con la vostra home (/home/nome_utente); in %distribution e %vendor sostituite SUSE con il nome della vostra distribuzione, nel mio è openSUSE, in %distsuffix dovrete sostituire anubisg1 con il vostro nick, o comunque con un suffisso che serva ad identificare univocamente i vostri pacchetti.

Il nostro computer ora è pronto, procuriamoci un file spec e analizziamolo in dettaglio.

Ottenere il primo file spec da studiare

Poichè per ora non abbiamo la minima idea di cosa sia, e di come sia strutturato un file spec, abbiamo la necessità di procurcene uno già preparato, magari con il codice sorgente a cui si riferisce, per poterlo magari usare e creare il nostro primo pacchetto. Per fare ciò dobbiamo scaricare un file di estensione .src.rpm, questo rpm contiene al suo interno solamente il codice sorgente (con relative patch, se esistenti) e il file spec necessario a compilarlo. in questo esempio utilizzeremo il file amsn-0.97RC1-9.1.src.rpm che scaricheremo direttamente dal mio repository.

Una volta scaricato sul Desktop, per esempio, provvediamo ad installarlo. (ricordate di NON eseguire nessun comando come root)

rpm -ivh /home/nome_utente/Desktop/amsn-0.97RC1-9.1.src.rpm

se avrete eseguito il comando da utente normale, (non mi scoccierò mai di ricordarvelo), troverete questi file installati nel vostro sistema

/home/anubis/src/rpm/SOURCES/amsn-0.97RC1.tar.bz2
          (ovvero il codice sorgente di amsn)

/home/anubis/src/rpm/SPECS/amsn.spec
          (il file spec che tanto sogniamo!)


ottenuti questi due file apriamo il file amsn.spec ed analizziamolo: (per quanto possibile cercherò di mantenere la stessa formattazione, colori compresi, che si ottiene aprendo il file con KWrite)


Name: amsn
Version: 0.97RC1
Release: 9.1
License: GPL
BuildRoot:%{_tmppath}/amsn-0.97RC1-build
Requires: tcl >= 8.4
Requires: tk >= 8.4
BuildRequires: glibc-devel make autoconf automake libtool gcc gcc-c++
BuildRequires: libjpeg-devel libpng-devel xorg-x11-devel
BuildRequires: tcl tk tcl-devel tk-devel
BuildRequires: update-desktop-files
%if %suse_version >= 1021
BuildRequires: gcc41-c++
%endif
Group: Productivity/Networking/AOLInstantMessenger
Packager: Andrea Florio <andreafl@libero.it>
Summary: MSN Messenger clone for Linux
URL: http://www.amsn-project.net/
Source: amsn-0.97RC1.tar.bz2
Conflicts:    amsnSVN 

%description
This is the last STABLE VERSION  

This is Tcl/Tk clone that implements the Microsoft Messenger (MSN) for
Unix,Windows, or Macintosh platforms. It supports file transfers,
groups, and many more features. Visit http://amsn-project.net/ for
details. This is an ongoing project, and it is already going pretty
well.

%prep
%setup -q

%build
%configure --prefix=/usr 

%install
rpm -fr $RPM_BUILD_ROOT
make DESTDIR=$RPM_BUILD_ROOT install
%suse_update_desktop_file -r amsn Productivity/Networking/AOLInstantMessenger

%clean
rm -rf "$RPM_BUILD_ROOT"

%files
%defattr(-,root,root)
%{_bindir}/*
%{_datadir}/amsn/*
%{_datadir}/pixmaps/amsn.png
%{_datadir}/applications/amsn.desktop

Sezione Sommario

la sezione sommario è il primo blocco di istruzioni presente nel file spec:


Name: amsn
Version: 0.97RC1
Release: 9.1
License: GPL
BuildRoot:%{_tmppath}/amsn-0.97RC1-build
Requires: tcl >= 8.4
Requires: tk >= 8.4
BuildRequires: glibc-devel make autoconf automake libtool gcc gcc-c++
BuildRequires: libjpeg-devel libpng-devel xorg-x11-devel
BuildRequires: tcl tk tcl-devel tk-devel
BuildRequires: update-desktop-files
%if %suse_version >= 1021
BuildRequires: gcc41-c++
%endif
Group: Productivity/Networking/AOLInstantMessenger
Packager: Andrea Florio <andreafl@libero.it>
Summary: MSN Messenger clone for Linux
URL: http://www.amsn-project.net/
Source: amsn-0.97RC1.tar.bz2
Conflicts:    amsnSVN 

Quesa parte non è difficile da capire, vengono infatti elencate le caratteristiche principali del pacchetto:

  • Name: - il nome
  • Version: - la versione
  • Release: - il "rilascio"
  • License: - la licenza con cui viene distribuito
  • BuildRoot - è la cartella dove vengono elaborati in file temporanei, precedentemente l'abbiamo definita nel file .rpmmacros, più esattamente abbiamo definito la %{_tmppath}.
  • Requires - indica le dipendenze necessarie a far "funzionare" il programma, mentre BuildRequires indica le dipendenze necessarie alla compilazione del pacchetto; in entrambi i casi si potrebbero scrivere tutte le dipendenze in un'unica riga, divise da uno spazio, ma si preferisce solitamente dividerle (vedi le due righe utilizzate per Requires) in caso di dipendenze particolarmente importanti che necessitano di essere visualizzate immediatamente.
  • Group - indica il gruppo di apparteneza del pacchetto, grazie a questo, se esiste, viene posizionata l'icona del programma nel vostro menù
  • Packager: - è chi pacchettizza il programma
  • Summary: - una breve descrizione del programma
  • URL: - è il sito di riferimento del programma
  • Source: - è il nome del codice sorgente
  • Conflicts: - è una lista di pacchetti con il quale il nostro, eventualmente può entrare in conflitto

Solo una parte richiede una spiegazione più approfondita:

%if %suse_version >= 1021
BuildRequires: gcc41-c++
%endif

Questo pezzo infatti e un "condizionale", la base per creare spec annidati per varie distribuzioni. In questo caso viene "comandato":

Se (%if) la versione di suse (%suse_version) è maggiore o uguale alla 10.2 (>= 1021) allora un BuildRequires aggiuntivo è il pacchetto gcc41-c++. La fine del comando è dato da endif (fine-se).

Le Macro

Per una definizione approfondita del termine macro in informatica rimando a questo link.

Sostanzialmente però, le macro permettono di definire tramite una singola "parola" un'intera funzione, o un percorso, o qualunque altra cosa noi vogliamo. Ciò serve per non riscrivere ogni volta una stringa più o meno lunga, basterà infatti inserire la macro precedentemente definita.

Le Macro presenti nel nostro file spec

Nel file spec che stiamo utilizzando sono presenti solamente tre macro.

  • %{_tmppath}
  • %{_bindir}
  • %{_datadir}

Queste 3 non sono state definite nel file spec, vediamo ora il perchè e a cosa si riferiscono:

la prima:

  • %{_tmppath}

è stata definita precedentemente nel file .rpmmacros:

%_tmppath    /home/anubis/src/tmp

ciò vuol dire che la stringa

BuildRoot: %{_tmppath}/amsn-0.97RC1-build

è identica a

BuildRoot: /home/anubis/src/tmp/amsn-0.97RC1-build

La seconda e la terza invece:

  • %{_bindir}
  • %{_datadir}

sono alcune delle macro standard predefinite di rpm. Ecco alcune di queste macro predefinite:

%{_bindir}         /usr/bin
%{_datadir}        /usr/share
%{_libdir}         /usr/lib
%{_sysconfdir}     /etc
%{_mandir}         /usr/share/man
%{_docdir}         /usr/share/doc
%{_iconsdir}       /usr/share/icons

Altre Macro standard

Oltre alle precedenti tre importantissime macro standard quasi sempre utilizzate sono le seguenti:

  • %{name}
  • %{version}
  • %{release}

queste tre vengono definite automaticamente all'inzio del file spec, indicano infatti il nome, la versione e la release del nostro pacchetto; praticamente le prime tre righe dello spec. Vediamo come sono comunemente utilizzate, servendoci della stringa:

BuildRoot: %{_tmppath}/amsn-0.97RC1-build

Questa infatti potrebbe essere sostituita con questa:

BuildRoot: %{_tmppath}/%{name}-%{version}-build

analogamente questa:

Source: amsn-0.97RC1.tar.bz2

può essere sostituita con questa:

Source: %{name}-%{version}.tar.bz2

anche se a prima vista sembra meno conveniente utilizzare le macro, andiamo infatti a scrivere una stringa più lunga, l'utilità delle macro appare evidente quando vogliamo aggiornare un pacchetto; Se il programma non è stato modificato radicalmente (non abbiamo ciò necessità di rifare il file spec) ci basterà modificare solo le prime righe e non tutto il file, con il rischio di dimenticare qualcosa.

Definire Macro personalizzate

Definire delle macro personalizzate è semplicissimo, basta seguire questo schema:

%define nome_macro valore_macro

ecco un esempio:

%define xorg /etc/X11

quando vorremo utilizzare questa macro ci basterà digitare %{xorg}

Sezione Descrizione e "Build"

Questa parte può essere definita come il "cuore" del file spec, è qui che si dice come il nostro pacchetto deve essere compilato.

%description
This is the last STABLE VERSION  

This is Tcl/Tk clone that implements the Microsoft Messenger (MSN) for
Unix,Windows, or Macintosh platforms. It supports file transfers,
groups, and many more features. Visit http://amsn-project.net/ for
details. This is an ongoing project, and it is already going pretty
well.

%prep
%setup -q

%build
%configure --prefix=/usr 

%install
rpm -fr $RPM_BUILD_ROOT
make DESTDIR=$RPM_BUILD_ROOT install
%suse_update_desktop_file -r amsn Productivity/Networking/AOLInstantMessenger
 
%clean
rm -rf "$RPM_BUILD_ROOT"

esaminiamo ora il tutto nel dettaglio:

  • %description - Qui va scritta la descrizione del pacchetto con tutte le informazioni necessarie. Questa parte verrà visualizzata all'interno del nostro Gestore di pacchetti.
  • %prep - Con questo comando si prepara l'ambiente di compilazione.
  • %setup -q - Grazie a questa direttiva viene decompresso l'archivio del codice sorgente, è possibile aggiungere l'opzione -n nome_cartella, cioè l'equivalente di cd nome_cartella. Ci si sposta nella cartella indicata, necessario nel caso in cui la cartella in cui si trovano in sorgenti abbia un nome diverso dell'archivio.
  • %build - Con questo comando inizia la compilazione.
  • %configure - il corrispondente di ./configure,mentre --prefix=/usr è una delle opzioni del "configure"
%install
rpm -fr $RPM_BUILD_ROOT
make DESTDIR=$RPM_BUILD_ROOT install

Con questi comandi diamo avvio al make ed al make install. Bisogna notare che $RPM_BUILD_ROOT è un macro, infatti sostituisce interamente la stringa

BuildRoot:%{_tmppath}/%{name}-%{version}-build
  • %suse_update_desktop_file - Questo comando, insieme alle relative opzioni, è supportato solo se è installato il pacchetto update-desktop-files, questo pacchetto
  • %clean - Grazie al clean si pulisce la cartella temporanea. La stringa rm -rf "$RPM_BUILD_ROOT" cancella la cartella temporanea.

Sezione Files

Una volta che abbiamo "installato" il nostro pacchetto dobbiamo dare le indicazioni per inserire nel nostro rpm i file che abbiamo "creato". Queste direttive vengona date dalla sezione files del nostro file spec.

%files
%defattr(-,root,root)
%{_bindir}/*
%{_datadir}/amsn/*
%{_datadir}/pixmaps/amsn.png
%{_datadir}/applications/amsn.desktop
  • %files - Questo è il comando per aprire la sezione files.
  • %defattr (-,root,root) - Qui si impostano i diritti dei file, possono essere inseriti i permessi di chmod, ma sotto forma di "terna numerica", ovvero utilizzando la forma "ottale"
%{_bindir}/*
%{_datadir}/amsn/*
%{_datadir}/pixmaps/amsn.png
%{_datadir}/applications/amsn.desktop

Questa è la lista dei file insieme al loro percorso di destinazione, da notare l'utilizzo delle macro.

Ora abbiamo finito di analizzare il nostro file spec. Vediamo quindi come creare finalmente il nostro rpm partendo dal codice sorgente e dal file spec

Ovviamente il discorso è molto più amplio e complicato.. non mi certo possibile srcivere tutto qui, sarebbe necessario scrivere un libro, e non ho nemmeno tutte le conoscenze necessarie, ma adesso avete una idea di come si comporti il file spec.

Creare il nostro primo rpm

Una volta creato il file spec e il codice sorgente del programma che vogliamo pacchettizzare, la creazione dell'rpm è molto semplice.

Per prima cosa spostare il sorgente all'interno della cartella /home/nome_utente/src/rpm/SOURCES/ (come detto precedentemente se abbiamo installato il pacchetto .src.rpm i file necessari si troveranno già al loro posto).

Successivamente dobbiamo spostarci nella cartella in cui è presente il file spec e quindi digitare:

rpmbuild -ba nome_programma.spec

nel caso del pacchetto che abbiamo esaminato fino ad ora:

cd /home/anubis/src/rpm/SPECS/
rpmbuild -ba amsn.spec

se tutto è andato a buon fine otterremo un output di questo tipo:

Wrote: /home/anubis/src/rpm/SRPMS/amsn-0.97RC1-9.1.src.rpm
Wrote: /home/anubis/src/rpm/RPMS/i586/amsn-0.97RC1-9.1.i586.rpm
Executing(%clean): /bin/sh -e /var/tmp/rpm-tmp.85100
+ umask 022
+ cd /usr/src/packages/BUILD
+ cd amsn-0.97RC1
+ rm -rf /var/tmp/amsn-0.97RC1-build
+ exit 0

Ci viene indicato dove sono stati creati gli rpm (sia del programma che del sorgente). L'operazione andata a buon fine termina con un + exit 0

Ora non vi resta altro che testare il vostro nuovo pacchetto!


Andrea Florio Anubisg1

Argomenti Correlati

Link Esterni