martedì 7 settembre 2010

Scrittura di uno SlackBuild

Su linux molto spesso per amministrare il sistema si scrivono dei comandi da terminale, questi possono servire per: ricompilare un kernel, per fare dei backup regolari o altre mansioni ripetitive che richiedono una lunga successione di comandi con un'eventuale perdita di tempo.
Con uno script di shell questi comandi vengono scritti una sola volta e quando tornano utili vengono lanciati dall'amministratore di sistema per fare tutto in automatico, uno di questi script è lo SlackBuild, script di Slackware per costruire pacchetti da sorgenti.





Andiamo a vedere in dettaglio come scrivere uno slackbuild, qui troverete degli esempi si slackbuild finiti, che opportunamente modificati vi faranno costruire il vostro pacchetto.

intestazione

  • La shell da utilizzare è sempre /bin/sh
  • Specificare per quale versione di slackware è scritto lo SlackBuild
  • L'autore dello SlackBuild. Potete mettere il nome o il nick, ma come contatto possibilmente mettete un indirizzo email (mio <at> indir.email)
  • L'ultimo che l'ha modificato e compilato (ovvero tu)
  • Il nome del pacchetto e il sito ufficiale
  • Una licenza per la distribuzione dello slackbuild 
#!/bin/sh

# Heavily based on the Slackware 13.1 SlackBuild

# Written by <your name> ( a contact )
# Last build from <your name> ( a contact )

# Slackware build script for <appname>
# Official Site: http://......

# Redistribution and use of this script, with or without modification, is
# permitted provided that the following conditions are met:
#
# 1. Redistributions of this script must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Se è già presente una licenza lasciarla, altrimenti metti la precedente

parametri di base

La seguente sezione è quella che contiene i parametri base, cioè il nome del pacchetto, la versione, l'architettura, la build version e l'url diretto da dove scaricare i sorgenti. Per quanto riguarda il BUILD, la norma è che ad ogni modifica del pacchetto, ricompilazione ecc, il numero va incrementato, mentre all'upgrade (cambio di versione) questo numero ritorna ad 1. Per quanto riguarda il TAG (la sigla dopo il numero), a partire dal repository per Slackware 13.1 questo deve essere obbligatoriamente 'sl', inclusi per i pacchetti già presenti nel 13.0 che verranno semplicemente ricompilati senza modifiche per essere portati nel nuovo repository. Questo perchè ora la sigla non indica più l'autore ma il repository su cui si trova.
Per l'url utilizzate esclusivamente il sito ufficiale del prodotto. Occhio ai doppi apici in SOURCE= . Spesso funziona anche senza ma in qualche caso può succedere un casino. Fate anche attenzione a quegli url che come separatore non hanno un trattino bensì un underscore (_) pechè in tal caso la sintassi $PKGNAME_$VERSION non funziona, visto che bash considera quell'underscore come parte del nome della variabile. In tal caso sostituite $PKGNAME con ${PKGNAME}: ${PKGNAME}_${VERSION}. Dove non è necessario (ovvero dove ci sono i trattini semplici) preferisco lasciarlo senza le parentesi graffe perchè aumenta la leggibilità.
 
set -e

PKGNAME=appname
VERSION=${VERSION:-1.4.1}
BUILD=${BUILD:-1}
TAG=${TAG:-sl}
ARCH=${ARCH:-i486}
SOURCE="http://downloads.sourceforge.net/project/......./$PKGNAME-$VERSION/$PKGNAME-$VERSION.tar.gz"

path di lavoro

Questa parte è fissa, cioè la determinazione dei path di lavoro
 
CWD=$(pwd)
TMP=${TMP:-/tmp/buildpkgs/$PKGNAME}
PKG=$TMP/package-$PKGNAME
OUTPUT=${OUTPUT:-$CWD}

download

Quindi si fa il download del pacchetto. Solitamente dovreste modificare queste righe solo se il nome del pacchetto non segue lo standard appname-1.4.1.tar.gz (es appname-1.4.1.tar.bz2, appname_1.4.1.tar.gz, appname-1.4.1-kde4.tar.gz, ecc...), oppure se si deve scaricare altri file da internet (p.e. patch)
 
if [ ! -e $PKGNAME-$VERSION.tar.gz ];then
wget $SOURCE
fi

architettura

In base all'architettura definita in $ARCH, vengono definiti i parametri della compilazione. Da notare il LIBDIRSUFFIX che determina se le librerie andranno a finire in /usr/lib o /usr/lib64
 
