La machine ultime pour compiler ses paquets debian.

Mar. 3, 2011

Voici un “petit” billet qui est à la frontière entre le perso et le boulot, mais qui risque d’être utile pour beaucoup de gens.

Dans le cadre de mon emploi actuel, je passe un certain temps à faire des paquets Debian, mais aussi Ubuntu.

Au début, j’utilisais 2 machines virtuelles, avec un petit pbuilderrc, cependant, ayant eu l’opportunité d’utiliser une machine plus puissante (4 coeurs et 4Go de ram), je me suis dis qu’il serait plutôt pratique de fusionner les 2 machines, et d’avoir qu’une machine de build.

Ma machine de build tourne sous Debian sid, même si j’ai longtemps été fidèle à Ubuntu, maintenant, je suis passé du coté de Debian (y compris pour mon poste de travail).

Pourquoi Debian sid ?, juste pour avoir les dernières versions des outils de build, surtout pour debootstrap.

Ça peut marcher aussi sous Debian stable, et même Ubuntu (mais quelques petites choses sont différentes).

Bon, commençons.

Les commandes précédées d’un “#” sont à exécuter en root, les commandes précédées d’un “$” sont à exécuter en utilisateur normal, non privilégié.

Précision, ma machine étant en 64 bits, j’ai la possibilité de compiler des paquets 32 et 64 bits.

En premier, il faut installer sudo, car avec le temps, j’ai appris (à mes dépends) qu’il ne faut jamais bidouiller ses paquets source en root, car ce n’est pas nécessaire, et que de plus, après quelques heures de tapotage de clavier, la fatigue faisant, on peut faire des actes regrétables et se transformer en Rage Guy pendant 5 minutes.

# aptitude install sudo

Ensuite, il faut adapter la configuration de sudo à ce qu’on fera avec pbuilder.

# visudo

Voici mon fichier de configuration de sudo :

This file MUST be edited with the ‘visudo’ command as root.

Please consider adding local content in /etc/sudoers.d/ instead of

directly modifying this file.

See the man page for details on how to write a sudoers file.

Defaults env_reset,env_keep=“DIST ARCH CONCURRENCY_LEVEL”

Host alias specification

User alias specification

Cmnd alias specification

User privilege specification

root ALL=(ALL:ALL) ALL

Allow members of group sudo to execute any command

%sudo ALL=(ALL:ALL) ALL

#includedir /etc/sudoers.d

Members of the admin group may gain root privileges

%adm ALL=(ALL:ALL) ALL

Remarquez surtout la ligne Defaults qui contient les instructions pour garder le contenu des variables DIST, ARCH et CONCURRENCY_LEVEL. Gardez les noms de ces variables dans la tête, on les utilisera après.

Après avoir installé sudo, on va s’occuper de la partie concrète de la compilation, avec l’installation des outils de compilation.

# aptitude install debhelper build-essential dpkg-dev pbuilder devscripts debootstrap

Parmis ces paquets, les plus remarquables sont pbuilder et debootstrap

Le paquet Lintian est aussi utile, car il permet de tester la conformité des paquets avec la Debian Policy.

Après avoir installé tout ça, il faut encore configurer le pbuilder, avec le fichier pbuilderrc. Vu que je n’aime pas trop aller modifier la configuration par défaut (placée dans /etc/pbuilderrc), je préfére créer le fichier /root/.pbuilderrc). Dont voici le mien.

# Codenames for Debian suites according to their alias. Update these when

needed.

UNSTABLE_CODENAME=“sid” TESTING_CODENAME=“wheezy” STABLE_CODENAME=“squeeze” STABLE_BACKPORTS_SUITE="$STABLE_CODENAME-backports" OLD_STABLE_CODENAME=“lenny” OLD_STABLE_BACKPORTS_SUITE="$OLD_STABLE_CODENAME-backports"

List of Debian suites.

DEBIAN_SUITES=($UNSTABLE_CODENAME $TESTING_CODENAME $STABLE_CODENAME $OLD_STABLE_CODENAME “unstable” “testing” “stable” “experimental”)

