SlideShare une entreprise Scribd logo
1  sur  14
A la découverte du système de
build redo
Thierry GAYET
http://www.nextinnovation.org

Bien que GNU/make soit devenu un standard, redo a été développé
comme une alternative devant combler les lacunes de l'outils initial.
Nous allons voir comment l'utiliser.

1. Introduction
Développé en scripts bash et python, « redo » est un concurrent de plus pour « gnu/make » basé
sur une conception de Daniel J. Bernstein. Une réécriture en langage C est en cours pour le
rendre encore plus performant.
L'idée de redo a été de réécrire le fonctionnement de make en seulement 250 lignes de script
shell. Une version light (partie minimal de redo) à même été réalisé en vérifiant les dépendances
et ce en seulement 150 lignes de code soit environ 3 kilo-octets..
Le nom « redo » vient du fait que dans la communauté, 75 version différentes de « make »
coexistent sous la même appellation et aussi pour faire la même chose. Cela rend donc l'outil plus
clair pour l'outil. Cela en fait donc un mini système de build avec gestion dé dépendance qqui peut
être inclus dans les projets eux même.
Il est distribué sous licence LGPLv2.
La version minimale étant quant à elle donné au domaine public.

2. Premier pas avec redo
La théorie derrière « redo » est presque magique: il peut faire tout ce que « make » peut faire.
Seule la mise en œuvre est beaucoup plus simple car la syntaxe est plus propre, et vous pouvez
faire encore plus souple choses sans recourir à des hacks immonde.
Loin des automatismes, des templates offertes soit par autotools, cMake ou autre, redo est
vraiment orienté comme un système minimal mains néanmoins fonctionnel.
Pour l'exemple, nous allons nous utiliser les code sources suivants.
Premièrement nous allons avoir besoin d'une fonction d'entrée main() qui sera définie dans le
fichier « main.c » :
#include <stdio.h>
#include "extension.h"
int main()
{
printf(module);
return 0;
}

Nous aurons également besoin d'un header « extension.h » qui définiera une déclaration externe
au main :
extern char *module;
Enfin, pour montrer un exemple concret de programmation modulaire, nous allons définir un second fichier
source « extension.c » :
char *module = "hello, world!n";

Les trois fichiers seront utilisés lors de la compilation.
Commençons par regarder la version de redo dont nous disposons :
$ redo --version
0.11