CHOST="i468"
if [ "$ARCH" = "i486" ]; then
SLKCFLAGS="-O2 -march=i486 -mtune=i686"
LIBDIRSUFFIX=""
elif [ "$ARCH" = "i586" ]; then
SLKCFLAGS="-O2 -march=i586 -mtune=i686"
LIBDIRSUFFIX=""
elif [ "$ARCH" = "i686" ]; then
SLKCFLAGS="-O2 -march=i686 -mtune=i686"
LIBDIRSUFFIX=""
elif [ "$ARCH" = "x86_64" ]; then
SLKCFLAGS="-O2 -fPIC"
LIBDIRSUFFIX="64"
CHOST="x86_64"
fi

preparazione dei sorgenti

Segue la:
  • rimozione di una compilazione precedente
  • scompattazione dei sorgenti
  • applicazione di eventuali patch; queste devono essere presenti nella stess directory dello SlackBuild e possono essere facoltativamente compresse.
  • settaggio dei permessi. E' opportuno che i permessi dei sorgenti siano solamente 755 o 644 e che i file siano tutti di root.
rm -rf $TMP
mkdir -p $TMP $PKG $OUTPUT

cd $TMP
tar xvf $CWD/$PKGNAME-$VERSION.tar.gz
cd $PKGNAME-$VERSION
### installazione patch (se presenti)
# patch -p1 < $CWD/some_patch.diff
# gzip -cd $CWD/compressed_patch.diff.gz |patch -p1

chown -R root:root .
chmod -R u+w,go+r-w,a-s .

compilazione

Comincia la compilazione. Nella maggior parte dei casi utilizzeremo lo standard ./configure&&make&&make install.
Per quanto ri guarda i parametri del configure, questi variano ovviamente da pacchetto a pacchetto, ma alcuni standard vanno seguiti:
  • Il pacchetto va installato in /usr
  • La configurazione deve andare in /etc
  • La documentazione in /usr/doc/nomepacc-versionepacc; tutti i file che si troveranno in altri path (i.e. /usr/share/doc) andranno poi spostati in tale directory
  • Le man pages vanno in /usr/man. Stesso discorso se l'installer le mette in /usr/share/man allora bisogna spostarle successivamente.
  • I dati andrebbero messi in /var/nomepacchetto o /var/lib/nomepacchetto, a seconda del pacchetto. P.E. apache li mette in /var/www, mysql li mette in /var/lib/mysql
  • Le librerie (questo è importante) vanno messe in /usr/lib per i pacchetti a 32bit e in /usr/lib64 per i pacchetti a 64bit. Questo viene fatto automaticamente se si mette correttamente --libdir=/usr/lib$LIBDIRSUFFIX e sopra viene definito LIBDIRSUFFIX a seconda dell'architettura. Se avete una macchina a 32bit e scrivete solamente pacchetti a 32bit, lasciate comunque questa accortezza per aiutare chi vorrà compilare il pacchetto a 64bit
  • In aggiunta metterete tutte le altre opzioni specifiche del software.
  • Per passare parametri a make (tipo "-j2" per ottimizzare la velocità, e altro), non viene più messo all'interno dello SlackBuild, ma si utilizza una variabile standard di make: MAKEFLAGS. Il MAKEFLAGS viene specificato fuori dello slackbuild per consentire al pacchettizzatore di passare parametri al comando 'make'. Per esempio MAKEFLAGS="-j2" bash pacchetto.SlackBuild
CFLAGS="$SLKCFLAGS" \
CXXFLAGS="$SLKCFLAGS" \
./configure \
--prefix=/usr \
--libdir=/usr/lib$LIBDIRSUFFIX \
--sysconfdir=/etc \
--localstatedir=/var \
--mandir=/usr/man \
--docdir=/usr/doc/$PKGNAME-$VERSION \
--build=$CHOST-slackware-linux
make
make install DESTDIR=$PKG

cmake

Alcuni pacchetti per essere compilati necessitano di cmake anzichè ./configure. In tal caso valgono comunque tutte le considerazioni fatte sopra, ma la sintassi è diversa:
 
( mkdir -p build
cd build
cmake .. \
-DCMAKE_C_FLAGS:STRING="$SLKCFLAGS" \
-DCMAKE_CXX_FLAGS:STRING="$SLKCFLAGS" \
-DCMAKE_INSTALL_PREFIX=/usr \
-DMAN_INSTALL_DIR=/usr/man \
-DSYSCONF_INSTALL_DIR=/etc \
-DLIB_SUFFIX=${LIBDIRSUFFIX}
make $MAKEFLAGS
make install DESTDIR=$PKG $MAKEFLAGS)