List of Ubuntu suites. Update these when needed.

UBUNTU_SUITES=(“natty” “maverick” “lucid” “karmic” “jaunty” “intrepid” “hardy” “gutsy”)

Mirrors to use. Update these to your preferred mirror.

DEBIAN_MIRROR=“ftp.fr.debian.org/” UBUNTU_MIRROR=“fr.archive.ubuntu.com”

Use old-releases mirrors for EOL versions

if [ “${DIST}” == “gutsy” ]; then UBUNTU_MIRROR=“old-releases.ubuntu.com” fi if [ “${DIST}” == “intrepid” ]; then UBUNTU_MIRROR=“old-releases.ubuntu.com” fi

Optionally use the changelog of a package to determine the suite to use if

none set.

if [ -z “${DIST}” ] && [ -r “debian/changelog” ]; then DIST=$(dpkg-parsechangelog | awk ‘/^Distribution: / {print $2}') # Use the unstable suite for Debian experimental packages. if [ “${DIST}” == “experimental” ]; then DIST=“unstable” fi fi

Optionally set a default distribution if none is used. Note that you can set

your own default (i.e. ${DIST:=“unstable”}).

: ${DIST:="$(lsb_release –short –codename)"}

Optionally set the architecture to the host architecture if none set. Note

that you can set your own default (i.e. ${ARCH:=“i386”}).

: ${ARCH:="$(dpkg –print-architecture)"}

NAME="$DIST" if [ -n “${ARCH}” ]; then NAME="$NAME-$ARCH" DEBOOTSTRAPOPTS=("–arch" “$ARCH” “${DEBOOTSTRAPOPTS[@]}") fi BASETGZ="/var/cache/pbuilder/$NAME-base.tgz” DISTRIBUTION="$DIST" BUILDRESULT="/var/cache/pbuilder/$NAME/result/" APTCACHE="/var/cache/pbuilder/$NAME/aptcache/" BUILDPLACE="/var/cache/pbuilder/build/"

if $(echo ${DEBIAN_SUITES[@]} | grep -q $DIST); then # Debian configuration MIRRORSITE=“http://$DEBIAN_MIRROR/debian/” COMPONENTS=“main contrib non-free” if $(echo “$STABLE_CODENAME stable” | grep -q $DIST); then EXTRAPACKAGES="$EXTRAPACKAGES debian-backports-keyring" OTHERMIRROR="$OTHERMIRROR | deb http://backports.debian.org/debian-backports $STABLE_BACKPORTS_SUITE $COMPONENTS" elif $(echo “$OLD_STABLE_CODENAME stable” | grep -q $DIST); then EXTRAPACKAGES="$EXTRAPACKAGES debian-backports-keyring" OTHERMIRROR="$OTHERMIRROR | deb http://backports.debian.org/debian-backports $OLD_STABLE_BACKPORTS_SUITE $COMPONENTS" elif $(echo “unstable” | grep -q $DIST); then DIST="$UNSTABLE_CODENAME" OTHERMIRROR="$OTHERMIRROR | deb http://ftp.fr.debian.org/debian/ experimental main" fi elif $(echo ${UBUNTU_SUITES[@]} | grep -q $DIST); then # Ubuntu configuration MIRRORSITE=“http://$UBUNTU_MIRROR/ubuntu/” COMPONENTS=“main restricted universe multiverse” v=0 n=0 for i in ${DEBOOTSTRAPOPTS[@]}; do if [ $v -ne 0 ]; then DEBOOTSTRAPOPTS[$n]="/usr/share/keyrings/ubuntu-archive-keyring.gpg" fi if [ $i == “–keyring” ]; then v=1; fi n=$((n+1)) done else echo “Unknown distribution: $DIST” exit 1 fi

Afin de faciliter son téléchargement, vous pouvez le télécharger ici

Cependant, avant de vous jeter à corps perdu à créer les pbuilder des différentes versions de Ubuntu, il y a un petit truc à faire si vous êtes sous debian.

Dans les paquets debootstrap de Debian et Ubuntu, Il s’avère que les fichiers /usr/share/debootstrap/scripts/gutsy sont légèrement différents (une ligne), mais ça suffit pour causer des soucis, surtout sous Ubuntu 11.04 “Natty”.

Donc sous Debian, à la ligne 72 du fichier /usr/share/debootstrap/gutsy, ajoutez la ligne suivante :

ln -nsf . “$TARGET/var/lib/dpkg/info/$ARCH”

Là, nous sommes enfin prets.

Avec ce beau .pbuilderrc, vous n’aurez qu’à taper la commande suivante pour créer un pbuilder Debian Squeeze en 64 bits :

$ DIST=squeeze ARCH=amd64 sudo pbuilder create

Ou un pbuilder Ubuntu Natty en 32 bits :

$ DIST=natty ARCH=i386 sudo pbuilder create

Mais là, vous vous demandez “Pourquoi nous a-t-il parlés de la variable CONCURRENCY_LEVEL ?”.

Voici la réponse.

La variable CONCURRENCY_LEVEL permet de lancer plusieurs processus pour une compilation, en d’autres termes, pour ceux qui connaissent make, ça correspond à l’option “-j”.

Pour compiler un paquet source avec 4 processus sous Debian Squeeze 64 bits voici comment faire :

$ CONCURRENCY_LEVEL=4 DIST=squeeze ARCH=amd64 sudo pbuilder build paquet.dsc

Pour compiler un paquet source avec 2 processus sous Ubuntu Natty 32 bits voici comment faire :

$ CONCURRENCY_LEVEL=2 DIST=natty ARCH=i386 sudo pbuilder build paquet.dsc

Voila, la machine de build est prête et fonctionnelle.

Mais sachant que j’aime bien avoir mes propres fonctions qui peuvent m’aider à automatiser certaines tâches, j’ai créé dans le dossier personnel de mon utilisateur non privilégié un dossier .scripts avec un fichier nommé pbuilder_utils dont voici le contenu :

function update_pbuilder() { nprocs=$(grep -cE “^processor” /proc/cpuinfo) dists=$@ for i in $dists; do CONCURRENCY_LEVEL=$nprocs DIST=$i ARCH=i386 sudo pbuilder update CONCURRENCY_LEVEL=$nprocs DIST=$i ARCH=amd64 sudo pbuilder update done } function create_pbuilder() { nprocs=$(grep -cE “^processor” /proc/cpuinfo) dists=$@ for i in $dists; do CONCURRENCY_LEVEL=$nprocs DIST=$i ARCH=i386 sudo pbuilder create CONCURRENCY_LEVEL=$nprocs DIST=$i ARCH=amd64 sudo pbuilder create done } function clean_pbuilder() { nprocs=$(grep -cE “^processor” /proc/cpuinfo) dists=$@ for i in $dists; do CONCURRENCY_LEVEL=$nprocs DIST=$i ARCH=i386 sudo pbuilder –clean CONCURRENCY_LEVEL=$nprocs DIST=$i ARCH=amd64 sudo pbuilder –clean done } function build_pbuilder() { nprocs=$(grep -cE “^processor” /proc/cpuinfo) dsc=$1 shift dists=$@ for i in $dists; do CONCURRENCY_LEVEL=$nprocs DIST=$i ARCH=i386 sudo pbuilder build $dsc CONCURRENCY_LEVEL=$nprocs DIST=$i ARCH=amd64 sudo pbuilder build $dsc done }

Dans le fichier .bashrc, j’ai ajouté la ligne source ~/.scripts/pbuilder_utils.

Vu comme ça, c’est un peu bourrin, mais voici les explications :

Voila, c’est à peu près tout.

Pour le pbuilderrc fourni ici, j’ai pris comme base celui fourni sur le wiki de ubuntu.com à l’adresse suivante : https://wiki.ubuntu.com/PbuilderHowto#Multiple%20pbuilders

Pour le reste, ben c’est de l’arrachage de cheveux, de la bidouille et de multiples essais infructueux.

Sur ce, bonne lecture.