Laboratorio di Sistemi Operativi Tool per la programmazione Alberto Montresor Renzo Davoli Copyright © 2004-2005 Alberto Montresor, Renzo Davoli Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license can be found at: http://www.gnu.org/licenses/fdl.html#TOC1 © 2004-2005 Renzo Davoli, Alberto Montresor 1 Sommario Come gestire progetti di programmazione molto grandi • Come organizzarli • Come compilarli • Come lavorare in cooperazione Nota: • Con un'enfasi sul C, ma i concetti valgono anche per altri linguaggi di programmazione © 2004-2005 Renzo Davoli, Alberto Montresor 2 Come organizzare un progetto Ovviamente: • Programmi di grandi dimensioni non possono essere contenuti in un file singolo Nel C • vi sono tecniche per semplificare gestione di file multipli • non sono "enforced": sono lasciate al programmatore Un programma grande è diviso in moduli: • i file .h contengono le funzioni prototipo del modulo ed eventuali costanti • i file .c contengono le definizioni di funzioni del modulo • i moduli sono compilati separatamente • viene generato un eseguibile tramite linking dei moduli © 2004-2005 Renzo Davoli, Alberto Montresor 3 Esempio: sample.c #include <stdio.h> #include "my_math.h" int main() { int a, b, c; puts("Input three numbers:"); scanf("%d %d %d", &a, &b, &c); printf("The average of %d %d %d is %f.\n", a,b,c,average(a,b,c)); return 0; } © 2004-2005 Renzo Davoli, Alberto Montresor 4 Esempio - Modulo my_math /* my_math.h */ #define PI 3.1415926 float average(int x, int y, int z); float sum(int x, int y, int z); /* my_math.c */ #include "my_math.h" float average(int x, int y, int z) { return sum(x,y,z)/3; } float sum(int x, int y, int z) { return x+y+z; } © 2004-2005 Renzo Davoli, Alberto Montresor 5 Compilare questo semplice programma Per generare my_math.o • Abbiamo bisogno di my_math.c e my_math.h • gcc –c my_math.c Per generare sample.o • Abbiamo bisogno di sample.c e my_math.h • gcc –c sample.c Per generare l'eseguibile • Abbiamo bisogno di my_math.o e sample.o • gcc –o sample sample.o my_math.o © 2004-2005 Renzo Davoli, Alberto Montresor 6 Come utilizzare make I programmi che consistono di molti moduli sono impossibili da mantenere manualmente Si crea un Makefile Target # Makefile for the sample sample: Indentazioni con tab, non spazi sample.o Dipendenze my_math.o cc –o sample sample.o my_math.o sample.o: sample.c my_math.h cc –c sample.c my_math.o: my_math.c my_math.h Comandi cc –c my_math.c clean: rm sample *.o core © 2004-2005 Renzo Davoli, Alberto Montresor 7 Makefile Un makefile consiste in un insieme di regole del tipo: Prerequisiti: • uno o più file utilizzati come input per creare il file target target ... : prerequisites ... command ... ... Regole Target: Nota: • il nome di un file da generare • un'azione da svolgere © 2004-2005 Renzo Davoli, Alberto Montresor • • una o più azioni da eseguire la prima regola è quella di "default", o radice 8 Come utilizzare make Come? • Si salva il file con il nome Makefile o makefile nella stessa directory contenente i file • Si lancia l'utility make Make • trova il Makefile • verifica le regole e le dipendenze e rigenera i file per cui è necessario un update Esempio: • Se solo sample.c è stato modificato: • cc –c sample.c • cc –o sample sample.o my_math.o © 2004-2005 Renzo Davoli, Alberto Montresor 9 Come utilizzare make Per rimuovere tutti i file generati • make clean Per ricompilare, è possibile: • Rimuovere tutti i file generati e ricompilare • make clean ; • make Oppure è possibile cambiare la data di ultima modifica: • touch my_math.h ; make • La data di ultima modifica di my_math.h prende l'ora corrente • Nota: questo perchè tutti i file dipendono da my_math.h © 2004-2005 Renzo Davoli, Alberto Montresor 10 Utilizzare make con directory multiple Con l'aumentare del numero di file .c • diventa difficile controllare tutto con un unico makefile • conviene utilizzare più makefile, uno per modulo Un programma viene organizzato in questo modo: • una directory per modulo • file header: • una directory per tutti i file .h • oppure: file .h di un modulo nel modulo stesso • Makefile nella directory radice per la creazione dell'eseguibile/libreria • Makefile in ogni modulo dirigono la creazione dei file .o © 2004-2005 Renzo Davoli, Alberto Montresor 11 Un esempio di Makefile Si consideri un programma C composto da • una struttura dati a coda queue • queue_types.h, queue_interface.h, queue.c • una struttura dati a stack stack • stack_types.h, stack_interface.h, stack.c • un modulo principale • main.c Organizzazione • • Tre sottodirectory: stack, queue, include Tutti i file .h in include Makefile Makefile stack stack.c queue include main.c Makefile stack.c s_t.h s_i.h ... © 2004-2005 Renzo Davoli, Alberto Montresor 12 Un esempio di Makefile stack contiene stack.c e il seguente Makefile: all: stack.o stack.o: stack.c \ ../include/stack_types.h \ ../include/stack_interface.h gcc -I../include -c stack.c clean: rm -f *.o Note: opzione -I di gcc • Specifica uno o più path in cui cercare per trovare file .h • Path multipli separati da virgole "," © 2004-2005 Renzo Davoli, Alberto Montresor 13 Un esempio di Makefile queue contiene queue.c e il seguente Makefile: all: queue.o queue.o: queue.c \ ../include/queue_types.h \ ../include/queue_interface.h gcc -I../include -c queue.c clean: rm -f *.o © 2004-2005 Renzo Davoli, Alberto Montresor 14 Un esempio di Makefile main contiene main.c e il seguente Makefile: all: main.o stackdir queuedir gcc -o main main.o ../stack/stack.o \ ../queue/queue.o main.o: main.c include/*.h gcc -Iinclude -c main.c stackdir: cd stack ; make all queuedir: cd queue ; make all © 2004-2005 Renzo Davoli, Alberto Montresor 15 Un esempio di Makefile clean: rm -f *.o main core cleanall: rm -f *.o main core cd stack ; make clean cd queue ; make clean Nota: • Ogni riga di comando viene eseguita tramite una subshell • Come viene gestita la directory corrente • Cosa succede se una directory manca? © 2004-2005 Renzo Davoli, Alberto Montresor 16 Utilizzazione delle macro nei makefile Macro nei Makefile • Utilizzate per semplificare la modifica dei Makefile • Utilizzate per ridurre la dimensione dei file semplificando espressioni ripetute Sintassi • Definizione: name = value • Riferimenti: $(name) o ${name} © 2004-2005 Renzo Davoli, Alberto Montresor 17 Un esempio di Makefile, rivisitato Makefile in stack: CC HDIR INCPATH DEPH = = = = gcc ../include -I$(HDIR) $(HDIR)/stack_types.h \ $(HDIR)/stack_interface.h SOURCE = stack.c OBJECTS = stack.o all: $(OBJECTS) stack.o: $(SOURCE) $(DEPH) $(CC) $(INCPATH) -c $(SOURCE) clean: rm -f *.o © 2004-2005 Renzo Davoli, Alberto Montresor 18 Un esempio di Makefile, rivisitato Makefile in queue CC HDIR INCPATH DEPH = = = = gcc ../include -I$(HDIR) $(HDIR)/queuetypes.h \ $(HDIR)/queueinterface.h SOURCE = queue.c OBJECTS = queue.o all: $(OBJECTS) queue.o: $(SOURCE) $(DEPH) $(CC) $(INCPATH) -c $(SOURCE) clean: rm -f *.o © 2004-2005 Renzo Davoli, Alberto Montresor 19 Un esempio di Makefile, rivisitato Makefile per main CC HDIR INCPATH DEPH = gcc = include = -I$(HDIR) = $(HDIR)/queue_types.h \ $(HDIR)/queue_interface.h \ $(HDIR)/stack_types.h \ $(HDIR)/stack_interface.h OBJECTS = stack/stack.o queue/queue.o all: main main: main.o stackdir queuedir $(CC) -o main main.o $(OBJECTS) © 2004-2005 Renzo Davoli, Alberto Montresor 20 Un esempio di makefile, rivisitato main.o: main.c $(HDIR)/*.h $(CC) $(INCPATH) -c main.c stackdir: cd stack && make all queuedir: cd queue && make all clean: rm -f *.o main core cleanall: -rm -f *.o main core cd stack && make clean cd queue && make clean Ignora eventuali errori Solo in caso di successo con cd © 2004-2005 Renzo Davoli, Alberto Montresor 21 Makefile "avanzati" Le funzionalità di make non si esauriscono qui • Strutture di controllo come statement condizionali e loop • Regole implicite che agiscono come default quando non sono presenti regole esplicite • Semplici funzioni di supporto per trasformare testo • Variabili automatiche che si riferiscono a vari elementi di un Makefile, come target e dipendenze. Per ulteriori dettagli: • http://www.gnu.org/manual/make/html_mono/make.html © 2004-2005 Renzo Davoli, Alberto Montresor 22 Esempi Dipendenze automatiche • make è in grado di inferire alcune dipendenze e regole OBJECTS = main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o edit : $(OBJECTS) cc -o edit $(objects) main.o : defs.h kbd.o : defs.h command.h command.o : defs.h command.h display.o : defs.h buffer.h insert.o : defs.h buffer.h search.o : defs.h buffer.h files.o : defs.h buffer.h command.h utils.o : defs.h © 2004-2005 Renzo Davoli, Alberto Montresor main.o : defs.h main.c gcc -c main.c 23 Esempi Uno stile alternativo • è possibile "raggruppare" le dipendenze OBJECTS = main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o edit : $(OBJECTS) cc -o edit $(OBJECTS) $(OBJECTS) : defs.h kbd.o command.o files.o : command.h display.o insert.o search.o files.o : buffer.h © 2004-2005 Renzo Davoli, Alberto Montresor 24 Esempi Regole "statiche" • Specificano il comportamento per una classe di file • gnuplot: input set{eps|gpt}.gpt *.plt, output output.{eps|gpt} Afferma che sono solo azioni .PHONY: all eps png all: eps png eps: quota.eps transfer.eps single.eps png: quota.png transfer.png single.png Identifica il prerequisito %.eps : %.plt seteps.gpt gnuplot seteps.gpt $< ; mv output.eps $@ %.png : %.plt seteps.gpt gnuplot setpng.gpt $< ; mv output.png $@ clean: rm -f *.eps *.png © 2004-2005 Renzo Davoli, Alberto Montresor Identifica il target 25 Portabilità E' sempre un problema! • Diversi tipi di: processori / compilatori / librerie / s.o. • Diverse versioni di: compilatori / librerie / s.o. Makefile per la portabilità: • scrivere un makefile è facile • come abbiamo visto... • scrivere un buon makefile è difficile • maintanance target (install, dist, distclean, ...) • opzioni utente • gestione delle dipendenze !!!!! • scrivere un makefile portatile è molto difficile • path di librerie, installazioni, etc. © 2004-2005 Renzo Davoli, Alberto Montresor 26 Auto-tools GNU project "auto-tools" • automake - generazione automatica makefile • autoheader - generazione config headers; per portabilità • autoconf - genera configure script • libtool - gestione librerie statiche/dinamiche config.h Makefile autoconf configure Makefile.am automake Makefile.in autoheader Config.h.in Configure.in © 2004-2005 Renzo Davoli, Alberto Montresor 27 Esempio di autoconf programmer@c:~/project> ls -1 my_math.c my_math.h sample.c programmer@c:~/project>:~/tmp> autoscan programmer@c:~/project>:~/tmp> ls -1 autoscan.log configure.scan Autoscan crea il file configure.scan, my_math.c che ci servirà come template per my_math.h sample.c creare il file configure.in Project © 2004-2005 Renzo Davoli, Alberto Montresor autoscan configure.scan 28 Esempio di autoconf programmer@c:~/project> cat configure.scan # -*- Autoconf -*# Process this file with autoconf for a configure script. AC_PREREQ(2.57) AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS) AC_CONFIG_SRCDIR([my_math.c]) AC_CONFIG_HEADER([config.h]) # Checks for programs. AC_PROG_CC # Checks for libraries. # Checks for header files. # Checks for typedefs, structures, and compiler characteristics. # Checks for library functions. AC_OUTPUT © 2004-2005 Renzo Davoli, Alberto Montresor 29 Esempio di autoconf programmer@c:~/project> cat configure.in # -*- Autoconf -*# Process this file with autoconf for a configure script. AC_PREREQ(2.57) AC_INIT(sample, [1.00], [[email protected]]) AC_CONFIG_SRCDIR([my_math.h]) #AC_CONFIG_HEADER([config.h]) # Checks for programs. AC_PROG_CC # Checks for libraries. # Checks for header files. Questa riga è commentata, perchè non abbiamo bisogno di un file config.h (per gestire portabilità) # Checks for typedefs, structures, and compiler characteristics. # Checks for library functions. AC_OUTPUT([Makefile]) © 2004-2005 Renzo Davoli, Alberto Montresor 30 Esempio di autoconf programmer@c:~/project> automake -a configure.in: `AM_INIT_AUTOMAKE' must be used automake: no implementation of AM_INIT_AUTOMAKE was found, automake: probably because aclocal.m4 is missing... automake: You should run aclocal to create this file, then automake: run automake again. automake: no `Makefile.am' found or specified -a aggiunge alcuni file standard al progetto; altrimenti li richiede autoscan.in Makefile.am © 2004-2005 Renzo Davoli, Alberto Montresor automake Makefile.in 31 Esempio di autoconf programmer@c:~/project> cat configure.in # -*- Autoconf -*# Process this file with autoconf for a configure script. AC_PREREQ(2.57) AC_INIT(sample, [1.00], [[email protected]]) AC_CONFIG_SRCDIR([my_math.h]) AM_INIT_AUTOMAKE # Checks for programs. AC_PROG_CC # Checks for libraries. # Checks for header files. # Checks for typedefs, structures, and compiler characteristics. # Checks for library functions. AC_OUTPUT([Makefile]) © 2004-2005 Renzo Davoli, Alberto Montresor 32 Esempio di autoconf programmer@c:~/project> cat Makefile.am noinst_PROGRAMS=sample sample_SOURCES=sample.c my_math.c #Ulteriori esempi, commentati: #bin_PROGRAMS=sample #include_HEADERS=my_math.h #lib_LIBRARIES=mymath.a #mymath_a_SOURCE=my_math.c Struttura generale: where_WHAT where - dove mettere i file generati WHAT - quale file considerare © 2004-2005 Renzo Davoli, Alberto Montresor 33 Esempio di autoconf programmer@c:~/project> aclocal programmer@c:~/project> automake -a automake Makefile.am: required file `./NEWS' not found Makefile.am: required file `./README' not found Makefile.am: required file `./AUTHORS' not found Makefile.am: required file `./ChangeLog' not found programmer@c:~/project> touch \ README NEWS AUTHORS ChangeLog programmer@c:~/project> automake -a programmer@c:~/project> autoconf autoscan.in Makefile.in © 2004-2005 Renzo Davoli, Alberto Montresor autoconf configure 34 Esempio di autoconf programmer@c:~/project> ./configure checking for a BSD-compatible install.. /usr/bin/install -c checking whether build environment is sane... yes checking for gawk... gawk checking whether make sets $(MAKE)... yes checking for gcc... gcc checking for C compiler default output... a.out checking whether the C compiler works... yes checking whether we are cross compiling... no checking for suffix of executables... checking for suffix of object files... o checking whether we are using the GNU C compiler... yes checking whether gcc accepts -g... yes checking for gcc option to accept ANSI C... none needed checking for style of include used by make... GNU checking dependency style of gcc... gcc configure: creating ./config.status config.status: creating Makefile config.status: executing depfiles commands © 2004-2005 Renzo Davoli, Alberto Montresor 35 Autoconf Note finali • Con questo esempio abbiamo solo "scalfito" le potenzialità di auto* • Maggiori informazioni presso: • google://automake • google://autoheader • google://autoconf • google://libtool © 2004-2005 Renzo Davoli, Alberto Montresor 36 CVS - Concurrent Versioning System Perchè utilizzare CVS? • tenere traccia delle differenti versioni dei vostri file • mantenere le vecchie versioni • lavorare sugli stessi file da postazioni diverse • lavorare sugli stessi file in cooperazione con altre persone Per chi è indicato? • Programmatori, scrittori (per chi usa latex) Open-source • http://www.cvshome.org/. © 2004-2005 Renzo Davoli, Alberto Montresor 37 CVS Repository Working dir 1 /home/cvs /home/cvs/proj1 /home/cvs/proj1/a.c,v /home/cvs/proj1/b.c,v /home/cvs/proj2 /home/cvs/proj2/a.tex,v Working dir 2 © 2004-2005 Renzo Davoli, Alberto Montresor 38 CVS Repository /home/cvs /home/cvs/proj1 /home/cvs/proj1/a.c,v /home/cvs/proj1/b.c,v Working dir 2 checkout /home/pippo/proj1 /home/pippo/proj1/a.c /home/pippo/proj1/b.c /home/cvs/proj2 /home/cvs/proj2/a.tex,v Working dir 2 © 2004-2005 Renzo Davoli, Alberto Montresor 39 CVS Repository Working dir 1 /home/cvs /home/cvs/proj1 /home/cvs/proj1/a.c,v /home/cvs/proj1/b.c,v /home/pippo/proj1 /home/pippo/proj1/a.c /home/pippo/proj1/b.c checkout /home/pippo/prog2 /home/pippo/prog2/a.tex /home/cvs/proj2 /home/cvs/proj2/a.tex,v Working dir 2 © 2004-2005 Renzo Davoli, Alberto Montresor 40 CVS Repository Working dir 1 /home/cvs /home/cvs/proj1 /home/cvs/proj1/a.c,v /home/cvs/proj1/b.c,v /home/pippo/proj1 /home/pippo/proj1/a.c /home/pippo/proj1/b.c checkout /home/pippo/prog2 /home/pippo/prog2/a.tex /home/cvs/proj2 /home/cvs/proj2/a.tex,v Working dir 2 /home/pluto/proj1 /home/pluto/proj1/a.c /home/pluto/proj1/b.c © 2004-2005 Renzo Davoli, Alberto Montresor 41 CVS Repository Working dir 1 /home/cvs /home/cvs/proj1 /home/cvs/proj1/a.c,v /home/cvs/proj1/b.c,v Modificato /home/pippo/proj1 /home/pippo/proj1/a.c /home/pippo/proj1/b.c /home/pippo/prog2 /home/pippo/prog2/a.tex /home/cvs/proj2 /home/cvs/proj2/a.tex,v Working dir 2 /home/pluto/proj1 /home/pluto/proj1/a.c /home/pluto/proj1/b.c © 2004-2005 Renzo Davoli, Alberto Montresor 42 CVS Repository Working dir 1 /home/cvs /home/cvs/proj1 /home/cvs/proj1/a.c,v /home/cvs/proj1/b.c,v commit /home/pippo/proj1 /home/pippo/proj1/a.c /home/pippo/proj1/b.c /home/pippo/prog2 /home/pippo/prog2/a.tex /home/cvs/proj2 /home/cvs/proj2/a.tex,v Working dir 2 /home/pluto/proj1 /home/pluto/proj1/a.c /home/pluto/proj1/b.c © 2004-2005 Renzo Davoli, Alberto Montresor 43 CVS Repository Working dir 1 /home/cvs /home/cvs/proj1 /home/cvs/proj1/a.c,v /home/cvs/proj1/b.c,v /home/pippo/proj1 /home/pippo/proj1/a.c /home/pippo/proj1/b.c update /home/pippo/prog2 /home/pippo/prog2/a.tex /home/cvs/proj2 /home/cvs/proj2/a.tex,v Working dir 2 /home/pluto/proj1 /home/pluto/proj1/a.c /home/pluto/proj1/b.c © 2004-2005 Renzo Davoli, Alberto Montresor 44 CVS Come funziona CVS? • Orientato ai file / orientato alla linea • Nessun vero e proprio concetto di "progetto" • Lavoro soprattutto con file testuali; può gestire file binari © 2004-2005 Renzo Davoli, Alberto Montresor 45 CVS Come indicare dove si trova un repository? • Local path • External :ext:user@host:path • Password server :pserver:user@host:path Da linea di comando: • cvs -d /home/cvs checkout proj • cvs -d :pserver:[email protected]:/home/cvs login Password: xxxxxxx cvs checkout Tramite configurazione, una volta: • export CVSROOT=cvs.c.com:/home/cvs • export CVS_RSH=ssh © 2004-2005 Renzo Davoli, Alberto Montresor 46 CVS - Importare un progetto pippo@c:~> cd temp pippo@c:~/temp> ls my_math.c my_math.h sample.c pippo@c:~/project> cvs -d /home/cvs import \ -m "First release" sample pippo start N sample/sample.c N sample/my_math.c N sample/my_math.h No conflicts generated by this import pippo@c:~/project> © 2004-2005 Renzo Davoli, Alberto Montresor 47 CVS - Importare un progetto pippo@c:~> cvs -d /home/cvs checkout sample cvs checkout: Updating sample U sample/my_math.c U sample/my_math.h U sample/sample.c pippo@c:~/> ls sample CVS/ my_math.c my_math.h sample.c pippo@c:~/> ls sample/CVS/ Entries Repository Root pippo@c:~/> cat sample/CVS/Root /home/cvs Da qui in poi, non è più necessario specificare -d /home/cvs © 2004-2005 Renzo Davoli, Alberto Montresor 48 CVS - Modificare un progetto pippo@c:~/sample> cp sample.c sample2.c pippo@c:~/sample> vi sample.c pippo@c:~/sample> cvs add sample2.c cvs add: scheduling file `sample2.c' for addition #include cvs add: use 'cvs commit' to #include add this file permanently <stdio.h> "my_math.h" int main() { int a, b, c; puts("Inserisci tre numeri:"); scanf("%d %d %d", &a, &b, &c); printf("The average of %d %d %d is %f\n", a,b,c,average(a,b,c)); } /* Commento finale */ © 2004-2005 Renzo Davoli, Alberto Montresor 49 CVS - Modificare un progetto pippo@c:~/sample> cvs commit -m "Added file" cvs commit: Examining . Checking in sample.c; /home/montreso/cvs/sample/sample.c,v <-- sample.c new revision: 1.2; previous revision: 1.1 done RCS file: /home/montreso/cvs/sample/sample2.c,v done Checking in sample2.c; /home/montreso/cvs/sample/sample2.c,v <-- sample2.c initial revision: 1.1 done © 2004-2005 Renzo Davoli, Alberto Montresor 50 CVS - Varie ed eventuali pippo@c:~/sample> cvs update cvs update: Updating . Vedere le differenze: pippo@c:~/sample> cvs diff -r1.1 sample.c Index: sample.c RCS file: /home/montreso/cvs/sample/sample.c,v retrieving revision 1.1 retrieving revision 1.2 diff -r1.1 -r1.2 6c6 < puts("Input three numbers:"); --> puts("Inserisci tre numeri:"); 10d9 < return 0; 11a11 > /* Commento finale */ © 2004-2005 Renzo Davoli, Alberto Montresor 51 Conclusioni Si può fare di più.... • Gestione delle versioni • Gestione dei conflitti • Fork di progetti • Gestione sicura dei repository • Etc. Etc. Per ulteriori informazioni: • google://cvs book © 2004-2005 Renzo Davoli, Alberto Montresor 52