personalizzazione

Le sezioni che seguono sono quelle che probabilmente più dovrete personalizzare. Quì si devono cancellare file inutili o che rischiano di sovrascrivere quelli di sistema, spostare alcuni file in altri path ecc.
### In this section you may remove some not needed files or move that file in other path
Ricordate che se avete compilato un modulo perl, probabilmete vi sarà stato creato un file che, se messo nel pacchetto, va a sostiturire quello già presente sul sistema. Ovviamente se non state compilando un modulo perl non inserirete questa sezione.
 
## remember to put this block if you are packeting a perl software, otherwise you may overwrite some system file
( cd $PKG
# Remove 'special' files
find . -name perllocal.pod \
-o -name ".packlist" \
-o -name "*.bs" \
| xargs rm -f
)

Potrete anche copiare file di configurazione ed eventuali altri file dalla directory dello SlackBuild.
Ricordate poi che gli script di start e stop si dovrebbero mettere possibilmente sotto /etc/rc.d; ricordo anche che tutti i file di configurazione (script inclusi) vanno messi con l'estensione .new per essere poi rinominati a posteriori nel doinst.sh..
 
cat $CWD/rc.application.sh > $PKG/etc/rc.d/rc.application.new
cat $PKG/etc/init.d/initscript >> $PKG/etc/rc.d/rc.program.new
rm $PKG/etc/init.d/initscript
mv $PKG/etc/appl.conf $PKG/etc/appl.conf.new

documentazione

Inoltre copiamo tutta la documentazione che riusciamo a trovare nei sorgenti del pacchetto (README, INSTALL, ChangeLog, ecc..) nella directory della documentazione. Nella stessa directory ci metteremo anche lo SlackBuild con cui è stato generato il pacchetto e slack-desc.
 
mkdir -p $PKG/usr/doc/$PKGNAME-$VERSION
cp -a \
README.TXT INSTALL.TXT some other documentation \
$PKG/usr/doc/$PKGNAME-$VERSION

cat $CWD/$PKGNAME.SlackBuild > $PKG/usr/doc/$PKGNAME-$VERSION/$PKGNAME.SlackBuild
cat $CWD/slack-desc > $PKG/usr/doc/$PKGNAME-$VERSION/slack-desc

Lo standard di slackware è che tutte le manpages siano compresse con gzip per risparmiare spazio su disco; di conseguenza cerchiamo versioni non compresse che installano i pacchetti e comprimiamole.
 
if [ -d $PKG/usr/man ]; then
( cd $PKG/usr/man
find . -type f -exec gzip -9 {} \;
for i in $( find . -type l ) ; do ln -s $( readlink $i ).gz $i.gz ; rm $i ; done
)
fi

strip

Puliamo anche i file binari e le librerie eliminando tutti gli strascichi che lascia gcc al fine di debuggure e linkare tra di loro gli object generati.
 
( cd $PKG
find . | xargs file | grep "executable" | grep ELF | cut -f 1 -d : | xargs -r strip --strip-unneeded 2> /dev/null || true
find . | xargs file | grep "shared object" | grep ELF | cut -f 1 -d : | xargs -r strip --strip-unneeded 2> /dev/null || true
find . | xargs file | grep "current ar archive" | cut -f 1 -d : | xargs -r strip --strip-unneeded 2> /dev/null || true
)

slack-desc e doinst.sh

Abbiamo quasi finito... Popoliamo la directory install/ del pacchetto. Quì ci andrà lo slack-desc e, se necessario, il doinst.sh.
 
mkdir -p $PKG/install
cat $CWD/slack-desc > $PKG/install/slack-desc

Possibilmente il doinst.sh non lo creiamo direttamente dentro lo SlackBuild, ma mettiamolo come file esterno per poi copiarlo nella directory install/. Se poi abbiamo bisogno di aggiungere operazioni di cui non sappiamo a priori le specifiche, ma le sappiamo solo dopo la compilazione, allora aggiungiamole da dentro lo SlackBuild con un >>. Un esempio di operazione necessaria è quella di avviare uno script di postinstallazione presente sotto la /usr/lib; ovviamente non sappiamo a priori se sarà in /usr/lib o /usr/lib64.
 
cat $CWD/doinst.sh > $PKG/install/doinst.sh
echo "( cd usr/lib$LIBDIRSUFFIX/$PKGNAME ; ./postinstall.sh )" >> $PKG/install/doinst.sh

slack-required

