ºÝºÝߣ

ºÝºÝߣShare a Scribd company logo
SISTEMI DI
   BUILD
ALTERNATIVI
SISTEMI DI BUILD?
MA PRIMA...
 Vediamo come funziona il classico ambiente
.cniue
 /ofgr
mk
 ae
mk isal
 ae ntl
.
├─at
 ─ n
│ ├─mi.
   ─ anc
│ └─Mkfl
   ─ aeie
├─be
 ─ e
│ ├─Mkfl
   ─ aeie
│ ├─prec
   ─ as.
│ └─preh
   ─ as.
└─Mkfl
 ─ aeie
/Makefile
MDLS=atbe
 OUE   n e
al
 l:
     frdri $MDLS;d 
      o i n (OUE) o
          (d$dr $MK}al;
           c $i; {AE l)
     dn
      oe



              /ant/Makefile
al mi.
 l: ano
mi.:mi. ./e/as.
 ano anc .bepreh
     $C)-./e - mi.
      (C I.be c anc
/bee/Makefile
OJ=./n/anopreo
 B   .atmi. as.
al po
 l: rg
po:$OJ
 rg (B)
     $C)- $ $OJ
      (C o @ (B)
preo precpreh
 as.: as. as.
     $C)- prec
      (C c as.
...e se generassimo parse.{c,h} da una grammatica
                      yacc?
 precpreh prey
  as. as.: as.
      $YC)- prey
       (AC d as.
      m ytbcprec
       v .a. as.
      m ytbhpreh
       v .a. as.
SOLUZIONE 1
Riordinare (buildare bee prima di ant)
ma l'ordine viene ignorato da make -j
SOLUZIONE 2
                      Ripetere
 MDLS=atbe
  OUE   n e
 al
  l:
      frdri $MDLS;d 
       o i n (OUE) o
           (d$dr $MK}al;
            c $i; {AE l)
      dn
       oe
      frdri $MDLS;d 
       o i n (OUE) o
           (d$dr $MK}al;
            c $i; {AE l)
      dn
       oe

             tempo di build raddoppiato!
  ...e non è detto che basti! (sono necessarie tante
ripetizioni quanti gli archi che attraversano i moduli
                     del progetto)
SOLUZIONE 3
       Ribuildare sempre e comunque
.HN:./e/as.
 POY .bepreh
./e/as.:
 .bepreh
    c ./e;
     d .be
    mk cen 
     ae la;
    mk al
     ae l

...ma non siamo ancora compatibili con make -j
SOLUZIONE 4
                Prevenzione
                   ma...




Miller, P.A. (1998), Recursive Make Considered
 Harmful, AUUGN Journal of AUUG Inc., 19(1)
Sistemi di Build Alternativi
Sistemi di Build Alternativi
TUP
Un sistema di build che non è a conoscenza del
     completo grafo sarà quindi più lento
Questa era la situazione con make
Tup invece, partendo da un nodo, riesce a ricavare il
            sottografo parziale minimo
Dovendo esaminare tutte le dipendenze: O(n)
O(log^2(n))
Scalabilità
Correttezza
Usabilità
SCALABILITÀ
I progetti crescono gradualmente, e le operazioni più
 comuni coinvolgono il rebuil dopo poche modifiche
                contenute su pochi file
CORRETTEZZA
Evita di costringere lo sviluppatore ad eseguire un
mk cen
 ae la

 nel caso in cui rimangano vecchi target nel tree,
 moduli esterni potrebbero iniziare a dipendervi,
nascondendo il problema fino a quando il file non
          verrà cancellato manualmente
±«³§´¡µþ±õ³¢±õ°ÕÀ
     Evitare l'impatto sulle performance con un
  c fo mk
   d o; ae

rischia di avere effetti diversi sul risultato rispetto ad
                      un semplice
  mk
   ae

 e costringe lo sviluppatore a memorizzare queste
                      differenze
IL BOUND O(N) DI MAKE E SIMILI
  Questi sistemi di build, percorrono l'albero delle
dipendenze, verificando se sia necessario aggiornarli
 uno per uno Ma per fare questa decisione, occorre
      analizzare tutte le dipendenze a ritroso
IL BOUND O(LOG^2(N)) DI TUP
   Sistemi di build come Tup, preferiscono invece
tenere memorizzato uno stato del grafo completo su
              disco (un database SQLite).
 Nel grafo, Tup memorizza anche i comandi usati per
            generare i file, questo serve a:
  Tenere traccia della generazione multipla di file
  Rieseguire i comandi, quando un
  argomento/opzione di questi viene cambiata
  Cancellare i file generati, quando il comando non è
  più richiesto
Da questo, Tup poi ricava la lista dei cambiamenti in
 tempo O(log(n)) (essendo i nodi indicizzati nel db)
  A questo punto, ricavando le dipendenze si può
ottenere il grafo parziale che rappresenta i passi che
              verranno svolti nella build.
    Nel caso di un progetto tipico, questo viene
     strutturato come un albero sul filesystem,
 permettendoci quindi di ottenere un tempo atteso
come O(log(n)), da qui O(log^2(n)) per l'intera build.
        Build System Rules and Algorithms
REDO
      Questo build sytem ha un approccio diverso:
anch'esso punta ad avere un completo grafo di tutte
     le dipendenze, ma queste vengono specificate
all'interno di diversi file e verranno letti da processi di
             redo chiamati ricorsivamente

Un primo prototipo di redo è stato implementato in
 sole 250 righe Bash! (Mentre l'implementazione di
   riferimento sono meno di 2000 righe Python)
Per ottenere un binario chiamato myprog, da due
 sorgenti "a.c" e "b.c", sono necessari solo 2 file:

dfutod
 eal..
rd-fhne$.
 eoicag 2c
gc-D-F$. - - $ $.
 c M M 2d c o 3 2c
ra DP <2d
 ed ES $.
rd-fhne$DP#:
 eoicag {ES*}



mpo.o
 yrgd
DP=aobo
 ES". ."
rd-fhne$ES
 eoicag DP
gc- $ $ES
 c o 3 DP
I file sono dei normali script shell (ma possono
 essere sostituiti da qualunque altro linguaggio di
 scripting) e le dipendenze sono specificate con le
         chiamate al comando redo-ifchange
redo-ifchange indica di rieseguire lo script corrente,
  solo nel caso in cui le dipendenze (fornite come
             argomento) siano cambiate
Per verificare se queste dipendenze sono cambiate,
    anche redo usa lo stesso approccio di tup: un
                    database sqlite
    Se queste non sono cambiate, redo deve solo
 esaminare il db, senza dover rileggere ed eseguire i
                    relativi file .do
Le dipendenze, come in default.o.do possono essere
  calcolate facilmente usando un altro programma
  esterno, come lo stesso gcc usato per compilare,
     senza bisogno di alcuna sintassi particolare
Redo abbraccia la filosofia Unix di piccoli programmi
componibili grazie a pipeline e ridirezioni dell'output,
e di default aggiunge tutto l'output nel file generato,
   questo permette, con queste 2 semplici righe:
  rd-fhneflls
   eoicag ieit
  ge ^r/flls
   rp sc ieit



 di rigenererare una lista intermedia di dipendenze
che potrà essere quindi riusata dal resto della build.
Redo disincentiva l'uso di variabili globali, e
spingendo l'unica vera informazione che dev'essere
accessibile a tutte le parti della build (ovvero il grafo
delle dipendenze) in un unico db, è possibile ripetere
 una parte della build che aveva dato errore senza
    problemi, essendo ogni passaggio modulare.
Questo viene anche invogliato dal formato stesso
    dell'output, ecco un ipotetico esempio:
$rd tc
  eo /
rd tc
 eo /
rd
 eo  tcc
      /.
rd
 eo    tccc
        /..
rd
 eo      tcccb
         /...
rd
 eo       tcccbb
           /....
L'indentazione caratterizza il livello della ricorsione a
cui è arrivato redo, ma copiando e incollando l'ultima
    riga per rieseguirla verbosamente, ci possiamo
 rendere conto che ognuno di questi è un comando
                         valido:
  $rd tcccbb-
    eo /.... x
  rd tcccbb
   eo /....
  *s -xdfutbd cccb. cccbbrd2tp
    h e eal..o ... b .....eo.m
  +rd-fhnecccbba
    eoicag .....
  +eh at-
    co -ob
  +ctcccbba
    a .....
  +.sep11
    /le .
  rd tcccbb(oe
   eo /.... dn)
Un altro vantaggio è quindi l'evidente assenza di flag
ed opzioni ripetute centinaia di volte nell'output delle
  tipiche compilazioni con make, output reso ancor
   meno leggibile nel caso in cui la compilazione sia
 avvenuta in parallelo, nascondendo quindi l'ordine
            logico che sottende alla build

                   Redo on Github
Altri sistemi di build o risorse interessanti:

Ninja: un build system veloce e di "basso
livello"
Fabricate: trova le dipendenze
automaticamente
Shake: un altro strumento che si concentra
sulla gestione accurata delle dipendenze e
rebuild minimi
Boilermake: un boilerplate makefile che segue
un approccio non ricorsivo
Altri sistemi di build o risorse interessanti:

Il punto di vista di Bruce Eckel nel 2004 su Ant,
le alternative disponibili all'epoca e le difficoltà
nel loro sviluppo
Un linguaggio puramente dichiarativo come
XML non è una buona scelta per un sistema di
build: come James Duncan Davidson arrivò a
sceglierlo nella creazione di Ant

More Related Content

Sistemi di Build Alternativi

  • 1. SISTEMI DI BUILD ALTERNATIVI
  • 3. MA PRIMA... Vediamo come funziona il classico ambiente .cniue /ofgr mk ae mk isal ae ntl
  • 4. . ├─at ─ n │ ├─mi. ─ anc │ └─Mkfl ─ aeie ├─be ─ e │ ├─Mkfl ─ aeie │ ├─prec ─ as. │ └─preh ─ as. └─Mkfl ─ aeie
  • 5. /Makefile MDLS=atbe OUE n e al l: frdri $MDLS;d o i n (OUE) o (d$dr $MK}al; c $i; {AE l) dn oe /ant/Makefile al mi. l: ano mi.:mi. ./e/as. ano anc .bepreh $C)-./e - mi. (C I.be c anc
  • 6. /bee/Makefile OJ=./n/anopreo B .atmi. as. al po l: rg po:$OJ rg (B) $C)- $ $OJ (C o @ (B) preo precpreh as.: as. as. $C)- prec (C c as.
  • 7. ...e se generassimo parse.{c,h} da una grammatica yacc? precpreh prey as. as.: as. $YC)- prey (AC d as. m ytbcprec v .a. as. m ytbhpreh v .a. as.
  • 8. SOLUZIONE 1 Riordinare (buildare bee prima di ant) ma l'ordine viene ignorato da make -j
  • 9. SOLUZIONE 2 Ripetere MDLS=atbe OUE n e al l: frdri $MDLS;d o i n (OUE) o (d$dr $MK}al; c $i; {AE l) dn oe frdri $MDLS;d o i n (OUE) o (d$dr $MK}al; c $i; {AE l) dn oe tempo di build raddoppiato! ...e non è detto che basti! (sono necessarie tante ripetizioni quanti gli archi che attraversano i moduli del progetto)
  • 10. SOLUZIONE 3 Ribuildare sempre e comunque .HN:./e/as. POY .bepreh ./e/as.: .bepreh c ./e; d .be mk cen ae la; mk al ae l ...ma non siamo ancora compatibili con make -j
  • 11. SOLUZIONE 4 Prevenzione ma... Miller, P.A. (1998), Recursive Make Considered Harmful, AUUGN Journal of AUUG Inc., 19(1)
  • 14. TUP Un sistema di build che non è a conoscenza del completo grafo sarà quindi più lento
  • 15. Questa era la situazione con make
  • 16. Tup invece, partendo da un nodo, riesce a ricavare il sottografo parziale minimo
  • 17. Dovendo esaminare tutte le dipendenze: O(n) O(log^2(n))
  • 19. SCALABILITÀ I progetti crescono gradualmente, e le operazioni più comuni coinvolgono il rebuil dopo poche modifiche contenute su pochi file
  • 20. CORRETTEZZA Evita di costringere lo sviluppatore ad eseguire un mk cen ae la nel caso in cui rimangano vecchi target nel tree, moduli esterni potrebbero iniziare a dipendervi, nascondendo il problema fino a quando il file non verrà cancellato manualmente
  • 21. ±«³§´¡µþ±õ³¢±õ°ÕÀ Evitare l'impatto sulle performance con un c fo mk d o; ae rischia di avere effetti diversi sul risultato rispetto ad un semplice mk ae e costringe lo sviluppatore a memorizzare queste differenze
  • 22. IL BOUND O(N) DI MAKE E SIMILI Questi sistemi di build, percorrono l'albero delle dipendenze, verificando se sia necessario aggiornarli uno per uno Ma per fare questa decisione, occorre analizzare tutte le dipendenze a ritroso
  • 23. IL BOUND O(LOG^2(N)) DI TUP Sistemi di build come Tup, preferiscono invece tenere memorizzato uno stato del grafo completo su disco (un database SQLite). Nel grafo, Tup memorizza anche i comandi usati per generare i file, questo serve a: Tenere traccia della generazione multipla di file Rieseguire i comandi, quando un argomento/opzione di questi viene cambiata Cancellare i file generati, quando il comando non è più richiesto
  • 24. Da questo, Tup poi ricava la lista dei cambiamenti in tempo O(log(n)) (essendo i nodi indicizzati nel db) A questo punto, ricavando le dipendenze si può ottenere il grafo parziale che rappresenta i passi che verranno svolti nella build. Nel caso di un progetto tipico, questo viene strutturato come un albero sul filesystem, permettendoci quindi di ottenere un tempo atteso come O(log(n)), da qui O(log^2(n)) per l'intera build. Build System Rules and Algorithms
  • 25. REDO Questo build sytem ha un approccio diverso: anch'esso punta ad avere un completo grafo di tutte le dipendenze, ma queste vengono specificate all'interno di diversi file e verranno letti da processi di redo chiamati ricorsivamente Un primo prototipo di redo è stato implementato in sole 250 righe Bash! (Mentre l'implementazione di riferimento sono meno di 2000 righe Python)
  • 26. Per ottenere un binario chiamato myprog, da due sorgenti "a.c" e "b.c", sono necessari solo 2 file: dfutod eal.. rd-fhne$. eoicag 2c gc-D-F$. - - $ $. c M M 2d c o 3 2c ra DP <2d ed ES $. rd-fhne$DP#: eoicag {ES*} mpo.o yrgd DP=aobo ES". ." rd-fhne$ES eoicag DP gc- $ $ES c o 3 DP
  • 27. I file sono dei normali script shell (ma possono essere sostituiti da qualunque altro linguaggio di scripting) e le dipendenze sono specificate con le chiamate al comando redo-ifchange redo-ifchange indica di rieseguire lo script corrente, solo nel caso in cui le dipendenze (fornite come argomento) siano cambiate
  • 28. Per verificare se queste dipendenze sono cambiate, anche redo usa lo stesso approccio di tup: un database sqlite Se queste non sono cambiate, redo deve solo esaminare il db, senza dover rileggere ed eseguire i relativi file .do Le dipendenze, come in default.o.do possono essere calcolate facilmente usando un altro programma esterno, come lo stesso gcc usato per compilare, senza bisogno di alcuna sintassi particolare
  • 29. Redo abbraccia la filosofia Unix di piccoli programmi componibili grazie a pipeline e ridirezioni dell'output, e di default aggiunge tutto l'output nel file generato, questo permette, con queste 2 semplici righe: rd-fhneflls eoicag ieit ge ^r/flls rp sc ieit di rigenererare una lista intermedia di dipendenze che potrà essere quindi riusata dal resto della build.
  • 30. Redo disincentiva l'uso di variabili globali, e spingendo l'unica vera informazione che dev'essere accessibile a tutte le parti della build (ovvero il grafo delle dipendenze) in un unico db, è possibile ripetere una parte della build che aveva dato errore senza problemi, essendo ogni passaggio modulare.
  • 31. Questo viene anche invogliato dal formato stesso dell'output, ecco un ipotetico esempio: $rd tc eo / rd tc eo / rd eo tcc /. rd eo tccc /.. rd eo tcccb /... rd eo tcccbb /....
  • 32. L'indentazione caratterizza il livello della ricorsione a cui è arrivato redo, ma copiando e incollando l'ultima riga per rieseguirla verbosamente, ci possiamo rendere conto che ognuno di questi è un comando valido: $rd tcccbb- eo /.... x rd tcccbb eo /.... *s -xdfutbd cccb. cccbbrd2tp h e eal..o ... b .....eo.m +rd-fhnecccbba eoicag ..... +eh at- co -ob +ctcccbba a ..... +.sep11 /le . rd tcccbb(oe eo /.... dn)
  • 33. Un altro vantaggio è quindi l'evidente assenza di flag ed opzioni ripetute centinaia di volte nell'output delle tipiche compilazioni con make, output reso ancor meno leggibile nel caso in cui la compilazione sia avvenuta in parallelo, nascondendo quindi l'ordine logico che sottende alla build Redo on Github
  • 34. Altri sistemi di build o risorse interessanti: Ninja: un build system veloce e di "basso livello" Fabricate: trova le dipendenze automaticamente Shake: un altro strumento che si concentra sulla gestione accurata delle dipendenze e rebuild minimi Boilermake: un boilerplate makefile che segue un approccio non ricorsivo
  • 35. Altri sistemi di build o risorse interessanti: Il punto di vista di Bruce Eckel nel 2004 su Ant, le alternative disponibili all'epoca e le difficoltà nel loro sviluppo Un linguaggio puramente dichiarativo come XML non è una buona scelta per un sistema di build: come James Duncan Davidson arrivò a sceglierlo nella creazione di Ant