Tout d'abord, pour commencer, créons un fichier « default.o.do » qui définiera le comportement de
la cible par défaut pour l'étape de compilation :
redo-ifchange $2.c
gcc -MD -MF $2.d -c -o $3 $2.c
read DEPS <$2.d
redo-ifchange ${DEPS#*:}

Ensuite définissons le fichier « helloworld.do » qui définira comment créer la cible principale en
l’occurrence notre binaire « helloworld » . Il décrit en plus des dépendances, l'étape de l'édition de
lien :
DEPS="main.o extension.o"
redo-ifchange $DEPS
gcc -o $3 $DEPS

Le nom du fichier « helloworld » servira comme le nom du binaire à générer. Il faut donc ajuster le
nom du fichier en fonction ce qui est à construire.
Nous pouvons voir les dépendances du binaire via les deux fichiers « main.o » et « extension.o ».
La règle par défaut est apporté dans le fichier « default.o.do ».
A ce stage nous devons avoir dans les fichiers suivants :
$ ls -al
total 32
drwxrwxr-x 2 tgayet tgayet 4096 févr. 1 12:38 .
drwxrwxr-x 7 tgayet tgayet 4096 févr. 1 12:37 ..
-rw-rw-r-- 1 tgayet tgayet 119 févr. 1 12:17 clean.do
-rw-rw-r-- 1 tgayet tgayet 91 févr. 1 11:30 default.o.do
-rw-rw-r-- 1 tgayet tgayet 34 févr. 1 11:54 extension.c
-rw-rw-r-- 1 tgayet tgayet 21 févr. 1 12:29 extension.h
-rw-rw-r-- 1 tgayet tgayet 62 févr. 1 11:58 helloworld.do
-rw-rw-r-- 1 tgayet tgayet 91 févr. 1 11:55 main.c

L'exécution donnera le résultat suivant :
$ redo helloworld
redo helloworld
redo

main.o

main.c: In function ‘main’:
main.c:7:2: attention : le format n'est pas une chaîne littérale et pas d'argument de format [-Wformat-security]
redo

extension.o

Une fois le processus lancé, des fichiers de dépendance avec une extension .d apparaissent :
$ ls -al
total 60
drwxrwxr-x 2 tgayet tgayet 4096 févr. 1 12:41 .
drwxrwxr-x 7 tgayet tgayet 4096 févr. 1 12:37 ..
-rw-rw-r-- 1 tgayet tgayet 119 févr. 1 12:17 clean.do
-rw-rw-r-- 1 tgayet tgayet 91 févr. 1 11:30 default.o.do
-rw-rw-r-- 1 tgayet tgayet 34 févr. 1 11:54 extension.c
-rw-rw-r-- 1 tgayet tgayet 35 févr. 1 12:41 extension.d
-rw-rw-r-- 1 tgayet tgayet 21 févr. 1 12:29 extension.h
-rw-rw-r-- 1 tgayet tgayet 1184 févr. 1 12:41 extension.o
-rwxrwxr-x 1 tgayet tgayet 8453 févr. 1 12:41 helloworld
-rw-rw-r-- 1 tgayet tgayet 62 févr. 1 11:58 helloworld.do
-rw-rw-r-- 1 tgayet tgayet 91 févr. 1 11:55 main.c
-rw-rw-r-- 1 tgayet tgayet 693 févr. 1 12:41 main.d
-rw-rw-r-- 1 tgayet tgayet 1432 févr. 1 12:41 main.o

Nous pouvons consulter ces deux fichiers qui sont utilisés par redo lors de la gestion de
dépendances :
$ cat extension.d
extension.o.redo2.tmp: extension.c
$ cat main.d
main.o.redo2.tmp: main.c /usr/include/stdio.h /usr/include/features.h 
/usr/include/x86_64-linux-gnu/bits/predefs.h 
/usr/include/x86_64-linux-gnu/sys/cdefs.h 
/usr/include/x86_64-linux-gnu/bits/wordsize.h 
/usr/include/x86_64-linux-gnu/gnu/stubs.h 
/usr/include/x86_64-linux-gnu/gnu/stubs-64.h 
/usr/lib/gcc/x86_64-linux-gnu/4.6/include/stddef.h 
/usr/include/x86_64-linux-gnu/bits/types.h 
/usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/libio.h 
/usr/include/_G_config.h /usr/include/wchar.h 
/usr/lib/gcc/x86_64-linux-gnu/4.6/include/stdarg.h 
/usr/include/x86_64-linux-gnu/bits/stdio_lim.h 
/usr/include/x86_64-linux-gnu/bits/sys_errlist.h extension.h

La modification du timestamp sur le header « extension.h » pour simuler sa modification
régénérera ce qui a bougé :
$ touch extension.h
$ redo helloworld
redo helloworld
redo

main.o

main.c: In function ‘main’:
main.c:7:2: attention : le format n'est pas une chaîne littérale et pas d'argument de format [-Wformat-security]
En modifiant le timestamp du fichier source « extension.c » :
$ touch extension.c
$ redo helloworld
redo helloworld
redo

extension.o

Cela nous aura bien généré le binaire « helloworld » comme attendu :
$ ls -al helloworld
-rwxrwxr-x 1 tgayet tgayet 8453 févr. 1 12:45 helloworld
$ file helloworld
helloworld: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for
GNU/Linux 2.6.24, BuildID[sha1]=0xade40be9e76eddf06173a5286339890faa0a821e, not stripped

Cependant la cilble « helloworld » est appelé explicitement mais n'est pas associé à une cible par
défaut. L'appel direct à redo nous affichera donc le message suivant :
$ redo
redo no rule to make 'all'

Sans la définition de la cible par défaut que nous venons de créer, nous aurions eu le message
d'erreur suivant :
$ redo helloworld.do
redo helloworld.do: exists and not marked as generated; not redoing.

Nous pouvons remédier à cela en créant un fichier « all.do » qui servira de cilbe par défaut :
redo-ifchange helloworld
redo helloworld

Ce qui permettra désormais d'appeler redo directement qui à son tour redirigera vers la cible
helloworld :
$ redo
redo all
redo

helloworld

redo

main.o

main.c: In function ‘main’:
main.c:7:2: attention : le format n'est pas une chaîne littérale et pas d'argument de format [-Wformat-security]
redo
redo

extension.o
helloworld

Pour plus de commodités, nous aurons aussi besoin de définir un fichier « clean.do » de façon à
permettre le nettoyage de l'environement. Ce fichier contiendra :
rm -fR *.o
rm -fR *.d
rm -fR helloworld

Son exécution sera simple :
$ redo clean
redo clean

3. Les variables $1, $2 et $3
Redo utilise dans les fichiers .do des variables $1, $2 ou $3 qui nécessitent une clarification :
Nom de la variable

Description

$1

nom du fichier cible

$2

nom de base de la cible, sans son extension
$3

nom d'un fichier temporaire qui sera renommé le
fichier cible (seulement si le fichier .do ne renvoie
pas d'erreur)

Une remarque vient à l'usage de redo : pourquoi ne pas avoir nommé les variables telles que
$FILE, $EXT, et $OUT au lieu de de $1, $2 ou $3 ?
Cela semble tentant et facile, mais malheureusement cela est un inconvénient via la compatibilité
descendante en lien avec la conception de originale de redo effectué par djb.
En effet, es noms plus longs ne sont pas nécessairement mieux. Apprendre la signification des
trois numéros ne prend pas longtemps,Et n'oubliez pas que Makefiles et perl ont eu aussi
d'étranges noms de variables à un seul caractère pendant une longue période. Ce n'est pas du
tout évident que les enlever est une amélioration.
Exemple avec les makefile $@ ou $^ dans les makefiles.

4. Au sujet des flags de compilation et de link
Le fichier default.o.do, à la base des règles de redo peut disposer de plusieurs variantes comme
par exemple, en incluant la définissions des flags utilisés lors de la compilation du code C ou C++.
redo-ifchange $2.c
$CC $CPPFLAGS $CFLAGS -MD -MF $2.d -c -o $3 $2.c
read DEPS <$2.d
redo-ifchange ${DEPS#*:}

Attention que pour l'exemple précédent, gcc a été remplacer par une variable d’environnement
$CC ce qui permettra de fonctionner à la fois en compilation native, mais aussi en crosscompilation. Donc pour que cela fonctionne en compilation native, il faut au préalable exporter la
variable CC dans son environnement :
$ export CC=gcc

Quant aux variables CFLAGS ou CPPFLAGS, en bash, une variable non définie est vue comme
une chaînes vide, ce qui ne nous posera pas de problème à l'exécution.
Pour l'étape de l'édition de lien on pourra également modifier le fichier de la target « helloworld.do
du fichier qui définit l'édition de lien par :
$CC $LDFLAGS -o $3 $objs $libs $LDLIBS

La aussi, la définition de CC dans l'export nous sera utile pour l'édition de lien native car sinon,
nous n'invoquerons pas le bon LD.

4. Exemple d'autres cibles
Pour chaque cible, all, clean, documentation, install, test, etc..., un fichier avec l'extension « .do »
peut être ajouté au projet.
En voici quelques exemples pour illustration :

4.1 «documentation.do » pour la génération de documentation
deps=$(find -name '*.[ch]')
redo-ifchange $deps
if ! (which doxygen &>/dev/null); then
echo 1>&2 arrêt de la génération de la documentation ; merci d'installer doxygen
exit 0
fi
doxygen >doxygen.out

Sera exécuté via la commande « redo documentation» ou « make documentation» via le wrapper.

4.2 « ctag.do » pour l'indexation du code
deps=$(find -name '*.[ch]')
redo-ifchange $deps
if ! (which ctags &>/dev/null); then
echo 1>&2 arret de l'indexation ; merci d'installer ctags
exit 0
fi
ctags -f- --exclude="output" --exclude="html" -R

Sera exécuté via la commande « redo ctag » ou « make ctags» via le wrapper.

4.3 « install.do » pour l'installation des fichiers
#!/bin/bash
exec >&2
redo-ifchange all
INSTALL_DIR=${INSTALL_DIR:-output/generic}
mkdir -p $INSTALL_DIR
files_to_copy="
helloworld
"
cp -au $files_to_copy "$INSTALL_DIR"

Sera exécuté via la commande « redo install» ou « make install » via le wrapper.
A noter l'uasage de « exec >&2 » qui est permet de sécuriser l'usage de certain scripts en lien avec redo.

5. Makefile pour contrôler redo
Comme nous l'avons vu, tout se fait en invoquant le script « redo ». « redo all » lorsqu'il est sans
argument ou bien « redo clean » pour nettoyer l’environnement de développement, ou enfin « redo
helloworld » pour spécifier la génération d'une target.
Pour interconnecter les GNU/make avec redo, un petit makefile est fourni. Il sert juste de
passerelle entre les deux système :
all:
Makefile:
@
%: FORCE
+./redo $@
.PHONY: FORCE

Cela permetta d'invoqué les même cible passé à make pour redo :
$ make clean
redo clean
redo clean
$ make
redo all
redo all
redo

helloworld

redo

main.o

main.c: In function ‘main’:
main.c:7:2: attention : le format n'est pas une chaîne littérale et pas d'argument de format [-Wformat-security]
redo
redo

extension.o
helloworld

6. Paramètres utilisable avec redo
Redo possède un certain nombre de paramètres que l'on peu utiliser pour détailler les étapes
interne. En général, ils ne sont pas utile mais en cas de problème dans la chaîne de build, cela
peut s'avérer très utile :
Nom du paramètre

Description

-j n

Nombre de threads à
paraléliser la génération

--jobs=n
-d
--debug
-v
--verbose
-x
--xtrace
-k
--keep-going

lancer

pour

Affiche des infos de debug au niveau des
vérification de dépendance
Affiche toutes les informations lu dans les
fichiers de dépendances .d et les
fichiers .do
Affiche les commandes telle qu'elles sont
exécutées réellement
Continue aussi longtemps que possible
même si une cible échoue.

--shuffle

Rend l'ordre du build aléatoire pour
trouver des bugs de dépendance

--debug-locks

Affiche les messages sur les fichiers de
vérouillage (utile pour le débug de redo)

--debug-pids

Affiche le process id (aka PID) dans les
traces (utile pour le debug)

--version

Affiche la version courante du script redo
et sort

A partir de notre exemple précédent qui donnait le résultat suivant, nous allons voir que nous
pouvons avoir plus d'information utile :
$ redo clean && redo all
redo clean
redo all
redo

helloworld

redo

main.o

redo

extension.o
En mode verbose nous obtenons la sortie suivante avec des informations détaillées sur les étapes
intermédiaires à redo :
$ redo clean --verbose ; redo all --verbose
redo clean
* sh -ev clean.do clean clean clean.redo2.tmp
rm -fR *.o
rm -fR *.d
rm -fR helloworld
find -depth '(' -name '.do_built*' -o -name '*.did' ')' -exec rm -rf "{}" ;
redo clean (done)

redo all
* sh -ev all.do all all all.redo2.tmp
redo-ifchange helloworld
redo

helloworld

* sh -ev helloworld.do helloworld helloworld helloworld.redo2.tmp
DEPS="main.o extension.o"
redo-ifchange $DEPS
redo

main.o

* sh -ev default.o.do main.o main main.o.redo2.tmp
redo-ifchange $2.c
$CC $CPPFLAGS $CFLAGS -MD -MF $2.d -c -o $3 $2.c
read DEPS <$2.d
redo-ifchange ${DEPS#*:}
redo

main.o (done)

redo

extension.o

* sh -ev default.o.do extension.o extension extension.o.redo2.tmp
redo-ifchange $2.c
$CC $CPPFLAGS $CFLAGS -MD -MF $2.d -c -o $3 $2.c
read DEPS <$2.d
redo-ifchange ${DEPS#*:}
redo

extension.o (done)

LDLIBS="$LDLIBS -lpthread"
$CC -o $3 $DEPS $objs $LOADLIBES $LDLIBS
redo

helloworld (done)

redo helloworld
redo

helloworld

* sh -ev helloworld.do helloworld helloworld helloworld.redo2.tmp
DEPS="main.o extension.o"
redo-ifchange $DEPS
LDLIBS="$LDLIBS -lpthread"
$CC -o $3 $DEPS $objs $LOADLIBES $LDLIBS
redo

helloworld (done)

redo all (done)

Le paramètre debug montre davantage d'informations sur les dépendances ::
$ redo –debug clean && redo --debug all
redo clean
redo clean (done)
redo all
redo: ?helloworld
redo: -- DIRTY (missing)
redo

helloworld

redo:

?main.o

redo:

-- DIRTY (missing)

redo

main.o

redo:

?main.c

redo:

?main.c

redo:

-- CLEAN (checked)

redo:

?../../../../../../usr/include/stdio.h

redo:

?../../../../../../usr/include/features.h

redo:

?../../../../../../usr/include/bits/predefs.h

redo:

-- DIRTY (never built)

redo:

?../../../../../../usr/include/sys/cdefs.h

redo:

-- DIRTY (never built)

redo:

?../../../../../../usr/include/bits/wordsize.h

redo:

-- DIRTY (never built)
redo:

?../../../../../../usr/include/gnu/stubs.h

redo:

-- DIRTY (never built)

redo:

?../../../../../../usr/include/gnu/stubs-32.h

redo:

-- DIRTY (never built)

redo:

?../../../../x-tools/arm-rpi-linux-gnueabi/lib/gcc/arm-rpi-linux-gnueabi/4.6.3/include/stddef.h

redo:

?../../../../../../usr/include/bits/types.h

redo:

-- DIRTY (never built)

redo:

?../../../../../../usr/include/bits/typesizes.h

redo:

-- DIRTY (never built)

redo:

?../../../../../../usr/include/libio.h

redo:

?../../../../../../usr/include/_G_config.h

redo:

?../../../../../../usr/include/wchar.h

redo:

?../../../../x-tools/arm-rpi-linux-gnueabi/lib/gcc/arm-rpi-linux-gnueabi/4.6.3/include/stdarg.h

redo:

?../../../../../../usr/include/bits/stdio_lim.h

redo:

-- DIRTY (never built)

redo:

?../../../../../../usr/include/bits/sys_errlist.h

redo:

-- DIRTY (never built)

redo:

?../../../../../../usr/include/bits/stdio.h

redo:

-- DIRTY (never built)

redo:

?extension.h

redo

main.o (done)

redo:

?extension.o

redo:

-- DIRTY (missing)

redo

extension.o

redo:

?extension.c

redo:

?extension.c

redo:

-- CLEAN (checked)

redo

extension.o (done)

redo

helloworld (done)

redo

helloworld

redo:

?main.o

redo:

?../../../../../../usr/include/stdio.h

redo:

-- CLEAN (checked)

redo:

?../../../../../../usr/include/features.h

redo:

-- CLEAN (checked)

redo:

?../../../../../../usr/include/libio.h

redo:

-- CLEAN (checked)

redo:

?../../../../../../usr/include/_G_config.h

redo:

-- CLEAN (checked)
redo:

?../../../../../../usr/include/wchar.h

redo:

-- CLEAN (checked)

redo:

?default.o.do

redo:

?main.c

redo:

-- CLEAN (checked)

redo:

?extension.h

redo:

-- CLEAN (checked)

redo:

?../../../../x-tools/arm-rpi-linux-gnueabi/lib/gcc/arm-rpi-linux-gnueabi/4.6.3/include/stddef.h

redo:

-- CLEAN (checked)

redo:

?../../../../x-tools/arm-rpi-linux-gnueabi/lib/gcc/arm-rpi-linux-gnueabi/4.6.3/include/stdarg.h

redo:

-- CLEAN (checked)

redo:

?../../../../../../usr/include/bits/predefs.h

redo:

?../../../../../../usr/include/sys/cdefs.h

redo:

?../../../../../../usr/include/bits/wordsize.h

redo:

?../../../../../../usr/include/gnu/stubs.h

redo:

?../../../../../../usr/include/gnu/stubs-32.h

redo:

?../../../../../../usr/include/bits/types.h

redo:

?../../../../../../usr/include/bits/typesizes.h

redo:

?../../../../../../usr/include/bits/stdio_lim.h

redo:

?../../../../../../usr/include/bits/sys_errlist.h

redo:

?../../../../../../usr/include/bits/stdio.h

redo:

?extension.o

redo:

?default.o.do

redo:

-- CLEAN (checked)

redo:

?extension.c

redo:

-- CLEAN (checked)

redo

helloworld (done)

redo all (done)
Pour la sortie avec le paramètre xtrace, nous pouvons voir les commandes telle que redo les exécute :
$ redo clean --xtrace && redo all --xtrace
redo clean
* sh -ex clean.do clean clean clean.redo2.tmp
+ rm -fR '*.o'
+ rm -fR '*.d'
+ rm -fR helloworld
+ find -depth '(' -name '.do_built*' -o -name '*.did' ')' -exec rm -rf '{}' ';'
redo clean (done)

redo all
* sh -ex all.do all all all.redo2.tmp
+ redo-ifchange helloworld
redo

helloworld

* sh -ex helloworld.do helloworld helloworld helloworld.redo2.tmp
+ DEPS='main.o extension.o'
+ redo-ifchange main.o extension.o
redo

main.o

* sh -ex default.o.do main.o main main.o.redo2.tmp
+ redo-ifchange main.c
+ /home/tgayet/x-tools/arm-rpi-linux-gnueabi/bin/arm-rpi-linux-gnueabi-gcc --sysroot= -I/usr/include -I/include
-I/android/bionic -DNDEBUG --sysroot= -I/usr/include -I/include -I/android/bionic -O2 -MD -MF main.d -c -o
main.o.redo2.tmp main.c
+ read DEPS
+ redo-ifchange main.c /usr/include/stdio.h /usr/include/features.h /usr/include/bits/predefs.h
/usr/include/sys/cdefs.h /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h
/home/tgayet/x-tools/arm-rpi-linux-gnueabi/lib/gcc/arm-rpi-linux-gnueabi/4.6.3/include/stddef.h
/usr/include/bits/types.h /usr/include/bits/typesizes.h /usr/include/libio.h /usr/include/_G_config.h
/usr/include/wchar.h /home/tgayet/x-tools/arm-rpi-linux-gnueabi/lib/gcc/arm-rpi-linuxgnueabi/4.6.3/include/stdarg.h /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h
/usr/include/bits/stdio.h extension.h
redo

main.o (done)

redo

extension.o

* sh -ex default.o.do extension.o extension extension.o.redo2.tmp
+ redo-ifchange extension.c
+ /home/tgayet/x-tools/arm-rpi-linux-gnueabi/bin/arm-rpi-linux-gnueabi-gcc --sysroot= -I/usr/include -I/include
-I/android/bionic -DNDEBUG --sysroot= -I/usr/include -I/include -I/android/bionic -O2 -MD -MF extension.d -c
-o extension.o.redo2.tmp extension.c
+ read DEPS
+ redo-ifchange extension.c
redo

extension.o (done)

+ LDLIBS=' -lpthread'
+ /home/tgayet/x-tools/arm-rpi-linux-gnueabi/bin/arm-rpi-linux-gnueabi-gcc -o helloworld.redo2.tmp main.o
extension.o -lpthread
redo

helloworld (done)

+ redo helloworld
redo

helloworld

* sh -ex helloworld.do helloworld helloworld helloworld.redo2.tmp
+ DEPS='main.o extension.o'
+ redo-ifchange main.o extension.o
+ LDLIBS=' -lpthread'
+ /home/tgayet/x-tools/arm-rpi-linux-gnueabi/bin/arm-rpi-linux-gnueabi-gcc -o helloworld.redo2.tmp main.o
extension.o -lpthread
redo

helloworld (done)

redo all (done)

7. Scripts de pilotage
Tout comme pour l'exemple des makefiles, il est possible d'utiliser des scripts bash qui
amélioreront l'usage de redo. L'usage du script bash « build.sh » passera les arguments qui lui
sont passé au autres redo des autres répertoires s'il en possède.

8. Utilisation de redo en cross-compilation
Pour la cross-compilation, le plus simple étant de définir un script de configuration « setenv-armrpi.sh » qui devra être « sourcer » avant l'étape de génération.
Exemple avec la toolchain ARM pour la raspberry pi :
#
# Définition pour le support ARM pour la raspberry pi
#
export ARM_TOOLCHAIN_PATH="/home/tgayet/x-tools/arm-rpi-linux-gnueabi/bin"
export PREFIX="arm-rpi-linux-gnueabi"
# -----------------------------------------------------# Définit les outils de la chaines de cross-compilation
export CC="${ARM_TOOLCHAIN_PATH}/${PREFIX}-gcc"
export CPP="${ARM_TOOLCHAIN_PATH}/${PREFIX}-cpp"
export AR="${ARM_TOOLCHAIN_PATH}/${PREFIX}-ar"
# Met à jour les flags de compilation
export CFLAGS="${CFLAGS} --sysroot=${SYSROOT} -I${SYSROOT}/usr/include -I$
{ANDROID_PREFIX}/include -I${DEV_PREFIX}/android/bionic"
export CPPFLAGS="${CFLAGS}"
export LDFLAGS="${LDFLAGS} -L${SYSROOT}/usr/lib -L${ANDROID_PREFIX}/lib"
if test ${DEBUG}; then
# Pour le mode debug, inclu les symbols de débug:
export CFLAGS="$CFLAGS -g -Wall -Wfatal-errors -Werror -Wno-unused"
else
# For mode release, enlève les symbols de débug et optimise
export CFLAGS="$CFLAGS -O2"
export CPPFLAGS="$CPPFLAGS -DNDEBUG"
fi
# Met à jour le prompt pour renseigner de l'architecture courante
label="[CC ARM]"
export ORIG_PS1=${ORIG_PS1:-$PS1}
export PS1="%F{yellow}$label%f$ORIG_PS1"

Le résultat est concluant et a bien été généré pour l'architecture ARM :
$ source setenv-arm-rpi.sh
$ redo clean ; redo all
redo clean
redo all
redo

helloworld

redo

main.o

redo

extension.o

redo

helloworld

$ file *|grep ARM
extension.o:

ELF 32-bit LSB relocatable, ARM, version 1 (SYSV), not stripped

helloworld:
ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs),
for GNU/Linux 3.0.39, not stripped
main.o:

ELF 32-bit LSB relocatable, ARM, version 1 (SYSV), not stripped

9. Conclusion
Vous voilà éclairé sur l'usage de redo, que vous pourrez croiser dans certain packages open
source ou encore l'utiliser au sein de vos développement. Quoi qu'il en soit vous avez désormais
une corde de plus à votre arc.

10. Liens
•
•
•
•
•
•
•
•
•
•
•

https://github.com/apenwarr/redo
http://grosskurth.ca/papers/mmath-thesis.pdf
http://cr.yp.to/redo.html
http://cr.yp.to/redo/atomic.html
http://cr.yp.to/redo/honest-script.html
http://cr.yp.to/redo/honest-nonfile.html
http://cr.yp.to/redo/honest-crossdir.html
http://miller.emu.id.au/pmiller/books/rmch/
http://aegis.sourceforge.net/auug97.pdf
http://www.xs4all.nl/~evbergen/nonrecursive-make.html
http://cr.yp.to/data.html

Contenu connexe

Tendances

PostgreSQL sous linux
PostgreSQL sous linuxPostgreSQL sous linux
PostgreSQL sous linuxKhalid ALLILI
 
Configuration dns sous linux
Configuration  dns sous linuxConfiguration  dns sous linux
Configuration dns sous linuxBalamine Gassama
 
les Commandes linux/Unix (giants networks)
les Commandes linux/Unix (giants networks)les Commandes linux/Unix (giants networks)
les Commandes linux/Unix (giants networks)Souhaib El
 
Shell sans les coquilles
Shell sans les coquillesShell sans les coquilles
Shell sans les coquillesÉdouard Lopez
 
Formation Linux - Initiation
Formation Linux - InitiationFormation Linux - Initiation
Formation Linux - Initiationrobertpluss
 
lpi 101 notes de cours
lpi 101 notes de courslpi 101 notes de cours
lpi 101 notes de coursISIG
 
LINUX Mise en place d’une exploitation industrialisée – automatisée – sécuris...
LINUX Mise en place d’une exploitation industrialisée – automatisée – sécuris...LINUX Mise en place d’une exploitation industrialisée – automatisée – sécuris...
LINUX Mise en place d’une exploitation industrialisée – automatisée – sécuris...Jean-Antoine Moreau
 
Guide pratique openssl sous debian
Guide pratique openssl sous debianGuide pratique openssl sous debian
Guide pratique openssl sous debianyahyaf10
 
Cmd dos sous windows
Cmd dos sous windowsCmd dos sous windows
Cmd dos sous windowsSelman Dridi
 
Analyse d'un kernel (crash, core) dump
Analyse d'un kernel (crash, core) dumpAnalyse d'un kernel (crash, core) dump
Analyse d'un kernel (crash, core) dumpGaëtan Trellu
 

Tendances (20)

PostgreSQL sous linux
PostgreSQL sous linuxPostgreSQL sous linux
PostgreSQL sous linux
 
Configuration dns sous linux
Configuration  dns sous linuxConfiguration  dns sous linux
Configuration dns sous linux
 
les Commandes linux/Unix (giants networks)
les Commandes linux/Unix (giants networks)les Commandes linux/Unix (giants networks)
les Commandes linux/Unix (giants networks)
 
Tp n 5 linux
Tp n 5 linuxTp n 5 linux
Tp n 5 linux
 
s de base
s de bases de base
s de base
 
Shell sans les coquilles
Shell sans les coquillesShell sans les coquilles
Shell sans les coquilles
 
Formation Linux - Initiation
Formation Linux - InitiationFormation Linux - Initiation
Formation Linux - Initiation
 
lpi 101 notes de cours
lpi 101 notes de courslpi 101 notes de cours
lpi 101 notes de cours
 
LINUX Mise en place d’une exploitation industrialisée – automatisée – sécuris...
LINUX Mise en place d’une exploitation industrialisée – automatisée – sécuris...LINUX Mise en place d’une exploitation industrialisée – automatisée – sécuris...
LINUX Mise en place d’une exploitation industrialisée – automatisée – sécuris...
 
Configuration dns
Configuration dnsConfiguration dns
Configuration dns
 
2020 (1)
2020 (1)2020 (1)
2020 (1)
 
Hdfs
HdfsHdfs
Hdfs
 
Rapport tp openssl
Rapport  tp  opensslRapport  tp  openssl
Rapport tp openssl
 
Linux commandes
Linux commandesLinux commandes
Linux commandes
 
Guide pratique openssl sous debian
Guide pratique openssl sous debianGuide pratique openssl sous debian
Guide pratique openssl sous debian
 
Cmd dos sous windows
Cmd dos sous windowsCmd dos sous windows
Cmd dos sous windows
 
Tp n 4 linux
Tp n 4 linuxTp n 4 linux
Tp n 4 linux
 
Implémentation d'openvpn
Implémentation d'openvpnImplémentation d'openvpn
Implémentation d'openvpn
 
Analyse d'un kernel (crash, core) dump
Analyse d'un kernel (crash, core) dumpAnalyse d'un kernel (crash, core) dump
Analyse d'un kernel (crash, core) dump
 
Guide complet linux
Guide complet linuxGuide complet linux
Guide complet linux
 

En vedette

Quel est le_prix_de_la_beaute
Quel est le_prix_de_la_beauteQuel est le_prix_de_la_beaute
Quel est le_prix_de_la_beautecatavrio
 
2008.10.08 Gestion Des Flux Documentaires Avec Le Club Alliances Ibm
2008.10.08   Gestion Des Flux Documentaires Avec Le Club Alliances Ibm2008.10.08   Gestion Des Flux Documentaires Avec Le Club Alliances Ibm
2008.10.08 Gestion Des Flux Documentaires Avec Le Club Alliances IbmHubert SENANT
 
Module 1 - Formation des doctorants
Module 1 - Formation des doctorantsModule 1 - Formation des doctorants
Module 1 - Formation des doctorantsMagalie Le Gall
 
Sauvegarde des murs en pierres seches et du vignoble en terrasses valaisan
Sauvegarde des murs en pierres seches et du vignoble en terrasses valaisanSauvegarde des murs en pierres seches et du vignoble en terrasses valaisan
Sauvegarde des murs en pierres seches et du vignoble en terrasses valaisanregiosuisse
 
ACHAT APPARTEMENT FAMILIAL PARIS TROCADERO
ACHAT APPARTEMENT FAMILIAL PARIS TROCADEROACHAT APPARTEMENT FAMILIAL PARIS TROCADERO
ACHAT APPARTEMENT FAMILIAL PARIS TROCADEROMarc Foujols
 
Ma femme m_._
Ma femme m_._Ma femme m_._
Ma femme m_._catavrio
 
3 Blondes Enqueteuses
3 Blondes Enqueteuses3 Blondes Enqueteuses
3 Blondes Enqueteusescatavrio
 
Blended mobilestrategy
Blended mobilestrategyBlended mobilestrategy
Blended mobilestrategyLee Schlenker
 
A la découverte d'abus
A la découverte d'abusA la découverte d'abus
A la découverte d'abusThierry Gayet
 
Moteurs de recherche de l'information scientifique
Moteurs de recherche de l'information scientifiqueMoteurs de recherche de l'information scientifique
Moteurs de recherche de l'information scientifiqueJoanne Mercher
 
Développement Noyau Et Driver Sous Gnu Linux
Développement Noyau Et Driver Sous Gnu LinuxDéveloppement Noyau Et Driver Sous Gnu Linux
Développement Noyau Et Driver Sous Gnu LinuxThierry Gayet
 
2008 Bloc Quebecois Platform Intro
2008 Bloc Quebecois Platform Intro2008 Bloc Quebecois Platform Intro
2008 Bloc Quebecois Platform Introguest8e28f9
 
ContrôLeur AéRien Etienne FrançOis
ContrôLeur AéRien    Etienne FrançOisContrôLeur AéRien    Etienne FrançOis
ContrôLeur AéRien Etienne FrançOisgawronski
 
Concert Lenny Kravitz
Concert Lenny KravitzConcert Lenny Kravitz
Concert Lenny Kravitzschumabrice39
 
Vente maison à Lamorlaye
Vente maison à LamorlayeVente maison à Lamorlaye
Vente maison à LamorlayeMarc Foujols
 
Commerce équitable et MDD
Commerce équitable et MDDCommerce équitable et MDD
Commerce équitable et MDDsarah38
 
Maitencillo Pwpt
Maitencillo PwptMaitencillo Pwpt
Maitencillo Pwptfixmarie
 
Shopping mission impossible
Shopping mission impossibleShopping mission impossible
Shopping mission impossiblecatavrio
 

En vedette (20)

Quel est le_prix_de_la_beaute
Quel est le_prix_de_la_beauteQuel est le_prix_de_la_beaute
Quel est le_prix_de_la_beaute
 
2008.10.08 Gestion Des Flux Documentaires Avec Le Club Alliances Ibm
2008.10.08   Gestion Des Flux Documentaires Avec Le Club Alliances Ibm2008.10.08   Gestion Des Flux Documentaires Avec Le Club Alliances Ibm
2008.10.08 Gestion Des Flux Documentaires Avec Le Club Alliances Ibm
 
Module 1 - Formation des doctorants
Module 1 - Formation des doctorantsModule 1 - Formation des doctorants
Module 1 - Formation des doctorants
 
Sauvegarde des murs en pierres seches et du vignoble en terrasses valaisan
Sauvegarde des murs en pierres seches et du vignoble en terrasses valaisanSauvegarde des murs en pierres seches et du vignoble en terrasses valaisan
Sauvegarde des murs en pierres seches et du vignoble en terrasses valaisan
 
ACHAT APPARTEMENT FAMILIAL PARIS TROCADERO
ACHAT APPARTEMENT FAMILIAL PARIS TROCADEROACHAT APPARTEMENT FAMILIAL PARIS TROCADERO
ACHAT APPARTEMENT FAMILIAL PARIS TROCADERO
 
Ma femme m_._
Ma femme m_._Ma femme m_._
Ma femme m_._
 
3 Blondes Enqueteuses
3 Blondes Enqueteuses3 Blondes Enqueteuses
3 Blondes Enqueteuses
 
Bolivie
BolivieBolivie
Bolivie
 
Grupo 4 exploradores 18
Grupo 4 exploradores 18Grupo 4 exploradores 18
Grupo 4 exploradores 18
 
Blended mobilestrategy
Blended mobilestrategyBlended mobilestrategy
Blended mobilestrategy
 
A la découverte d'abus
A la découverte d'abusA la découverte d'abus
A la découverte d'abus
 
Moteurs de recherche de l'information scientifique
Moteurs de recherche de l'information scientifiqueMoteurs de recherche de l'information scientifique
Moteurs de recherche de l'information scientifique
 
Développement Noyau Et Driver Sous Gnu Linux
Développement Noyau Et Driver Sous Gnu LinuxDéveloppement Noyau Et Driver Sous Gnu Linux
Développement Noyau Et Driver Sous Gnu Linux
 
2008 Bloc Quebecois Platform Intro
2008 Bloc Quebecois Platform Intro2008 Bloc Quebecois Platform Intro
2008 Bloc Quebecois Platform Intro
 
ContrôLeur AéRien Etienne FrançOis
ContrôLeur AéRien    Etienne FrançOisContrôLeur AéRien    Etienne FrançOis
ContrôLeur AéRien Etienne FrançOis
 
Concert Lenny Kravitz
Concert Lenny KravitzConcert Lenny Kravitz
Concert Lenny Kravitz
 
Vente maison à Lamorlaye
Vente maison à LamorlayeVente maison à Lamorlaye
Vente maison à Lamorlaye
 
Commerce équitable et MDD
Commerce équitable et MDDCommerce équitable et MDD
Commerce équitable et MDD
 
Maitencillo Pwpt
Maitencillo PwptMaitencillo Pwpt
Maitencillo Pwpt
 
Shopping mission impossible
Shopping mission impossibleShopping mission impossible
Shopping mission impossible
 

Similaire à A la découverte de redo

Compilation noyau linux depuis les sources
Compilation noyau linux depuis les sourcesCompilation noyau linux depuis les sources
Compilation noyau linux depuis les sourcesThierry Gayet
 
Rapport systéme embarqué busybox
Rapport systéme embarqué busyboxRapport systéme embarqué busybox
Rapport systéme embarqué busyboxAyoub Rouzi
 
Docker, ça mange quoi au printemps
Docker, ça mange quoi au printempsDocker, ça mange quoi au printemps
Docker, ça mange quoi au printempsJulien Maitrehenry
 
Julien Maitrehenry - Docker, ça mange quoi au printemps
Julien Maitrehenry - Docker, ça mange quoi au printempsJulien Maitrehenry - Docker, ça mange quoi au printemps
Julien Maitrehenry - Docker, ça mange quoi au printempsWeb à Québec
 
Maintenance du système Linux
Maintenance du système LinuxMaintenance du système Linux
Maintenance du système LinuxEL AMRI El Hassan
 
Présentation CoreOS
Présentation CoreOSPrésentation CoreOS
Présentation CoreOSgcatt
 
PostgreSQL sous linux
PostgreSQL sous linuxPostgreSQL sous linux
PostgreSQL sous linuxKhalid ALLILI
 
Oxalide Workshop #4 - Docker, des tours dans le petit bassin
Oxalide Workshop #4 - Docker, des tours dans le petit bassinOxalide Workshop #4 - Docker, des tours dans le petit bassin
Oxalide Workshop #4 - Docker, des tours dans le petit bassinLudovic Piot
 
Oxalide Workshop #4 - Docker, des tours dans le petit bassin
Oxalide Workshop #4 - Docker, des tours dans le petit bassinOxalide Workshop #4 - Docker, des tours dans le petit bassin
Oxalide Workshop #4 - Docker, des tours dans le petit bassinOxalide
 
programmation_shell_2022 (1).pptx
programmation_shell_2022 (1).pptxprogrammation_shell_2022 (1).pptx
programmation_shell_2022 (1).pptxManalAg
 
Docker en Production (Docker Paris)
Docker en Production (Docker Paris)Docker en Production (Docker Paris)
Docker en Production (Docker Paris)Jérôme Petazzoni
 
Anatomie d'une des particularité de la libc
Anatomie d'une des particularité de la libcAnatomie d'une des particularité de la libc
Anatomie d'une des particularité de la libcThierry Gayet
 
optimadata.nl-Comment exécuter Postgres sur Docker partie 2.pdf
optimadata.nl-Comment exécuter Postgres sur Docker partie 2.pdfoptimadata.nl-Comment exécuter Postgres sur Docker partie 2.pdf
optimadata.nl-Comment exécuter Postgres sur Docker partie 2.pdfPascal Ponzoni
 
Mysql Apche PHP sous linux
Mysql Apche PHP sous linuxMysql Apche PHP sous linux
Mysql Apche PHP sous linuxKhalid ALLILI
 
Rappels Modularisation application C/C++
Rappels Modularisation application C/C++Rappels Modularisation application C/C++
Rappels Modularisation application C/C++Sylvain Leroy
 

Similaire à A la découverte de redo (20)

Snort implementation
Snort implementationSnort implementation
Snort implementation
 
Boot
BootBoot
Boot
 
Compilation noyau linux depuis les sources
Compilation noyau linux depuis les sourcesCompilation noyau linux depuis les sources
Compilation noyau linux depuis les sources
 
Rapport systéme embarqué busybox
Rapport systéme embarqué busyboxRapport systéme embarqué busybox
Rapport systéme embarqué busybox
 
Docker, ça mange quoi au printemps
Docker, ça mange quoi au printempsDocker, ça mange quoi au printemps
Docker, ça mange quoi au printemps
 
Julien Maitrehenry - Docker, ça mange quoi au printemps
Julien Maitrehenry - Docker, ça mange quoi au printempsJulien Maitrehenry - Docker, ça mange quoi au printemps
Julien Maitrehenry - Docker, ça mange quoi au printemps
 
Noyau
NoyauNoyau
Noyau
 
Maintenance du système Linux
Maintenance du système LinuxMaintenance du système Linux
Maintenance du système Linux
 
Présentation CoreOS
Présentation CoreOSPrésentation CoreOS
Présentation CoreOS
 
Bash bonnes pratiques
Bash bonnes pratiquesBash bonnes pratiques
Bash bonnes pratiques
 
PostgreSQL sous linux
PostgreSQL sous linuxPostgreSQL sous linux
PostgreSQL sous linux
 
Oxalide Workshop #4 - Docker, des tours dans le petit bassin
Oxalide Workshop #4 - Docker, des tours dans le petit bassinOxalide Workshop #4 - Docker, des tours dans le petit bassin
Oxalide Workshop #4 - Docker, des tours dans le petit bassin
 
Oxalide Workshop #4 - Docker, des tours dans le petit bassin
Oxalide Workshop #4 - Docker, des tours dans le petit bassinOxalide Workshop #4 - Docker, des tours dans le petit bassin
Oxalide Workshop #4 - Docker, des tours dans le petit bassin
 
Langage C
Langage CLangage C
Langage C
 
programmation_shell_2022 (1).pptx
programmation_shell_2022 (1).pptxprogrammation_shell_2022 (1).pptx
programmation_shell_2022 (1).pptx
 
Docker en Production (Docker Paris)
Docker en Production (Docker Paris)Docker en Production (Docker Paris)
Docker en Production (Docker Paris)
 
Anatomie d'une des particularité de la libc
Anatomie d'une des particularité de la libcAnatomie d'une des particularité de la libc
Anatomie d'une des particularité de la libc
 
optimadata.nl-Comment exécuter Postgres sur Docker partie 2.pdf
optimadata.nl-Comment exécuter Postgres sur Docker partie 2.pdfoptimadata.nl-Comment exécuter Postgres sur Docker partie 2.pdf
optimadata.nl-Comment exécuter Postgres sur Docker partie 2.pdf
 
Mysql Apche PHP sous linux
Mysql Apche PHP sous linuxMysql Apche PHP sous linux
Mysql Apche PHP sous linux
 
Rappels Modularisation application C/C++
Rappels Modularisation application C/C++Rappels Modularisation application C/C++
Rappels Modularisation application C/C++
 

A la découverte de redo

  • 1. A la découverte du système de build redo Thierry GAYET http://www.nextinnovation.org Bien que GNU/make soit devenu un standard, redo a été développé comme une alternative devant combler les lacunes de l'outils initial. Nous allons voir comment l'utiliser. 1. Introduction Développé en scripts bash et python, « redo » est un concurrent de plus pour « gnu/make » basé sur une conception de Daniel J. Bernstein. Une réécriture en langage C est en cours pour le rendre encore plus performant. L'idée de redo a été de réécrire le fonctionnement de make en seulement 250 lignes de script shell. Une version light (partie minimal de redo) à même été réalisé en vérifiant les dépendances et ce en seulement 150 lignes de code soit environ 3 kilo-octets.. Le nom « redo » vient du fait que dans la communauté, 75 version différentes de « make » coexistent sous la même appellation et aussi pour faire la même chose. Cela rend donc l'outil plus clair pour l'outil. Cela en fait donc un mini système de build avec gestion dé dépendance qqui peut être inclus dans les projets eux même. Il est distribué sous licence LGPLv2. La version minimale étant quant à elle donné au domaine public. 2. Premier pas avec redo La théorie derrière « redo » est presque magique: il peut faire tout ce que « make » peut faire. Seule la mise en œuvre est beaucoup plus simple car la syntaxe est plus propre, et vous pouvez faire encore plus souple choses sans recourir à des hacks immonde. Loin des automatismes, des templates offertes soit par autotools, cMake ou autre, redo est vraiment orienté comme un système minimal mains néanmoins fonctionnel. Pour l'exemple, nous allons nous utiliser les code sources suivants. Premièrement nous allons avoir besoin d'une fonction d'entrée main() qui sera définie dans le fichier « main.c » : #include <stdio.h> #include "extension.h" int main() { printf(module); return 0; } Nous aurons également besoin d'un header « extension.h » qui définiera une déclaration externe au main : extern char *module;
  • 2. Enfin, pour montrer un exemple concret de programmation modulaire, nous allons définir un second fichier source « extension.c » : char *module = "hello, world!n"; Les trois fichiers seront utilisés lors de la compilation. Commençons par regarder la version de redo dont nous disposons : $ redo --version 0.11 Tout d'abord, pour commencer, créons un fichier « default.o.do » qui définiera le comportement de la cible par défaut pour l'étape de compilation : redo-ifchange $2.c gcc -MD -MF $2.d -c -o $3 $2.c read DEPS <$2.d redo-ifchange ${DEPS#*:} Ensuite définissons le fichier « helloworld.do » qui définira comment créer la cible principale en l’occurrence notre binaire « helloworld » . Il décrit en plus des dépendances, l'étape de l'édition de lien : DEPS="main.o extension.o" redo-ifchange $DEPS gcc -o $3 $DEPS Le nom du fichier « helloworld » servira comme le nom du binaire à générer. Il faut donc ajuster le nom du fichier en fonction ce qui est à construire. Nous pouvons voir les dépendances du binaire via les deux fichiers « main.o » et « extension.o ». La règle par défaut est apporté dans le fichier « default.o.do ». A ce stage nous devons avoir dans les fichiers suivants : $ ls -al total 32 drwxrwxr-x 2 tgayet tgayet 4096 févr. 1 12:38 . drwxrwxr-x 7 tgayet tgayet 4096 févr. 1 12:37 .. -rw-rw-r-- 1 tgayet tgayet 119 févr. 1 12:17 clean.do -rw-rw-r-- 1 tgayet tgayet 91 févr. 1 11:30 default.o.do -rw-rw-r-- 1 tgayet tgayet 34 févr. 1 11:54 extension.c -rw-rw-r-- 1 tgayet tgayet 21 févr. 1 12:29 extension.h -rw-rw-r-- 1 tgayet tgayet 62 févr. 1 11:58 helloworld.do -rw-rw-r-- 1 tgayet tgayet 91 févr. 1 11:55 main.c L'exécution donnera le résultat suivant : $ redo helloworld redo helloworld redo main.o main.c: In function ‘main’: main.c:7:2: attention : le format n'est pas une chaîne littérale et pas d'argument de format [-Wformat-security] redo extension.o Une fois le processus lancé, des fichiers de dépendance avec une extension .d apparaissent : $ ls -al total 60 drwxrwxr-x 2 tgayet tgayet 4096 févr. 1 12:41 .
  • 3. drwxrwxr-x 7 tgayet tgayet 4096 févr. 1 12:37 .. -rw-rw-r-- 1 tgayet tgayet 119 févr. 1 12:17 clean.do -rw-rw-r-- 1 tgayet tgayet 91 févr. 1 11:30 default.o.do -rw-rw-r-- 1 tgayet tgayet 34 févr. 1 11:54 extension.c -rw-rw-r-- 1 tgayet tgayet 35 févr. 1 12:41 extension.d -rw-rw-r-- 1 tgayet tgayet 21 févr. 1 12:29 extension.h -rw-rw-r-- 1 tgayet tgayet 1184 févr. 1 12:41 extension.o -rwxrwxr-x 1 tgayet tgayet 8453 févr. 1 12:41 helloworld -rw-rw-r-- 1 tgayet tgayet 62 févr. 1 11:58 helloworld.do -rw-rw-r-- 1 tgayet tgayet 91 févr. 1 11:55 main.c -rw-rw-r-- 1 tgayet tgayet 693 févr. 1 12:41 main.d -rw-rw-r-- 1 tgayet tgayet 1432 févr. 1 12:41 main.o Nous pouvons consulter ces deux fichiers qui sont utilisés par redo lors de la gestion de dépendances : $ cat extension.d extension.o.redo2.tmp: extension.c $ cat main.d main.o.redo2.tmp: main.c /usr/include/stdio.h /usr/include/features.h /usr/include/x86_64-linux-gnu/bits/predefs.h /usr/include/x86_64-linux-gnu/sys/cdefs.h /usr/include/x86_64-linux-gnu/bits/wordsize.h /usr/include/x86_64-linux-gnu/gnu/stubs.h /usr/include/x86_64-linux-gnu/gnu/stubs-64.h /usr/lib/gcc/x86_64-linux-gnu/4.6/include/stddef.h /usr/include/x86_64-linux-gnu/bits/types.h /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h /usr/lib/gcc/x86_64-linux-gnu/4.6/include/stdarg.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h /usr/include/x86_64-linux-gnu/bits/sys_errlist.h extension.h La modification du timestamp sur le header « extension.h » pour simuler sa modification régénérera ce qui a bougé : $ touch extension.h $ redo helloworld redo helloworld redo main.o main.c: In function ‘main’: main.c:7:2: attention : le format n'est pas une chaîne littérale et pas d'argument de format [-Wformat-security] En modifiant le timestamp du fichier source « extension.c » : $ touch extension.c $ redo helloworld redo helloworld
  • 4. redo extension.o Cela nous aura bien généré le binaire « helloworld » comme attendu : $ ls -al helloworld -rwxrwxr-x 1 tgayet tgayet 8453 févr. 1 12:45 helloworld $ file helloworld helloworld: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0xade40be9e76eddf06173a5286339890faa0a821e, not stripped Cependant la cilble « helloworld » est appelé explicitement mais n'est pas associé à une cible par défaut. L'appel direct à redo nous affichera donc le message suivant : $ redo redo no rule to make 'all' Sans la définition de la cible par défaut que nous venons de créer, nous aurions eu le message d'erreur suivant : $ redo helloworld.do redo helloworld.do: exists and not marked as generated; not redoing. Nous pouvons remédier à cela en créant un fichier « all.do » qui servira de cilbe par défaut : redo-ifchange helloworld redo helloworld Ce qui permettra désormais d'appeler redo directement qui à son tour redirigera vers la cible helloworld : $ redo redo all redo helloworld redo main.o main.c: In function ‘main’: main.c:7:2: attention : le format n'est pas une chaîne littérale et pas d'argument de format [-Wformat-security] redo redo extension.o helloworld Pour plus de commodités, nous aurons aussi besoin de définir un fichier « clean.do » de façon à permettre le nettoyage de l'environement. Ce fichier contiendra : rm -fR *.o rm -fR *.d rm -fR helloworld Son exécution sera simple : $ redo clean redo clean 3. Les variables $1, $2 et $3 Redo utilise dans les fichiers .do des variables $1, $2 ou $3 qui nécessitent une clarification : Nom de la variable Description $1 nom du fichier cible $2 nom de base de la cible, sans son extension
  • 5. $3 nom d'un fichier temporaire qui sera renommé le fichier cible (seulement si le fichier .do ne renvoie pas d'erreur) Une remarque vient à l'usage de redo : pourquoi ne pas avoir nommé les variables telles que $FILE, $EXT, et $OUT au lieu de de $1, $2 ou $3 ? Cela semble tentant et facile, mais malheureusement cela est un inconvénient via la compatibilité descendante en lien avec la conception de originale de redo effectué par djb. En effet, es noms plus longs ne sont pas nécessairement mieux. Apprendre la signification des trois numéros ne prend pas longtemps,Et n'oubliez pas que Makefiles et perl ont eu aussi d'étranges noms de variables à un seul caractère pendant une longue période. Ce n'est pas du tout évident que les enlever est une amélioration. Exemple avec les makefile $@ ou $^ dans les makefiles. 4. Au sujet des flags de compilation et de link Le fichier default.o.do, à la base des règles de redo peut disposer de plusieurs variantes comme par exemple, en incluant la définissions des flags utilisés lors de la compilation du code C ou C++. redo-ifchange $2.c $CC $CPPFLAGS $CFLAGS -MD -MF $2.d -c -o $3 $2.c read DEPS <$2.d redo-ifchange ${DEPS#*:} Attention que pour l'exemple précédent, gcc a été remplacer par une variable d’environnement $CC ce qui permettra de fonctionner à la fois en compilation native, mais aussi en crosscompilation. Donc pour que cela fonctionne en compilation native, il faut au préalable exporter la variable CC dans son environnement : $ export CC=gcc Quant aux variables CFLAGS ou CPPFLAGS, en bash, une variable non définie est vue comme une chaînes vide, ce qui ne nous posera pas de problème à l'exécution. Pour l'étape de l'édition de lien on pourra également modifier le fichier de la target « helloworld.do du fichier qui définit l'édition de lien par : $CC $LDFLAGS -o $3 $objs $libs $LDLIBS La aussi, la définition de CC dans l'export nous sera utile pour l'édition de lien native car sinon, nous n'invoquerons pas le bon LD. 4. Exemple d'autres cibles Pour chaque cible, all, clean, documentation, install, test, etc..., un fichier avec l'extension « .do » peut être ajouté au projet. En voici quelques exemples pour illustration : 4.1 «documentation.do » pour la génération de documentation deps=$(find -name '*.[ch]') redo-ifchange $deps if ! (which doxygen &>/dev/null); then echo 1>&2 arrêt de la génération de la documentation ; merci d'installer doxygen exit 0 fi
  • 6. doxygen >doxygen.out Sera exécuté via la commande « redo documentation» ou « make documentation» via le wrapper. 4.2 « ctag.do » pour l'indexation du code deps=$(find -name '*.[ch]') redo-ifchange $deps if ! (which ctags &>/dev/null); then echo 1>&2 arret de l'indexation ; merci d'installer ctags exit 0 fi ctags -f- --exclude="output" --exclude="html" -R Sera exécuté via la commande « redo ctag » ou « make ctags» via le wrapper. 4.3 « install.do » pour l'installation des fichiers #!/bin/bash exec >&2 redo-ifchange all INSTALL_DIR=${INSTALL_DIR:-output/generic} mkdir -p $INSTALL_DIR files_to_copy=" helloworld " cp -au $files_to_copy "$INSTALL_DIR" Sera exécuté via la commande « redo install» ou « make install » via le wrapper. A noter l'uasage de « exec >&2 » qui est permet de sécuriser l'usage de certain scripts en lien avec redo. 5. Makefile pour contrôler redo Comme nous l'avons vu, tout se fait en invoquant le script « redo ». « redo all » lorsqu'il est sans argument ou bien « redo clean » pour nettoyer l’environnement de développement, ou enfin « redo helloworld » pour spécifier la génération d'une target. Pour interconnecter les GNU/make avec redo, un petit makefile est fourni. Il sert juste de passerelle entre les deux système : all: Makefile: @ %: FORCE +./redo $@ .PHONY: FORCE Cela permetta d'invoqué les même cible passé à make pour redo : $ make clean redo clean redo clean $ make redo all
  • 7. redo all redo helloworld redo main.o main.c: In function ‘main’: main.c:7:2: attention : le format n'est pas une chaîne littérale et pas d'argument de format [-Wformat-security] redo redo extension.o helloworld 6. Paramètres utilisable avec redo Redo possède un certain nombre de paramètres que l'on peu utiliser pour détailler les étapes interne. En général, ils ne sont pas utile mais en cas de problème dans la chaîne de build, cela peut s'avérer très utile : Nom du paramètre Description -j n Nombre de threads à paraléliser la génération --jobs=n -d --debug -v --verbose -x --xtrace -k --keep-going lancer pour Affiche des infos de debug au niveau des vérification de dépendance Affiche toutes les informations lu dans les fichiers de dépendances .d et les fichiers .do Affiche les commandes telle qu'elles sont exécutées réellement Continue aussi longtemps que possible même si une cible échoue. --shuffle Rend l'ordre du build aléatoire pour trouver des bugs de dépendance --debug-locks Affiche les messages sur les fichiers de vérouillage (utile pour le débug de redo) --debug-pids Affiche le process id (aka PID) dans les traces (utile pour le debug) --version Affiche la version courante du script redo et sort A partir de notre exemple précédent qui donnait le résultat suivant, nous allons voir que nous pouvons avoir plus d'information utile : $ redo clean && redo all redo clean redo all redo helloworld redo main.o redo extension.o
  • 8. En mode verbose nous obtenons la sortie suivante avec des informations détaillées sur les étapes intermédiaires à redo : $ redo clean --verbose ; redo all --verbose redo clean * sh -ev clean.do clean clean clean.redo2.tmp rm -fR *.o rm -fR *.d rm -fR helloworld find -depth '(' -name '.do_built*' -o -name '*.did' ')' -exec rm -rf "{}" ; redo clean (done) redo all * sh -ev all.do all all all.redo2.tmp redo-ifchange helloworld redo helloworld * sh -ev helloworld.do helloworld helloworld helloworld.redo2.tmp DEPS="main.o extension.o" redo-ifchange $DEPS redo main.o * sh -ev default.o.do main.o main main.o.redo2.tmp redo-ifchange $2.c $CC $CPPFLAGS $CFLAGS -MD -MF $2.d -c -o $3 $2.c read DEPS <$2.d redo-ifchange ${DEPS#*:} redo main.o (done) redo extension.o * sh -ev default.o.do extension.o extension extension.o.redo2.tmp redo-ifchange $2.c $CC $CPPFLAGS $CFLAGS -MD -MF $2.d -c -o $3 $2.c read DEPS <$2.d
  • 9. redo-ifchange ${DEPS#*:} redo extension.o (done) LDLIBS="$LDLIBS -lpthread" $CC -o $3 $DEPS $objs $LOADLIBES $LDLIBS redo helloworld (done) redo helloworld redo helloworld * sh -ev helloworld.do helloworld helloworld helloworld.redo2.tmp DEPS="main.o extension.o" redo-ifchange $DEPS LDLIBS="$LDLIBS -lpthread" $CC -o $3 $DEPS $objs $LOADLIBES $LDLIBS redo helloworld (done) redo all (done) Le paramètre debug montre davantage d'informations sur les dépendances :: $ redo –debug clean && redo --debug all redo clean redo clean (done) redo all redo: ?helloworld redo: -- DIRTY (missing) redo helloworld redo: ?main.o redo: -- DIRTY (missing) redo main.o redo: ?main.c redo: ?main.c redo: -- CLEAN (checked) redo: ?../../../../../../usr/include/stdio.h redo: ?../../../../../../usr/include/features.h redo: ?../../../../../../usr/include/bits/predefs.h redo: -- DIRTY (never built) redo: ?../../../../../../usr/include/sys/cdefs.h redo: -- DIRTY (never built) redo: ?../../../../../../usr/include/bits/wordsize.h redo: -- DIRTY (never built)
  • 10. redo: ?../../../../../../usr/include/gnu/stubs.h redo: -- DIRTY (never built) redo: ?../../../../../../usr/include/gnu/stubs-32.h redo: -- DIRTY (never built) redo: ?../../../../x-tools/arm-rpi-linux-gnueabi/lib/gcc/arm-rpi-linux-gnueabi/4.6.3/include/stddef.h redo: ?../../../../../../usr/include/bits/types.h redo: -- DIRTY (never built) redo: ?../../../../../../usr/include/bits/typesizes.h redo: -- DIRTY (never built) redo: ?../../../../../../usr/include/libio.h redo: ?../../../../../../usr/include/_G_config.h redo: ?../../../../../../usr/include/wchar.h redo: ?../../../../x-tools/arm-rpi-linux-gnueabi/lib/gcc/arm-rpi-linux-gnueabi/4.6.3/include/stdarg.h redo: ?../../../../../../usr/include/bits/stdio_lim.h redo: -- DIRTY (never built) redo: ?../../../../../../usr/include/bits/sys_errlist.h redo: -- DIRTY (never built) redo: ?../../../../../../usr/include/bits/stdio.h redo: -- DIRTY (never built) redo: ?extension.h redo main.o (done) redo: ?extension.o redo: -- DIRTY (missing) redo extension.o redo: ?extension.c redo: ?extension.c redo: -- CLEAN (checked) redo extension.o (done) redo helloworld (done) redo helloworld redo: ?main.o redo: ?../../../../../../usr/include/stdio.h redo: -- CLEAN (checked) redo: ?../../../../../../usr/include/features.h redo: -- CLEAN (checked) redo: ?../../../../../../usr/include/libio.h redo: -- CLEAN (checked) redo: ?../../../../../../usr/include/_G_config.h redo: -- CLEAN (checked)
  • 11. redo: ?../../../../../../usr/include/wchar.h redo: -- CLEAN (checked) redo: ?default.o.do redo: ?main.c redo: -- CLEAN (checked) redo: ?extension.h redo: -- CLEAN (checked) redo: ?../../../../x-tools/arm-rpi-linux-gnueabi/lib/gcc/arm-rpi-linux-gnueabi/4.6.3/include/stddef.h redo: -- CLEAN (checked) redo: ?../../../../x-tools/arm-rpi-linux-gnueabi/lib/gcc/arm-rpi-linux-gnueabi/4.6.3/include/stdarg.h redo: -- CLEAN (checked) redo: ?../../../../../../usr/include/bits/predefs.h redo: ?../../../../../../usr/include/sys/cdefs.h redo: ?../../../../../../usr/include/bits/wordsize.h redo: ?../../../../../../usr/include/gnu/stubs.h redo: ?../../../../../../usr/include/gnu/stubs-32.h redo: ?../../../../../../usr/include/bits/types.h redo: ?../../../../../../usr/include/bits/typesizes.h redo: ?../../../../../../usr/include/bits/stdio_lim.h redo: ?../../../../../../usr/include/bits/sys_errlist.h redo: ?../../../../../../usr/include/bits/stdio.h redo: ?extension.o redo: ?default.o.do redo: -- CLEAN (checked) redo: ?extension.c redo: -- CLEAN (checked) redo helloworld (done) redo all (done) Pour la sortie avec le paramètre xtrace, nous pouvons voir les commandes telle que redo les exécute : $ redo clean --xtrace && redo all --xtrace redo clean * sh -ex clean.do clean clean clean.redo2.tmp + rm -fR '*.o' + rm -fR '*.d' + rm -fR helloworld + find -depth '(' -name '.do_built*' -o -name '*.did' ')' -exec rm -rf '{}' ';' redo clean (done) redo all
  • 12. * sh -ex all.do all all all.redo2.tmp + redo-ifchange helloworld redo helloworld * sh -ex helloworld.do helloworld helloworld helloworld.redo2.tmp + DEPS='main.o extension.o' + redo-ifchange main.o extension.o redo main.o * sh -ex default.o.do main.o main main.o.redo2.tmp + redo-ifchange main.c + /home/tgayet/x-tools/arm-rpi-linux-gnueabi/bin/arm-rpi-linux-gnueabi-gcc --sysroot= -I/usr/include -I/include -I/android/bionic -DNDEBUG --sysroot= -I/usr/include -I/include -I/android/bionic -O2 -MD -MF main.d -c -o main.o.redo2.tmp main.c + read DEPS + redo-ifchange main.c /usr/include/stdio.h /usr/include/features.h /usr/include/bits/predefs.h /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h /home/tgayet/x-tools/arm-rpi-linux-gnueabi/lib/gcc/arm-rpi-linux-gnueabi/4.6.3/include/stddef.h /usr/include/bits/types.h /usr/include/bits/typesizes.h /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h /home/tgayet/x-tools/arm-rpi-linux-gnueabi/lib/gcc/arm-rpi-linuxgnueabi/4.6.3/include/stdarg.h /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h /usr/include/bits/stdio.h extension.h redo main.o (done) redo extension.o * sh -ex default.o.do extension.o extension extension.o.redo2.tmp + redo-ifchange extension.c + /home/tgayet/x-tools/arm-rpi-linux-gnueabi/bin/arm-rpi-linux-gnueabi-gcc --sysroot= -I/usr/include -I/include -I/android/bionic -DNDEBUG --sysroot= -I/usr/include -I/include -I/android/bionic -O2 -MD -MF extension.d -c -o extension.o.redo2.tmp extension.c + read DEPS + redo-ifchange extension.c redo extension.o (done) + LDLIBS=' -lpthread' + /home/tgayet/x-tools/arm-rpi-linux-gnueabi/bin/arm-rpi-linux-gnueabi-gcc -o helloworld.redo2.tmp main.o extension.o -lpthread redo helloworld (done) + redo helloworld redo helloworld * sh -ex helloworld.do helloworld helloworld helloworld.redo2.tmp + DEPS='main.o extension.o'
  • 13. + redo-ifchange main.o extension.o + LDLIBS=' -lpthread' + /home/tgayet/x-tools/arm-rpi-linux-gnueabi/bin/arm-rpi-linux-gnueabi-gcc -o helloworld.redo2.tmp main.o extension.o -lpthread redo helloworld (done) redo all (done) 7. Scripts de pilotage Tout comme pour l'exemple des makefiles, il est possible d'utiliser des scripts bash qui amélioreront l'usage de redo. L'usage du script bash « build.sh » passera les arguments qui lui sont passé au autres redo des autres répertoires s'il en possède. 8. Utilisation de redo en cross-compilation Pour la cross-compilation, le plus simple étant de définir un script de configuration « setenv-armrpi.sh » qui devra être « sourcer » avant l'étape de génération. Exemple avec la toolchain ARM pour la raspberry pi : # # Définition pour le support ARM pour la raspberry pi # export ARM_TOOLCHAIN_PATH="/home/tgayet/x-tools/arm-rpi-linux-gnueabi/bin" export PREFIX="arm-rpi-linux-gnueabi" # -----------------------------------------------------# Définit les outils de la chaines de cross-compilation export CC="${ARM_TOOLCHAIN_PATH}/${PREFIX}-gcc" export CPP="${ARM_TOOLCHAIN_PATH}/${PREFIX}-cpp" export AR="${ARM_TOOLCHAIN_PATH}/${PREFIX}-ar" # Met à jour les flags de compilation export CFLAGS="${CFLAGS} --sysroot=${SYSROOT} -I${SYSROOT}/usr/include -I$ {ANDROID_PREFIX}/include -I${DEV_PREFIX}/android/bionic" export CPPFLAGS="${CFLAGS}" export LDFLAGS="${LDFLAGS} -L${SYSROOT}/usr/lib -L${ANDROID_PREFIX}/lib" if test ${DEBUG}; then # Pour le mode debug, inclu les symbols de débug: export CFLAGS="$CFLAGS -g -Wall -Wfatal-errors -Werror -Wno-unused" else # For mode release, enlève les symbols de débug et optimise export CFLAGS="$CFLAGS -O2" export CPPFLAGS="$CPPFLAGS -DNDEBUG" fi # Met à jour le prompt pour renseigner de l'architecture courante label="[CC ARM]" export ORIG_PS1=${ORIG_PS1:-$PS1} export PS1="%F{yellow}$label%f$ORIG_PS1" Le résultat est concluant et a bien été généré pour l'architecture ARM : $ source setenv-arm-rpi.sh $ redo clean ; redo all redo clean
  • 14. redo all redo helloworld redo main.o redo extension.o redo helloworld $ file *|grep ARM extension.o: ELF 32-bit LSB relocatable, ARM, version 1 (SYSV), not stripped helloworld: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 3.0.39, not stripped main.o: ELF 32-bit LSB relocatable, ARM, version 1 (SYSV), not stripped 9. Conclusion Vous voilà éclairé sur l'usage de redo, que vous pourrez croiser dans certain packages open source ou encore l'utiliser au sein de vos développement. Quoi qu'il en soit vous avez désormais une corde de plus à votre arc. 10. Liens • • • • • • • • • • • https://github.com/apenwarr/redo http://grosskurth.ca/papers/mmath-thesis.pdf http://cr.yp.to/redo.html http://cr.yp.to/redo/atomic.html http://cr.yp.to/redo/honest-script.html http://cr.yp.to/redo/honest-nonfile.html http://cr.yp.to/redo/honest-crossdir.html http://miller.emu.id.au/pmiller/books/rmch/ http://aegis.sourceforge.net/auug97.pdf http://www.xs4all.nl/~evbergen/nonrecursive-make.html http://cr.yp.to/data.html