Ora andiamo a costruire il file delle dipendenze slack-required. Questo si genera con il tool requiredbuilder. Ricordiamoci di installare sempre l'ultima versione di questo tool prima di compilare. Dovremo anche assicurarci che i file del pacchetto siano tutti di root, poi lanciamo il requiredbuilder per costruire le dipendenze e finalmente creiamo il pacchetto.
 
### reset owner and create slack-required file using requiredbuilder.requiredbuilder.
cd $PKG
chown -R root:root $PKG

if [ -x "$(which requiredbuilder 2>/dev/null)" ];then
requiredbuilder -y -v -s $CWD $PKG
fi

costruzione pacchetto

Finalmente abbiamo finito. Possiamo costruire il nostro pacchetto.
 
/sbin/makepkg -l y -c n $OUTPUT/$PKGNAME-$VERSION-$ARCH-$BUILD$TAG.${PKGTYPE:-txz}

Se poi il pacchettizzatore è sicuro che andrà tutto a buon fine, può decidere di lanciare lo slackbuild con il parametro --cleanup per rimuovere le directory di lavoro al termine del processo.
 
if [ "$1" = "--cleanup" ]; then
rm -rf $TMP
fi

doinst.sh

Il doinst.sh viene utilizzato per effettuare tutte quelle operazioni che provvederanno ad integrare il pacchetto nel resto della distribuzione. Per esempi tipici di doinst.sh vedi la directory /var/log/scripts che è una raccolta dei doinst.sh di tutti i pacchetti installati sul sistema.
Ecco alcuni usi:

rinomina file di configurazione .new

Questo forse è l'uso maggiore per cui si crea un doinst.sh.
Quando nello SlackBuild abbiamo creato un file tipo etc/configfile.new, il doinst deve provvedere a rinominarlo in etc/configfile a patto che quest'ultimo non esista già sul sistema. Nello script viene definita una funzione, config (da non toccare), che fa questo lavoro. Al pacchettizzatore è sufficente richiamala con config etc/configfile.new. Utilizzate i path relativi!!
 
config() {
NEW="$1"
OLD="$(dirname $NEW)/$(basename $NEW .new)"
# If there's no config file by that name, mv it over:
if [ ! -r $OLD ]; then
mv $NEW $OLD
elif [ "$(cat $OLD | md5sum)" = "$(cat $NEW | md5sum)" ]; then
# toss the redundant copy
rm $NEW
fi
# Otherwise, we leave the .new copy for the admin to consider...
}

config etc/configfile.new
config etc/program/my.conf.new

gli script di start

Per gli script in rc invece va fatta una aggiunta; infatti se un file rc con lo stesso nome già esiste, allora è necessario che abbiano gli stessi permessi. Questo si fa così:
 
if [ -e etc/rc.d/rc.script ]; then
cp -a etc/rc.d/rc.script etc/rc.d/rc.script.new.incoming
cat etc/rc.d/rc.script.new > etc/rc.d/rc.script.new.incoming
mv etc/rc.d/rc.script.new.incoming etc/rc.d/rc.script.new
fi
config etc/rc.d/rc.script.new

i link

Se lo SlackBuild ha creato dei link, con ln o con make install, questi non verranno inseriti nel txz finale. Al posto loro verrà messa nel doinst.sh una riga per ogni link che provvederà a crearlo in fase di postinstallazione. A fare questa operazione ci penserà makepkg che per ogni link che trova metterà una cosa del genere nel doinst.sh:
 
( cd usr/bin ; rm -rf view )
( cd usr/bin ; ln -sf vim view )

quindi di questo non dovremo preoccuparci

file icona, menu, .desktop ecc

Quando si installano pacchetti per kde e/o si aggiungono nuove icone e/o file .desktop ecc.., è necessario aggiornare il database di kde.
 
if [ -x /usr/bin/update-desktop-database ]; then
usr/bin/update-desktop-database -q usr/share/applications >/dev/null 2>&1
fi
if [ -x /usr/bin/update-mime-database ]; then
usr/bin/update-mime-database usr/share/mime >/dev/null 2>&1
fi
if [ -e usr/share/icons/hicolor/icon-theme.cache ]; then
if [ -x /usr/bin/gtk-update-icon-cache ]; then
usr/bin/gtk-update-icon-cache usr/share/icons/hicolor >/dev/null 2>&1
fi
fi

post-installazione personalizzata

Potrebbe essere necessario avviare qualche script di postinstallazione al termine del doinst. Se lo script non si trova nel path, allora solitamente si fa un 'cd directory' e './script'. Cerchiamo di utilizzare sempre percorsi relativi e mai assoluti perchè se stiamo installando in un chroot (come spiegato all'inizio dell'articolo) allora si rischia di incasinare il sistema principale
 
( cd usr/share/programma ; ./postinstall.sh )

se il postinstall si trova sotto usr/lib, allora dobbiamo inserire questa riga dallo SlackBuild per determinare perchè non sappiamo a priori se utilizziamo una slackware a 32 o 64bit e quindi se lo script è in usr/lib o usr/lib64.
 
echo "( cd usr/lib$LIBDIRSUFFIX ; ./postinstall.sh )" >> $PKG/install/doinst.sh

In caso lo script al suo interno faccia riferimento a percorsi assoluti del sistema, allora dovremo lanciare tale comando in chroot:
 
chroot . usr/share/programma/postinstall.sh

utenti

Prima del makepkg abbiamo settato tutti i proprietari dei file a root. Se abbiamo qualche pacchetto che richiede di essere avviato come altro utente (p.e. squid) dovremo provvedere a creare l'utente e, se serve, anche il gruppo. Prima dovremo controllare però che già non esista. Ovviamente dovremo utilizzare useradd e groupadd che vanno a modificare l'/etc/passwd e l'/etc/group; si rende quindi necessario il lancio in chroot per evitare che si creino le utenze sul sistema sbagliato
 
if ! grep -q "^nomegruppo:" etc/group; then
chroot . groupadd mygroup &>/dev/null
fi
if ! grep -q "^nomeutente:" etc/passwd; then
chroot . useradd -d /var/lib/nomeprogramma -s /bin/false -c "Utente programma" -g nomegruppo nomeutente &>/dev/null
fi

e poi settare i permessi adeguati, permessi che abbiamo tolto dallo slackbuild con chown root.root
 
chown -R nomeutente.nomegruppo var/lib/nomeprogramma

utenti e id

Talvolta si potrebbe volere un determinato uid e gid per utenti e gruppi; uno useradd secco genera un id solitamente alto, che potrebbe confondersi con le utenze classiche mentre i servizi hanno spesso e volentieri id bassi. Vedi il corrente /etc/passwd. Nel modo seguente è possibile 'tentare' di scegliere un determinato id e, se fallisce, allora ripiegare su un id normale.
 
if ! grep -q "^apache:" etc/group; then
if ! grep -q ":80:" etc/group; then
chroot . groupadd -g 80 apache &>/dev/null
else
chroot . groupadd apache &>/dev/null
fi
fi

if ! grep -q "^apache:" etc/passwd; then
if ! grep -q ":80:" etc/passwd; then
chroot . useradd -u 80 -d /var/www -s /bin/false -c "Apache User" -g apache apache &>/dev/null
else
chroot . useradd -d /var/www -s /bin/false -c "Apache User" -g apache apache &>/dev/null
fi
fi
chown apache.apache var/www/htdocs

slack-desc

Questo è più semplice. Si tratta di mettere una descrizione del pacchetto di un massimo di 11 righe e un massimo di 72 caratteri per riga. Personalmente prendo qualche riga dal README o dal sito ufficiale e lo copio lì dentro. Come esempi di descrizione si possono prendere tutti quelli di slackware.
La struttura di questo file è molto rigida. Le prime 6 righe sono solo commenti (le istruzioni per costruire lo slack-desc, ma vanno lasciate. La riga successiva, la handy-ruler, è un remember sul numero limite di caratteri per riga. La descrizione è fatta di esattamente 11 righe (se ne vuoi di meno basta lasciarle vuote) composte di nomepacchetto, due punti, spazio, descrizione. Il nome del pacchetto deve essere esattamente lo stesso indicato in $PKGNAME
Non deve essere inserito il nome del pacchettizzatore né l'url del programma.
 
# HOW TO EDIT THIS FILE:
# The "handy ruler" below makes it easier to edit a package description. Line
# up the first '|' above the ':' following the base package name, and the '|' on
# the right side marks the last column you can put a character in. You must make
# exactly 11 lines for the formatting to be correct. It's also customary to
# leave one space after the ':'.

|-----handy-ruler------------------------------------------------------|
pkgname: pkgname - A title for package
pkgname:
pkgname: Long description
pkgname:
pkgname:
pkgname:
pkgname:
pkgname:
pkgname:
pkgname:
pkgname:
 
per questa guida ringrazio la comunità di slacky.eu alla prossima .

Nessun commento:

Posta un commento