(E-Book - ITA - PDF) Programmare Linux
(E-Book - ITA - PDF) Programmare Linux
Programmare Linux
Table of Contents
...............................................................................................................................................................................1
1. Introduzione .....................................................................................................................................................1
1.1 Perche questa guida?.......................................................................................................................................1
1.2 Come collaboro a questa guida?.....................................................................................................................1
1.3 Uso e ridistribuzione ......................................................................................................................................2
1.4 Requisiti iniziali..............................................................................................................................................2
2. Strumenti di programmazione...........................................................................................................................2
2.1 Che cosa è un compilatore? ...........................................................................................................................3
Che cosa fanno i compilatori ?................................................................................................................3
Il linker.....................................................................................................................................................3
2.2 Il Gnu C compiler (GCC) ..............................................................................................................................4
2.3 Introduzione agli editor di testo......................................................................................................................6
Gli editor di testo.....................................................................................................................................6
Joe............................................................................................................................................................6
Emacs ......................................................................................................................................................8
Emacs e la programmazione....................................................................................................................9
Una sessione d'esempio...........................................................................................................................9
2.4 Il Gnu Make....................................................................................................................................................9
Che cosa fa make?.................................................................................................................................10
Un semplice makefile............................................................................................................................10
Macro e Makefile...................................................................................................................................12
Ancora un altro Makefile.......................................................................................................................13
L'uso dei suffissi in un makefile............................................................................................................13
Un makefile completo............................................................................................................................13
2.5 AutoMake e AutoConf..................................................................................................................................14
Prima fase: Dai sorgenti al [Link]................................................................................................15
Seconda fase: Documentazione.............................................................................................................15
Terza fase: Creazione del file [Link]...........................................................................................16
Quarta fase:Autoheader e acconfig.h.....................................................................................................17
Quinta Fase: Realizzazione dello script configure.................................................................................18
2.6 Creiamo un pacchetto con Automake e Autoconf........................................................................................18
Prima fase: Dai sorgenti al file [Link]..........................................................................................18
Terza fase: Creazione del [Link].................................................................................................21
Quarta fase: Autoheader e acconfig.h....................................................................................................21
Quinta fase: Realizziamo lo script configure.........................................................................................22
Note finali..............................................................................................................................................23
2.7 Documentazione sul Make ...........................................................................................................................23
2.8 Il Gnu Debugger...........................................................................................................................................23
Come funziona il GDB?.........................................................................................................................23
Breakpoint e Watchpoint.......................................................................................................................24
Breakpoint..............................................................................................................................................24
Watchpoint.............................................................................................................................................24
Abilitazione e Disabilitazione di watchpoints e breakpoints.................................................................25
Muoversi durante l'esecuzione...............................................................................................................26
Il GDB e lo stack....................................................................................................................................27
Sessione di esempio...............................................................................................................................27
2.9 Documentazione sul GDB............................................................................................................................29
2.10 Il Data Display Debugger (DDD)...............................................................................................................29
i
Programmare Linux
Table of Contents
2.11 Scrivere la guida in linea (man page).........................................................................................................30
2.12 Creiamo un RPM........................................................................................................................................32
Esempio di /etc/rpmrc............................................................................................................................33
Creiamo il file di specifiche...................................................................................................................33
Creiamo il pacchetto RPM.....................................................................................................................34
Un pacchetto contenente i sorgenti........................................................................................................35
2.13 Risorse e approfondimenti sugli strumenti di sviluppo..............................................................................35
3. Iniziamo a programmare.................................................................................................................................35
3.1 Le parole chiave del C..................................................................................................................................35
3.2 Come è composto un programma C?............................................................................................................35
Espressioni.............................................................................................................................................35
Le istruzioni...........................................................................................................................................36
I blocchi di istruzioni.............................................................................................................................36
Blocchi di funzione................................................................................................................................37
3.3 Il primo programma......................................................................................................................................39
Macro di uscita.......................................................................................................................................41
3.4 Ancora sulle funzioni....................................................................................................................................42
Esercizi...................................................................................................................................................44
3.5 Direttive al preprocessore.............................................................................................................................45
4. ChangeLog .....................................................................................................................................................45
5. TO DO (Da fare).............................................................................................................................................45
ii
Guida alla programmazione C in ambiente GNU/Linux
Giorgio Zoppi
deneb@[Link]
versione 0.0.1e, 11 Gennaio 1999
1. Introduzione
Programmare Linux ha come obiettivo primario insegnare ai principianti la programmazione C in ambiente
GNU/Linux. Vuole essere in secondo luogo un riferimento per tutti coloro che, provenendo da altre
esperienze di programmazione, desiderano programmare in Linux.
Il libro è suddiviso in due parti essenziali, la prima che riguarda la programmazione C vera e propria e la
seconda che è inerente alla programmazione del sistema operativo.
Nel caso troviate scorrettezze, vi prego di contattarmi all'indirizzo e−mail specificato, o mandare un post alla
mailing list.
Durante il libro verranno presentati esercizi di programmazione, per le soluzioni e/o correzioni fate
riferimento alla mailing list sopra citata.
1
Programmare Linux
Questo libro è una documentazione gratuita; si può ridistribuirlo e/o modificarlo secondo le specifiche della
GNU General Public License pubblicata dalla Free Software Foundation; presenti nella versione 2 della
License, o (a scelta) in qualche versione seguente.
Questa documentazione viene distribuita nella speranza che possa essere utile, ma senza alcuna garanzia;
senza anche l'implicita garanzia di commerciabilità o di adeguatezza ad uno scopo particolare. Si veda la
GNU General Public License per maggiori particolari.
Si può ottenere una copia della GNU General Public License scrivendo alla Free Software Foundation, Inc.,
675 Mass Ave, Cambridge, MA 02139, USA. La guida è attualmente disponibile nei seguenti formati:
• [Link]
• [Link]
2. Strumenti di programmazione
È particolarmente importante per un programmatore avere strumenti flessibili di programmazione. In Linux
sono stati sviluppati contemporaneamente al sistema operativo una miriade di linguaggi di programmazione
ed alcuni strumenti utilissimi per testare e verificare i programmmi. In questo capitolo introdurremo gli
strumenti di base, che useremo per tutto il resto del libro, tra cui il compilatore GCC (Gnu C Compiler), il
debugger GDB (Gnu Debugger) il GNU Make e l'editor Emacs. Iniziamo allora a capire come funziona un
compilatore per poi passare a una breve descrizione del GCC.
..............
Linguaggio di . . Linguaggio
−−−−−−−−−−>. Compilatore.−−−−−−−−−−−> Macchina
Programmazione . . (Target)
(Sorgente) ..............
Figura 1.1
Un compilatore permette alla maggior parte degli utenti di computer di ignorare i dettagli del linguaggio
macchina. I compilatori quindi permettono ai programmi di essere indipendenti dalla macchina. Questa è una
risorsa particolarmente preziosa in un periodo dove il numero e la varietà di computer continua a crescere
esplosivamente.
Il linker
Il linker è un programma che attua il processo di linking, che consiste nell'unione di uno o più codici oggetto
e (opzionalmente) i moduli di codice oggetto contenuti in una libreria, in modo da produrre un file eseguibile.
Il GCC (a patto che non specifichiamo l'opzione −c) esegue automaticamente il processo di linking. Lo
schema di figura 1.1 puo essere esteso nel seguente modo:
...............................
. .
File Sorgente −−−−−>. Compilatore −−−−−−> Linker . −−−> File Eseguibile
............................... |
−−−> File Oggetto −−
Figura 1.2
−c file_sorgente1, file_sorgente2, ecc.. Compila senza linkare i files sorgenti specificati, creando
un file oggetto per ogni file sorgente specificato. Questa
opzione è utile per la compilazione separata mediante
l'utilizzo dell'utility make.
Esempio di utilizzo:
gcc −c sourcefile.c
Output:
sourcefile.o
Non preoccupatevi se non vi è chiaro qualcosa delle opzioni presenti nella tabella 1.0, in seguito ci
ritorneremo sopra. Ho solo voluto dare una discreta panoramica delle opzioni che useremo per compilare gli
esempi di questo testo.
L'utilità di questo mio intervento è chiara se si pensa che per programmare è indispensabile un editor in cui
scrivere il nostro codice, da dare poi in pasto al nostro compilatore preferito.
Joe
Inizialmente volevo partire presentando l'editor di testi VI che è presente nella quasi totalità dei sistemi
UNIX−like. In seguito però ho deciso di fare una breve introduzione ai comandi di Joe (Joe's Own Editor) in
quanto questo è sicuramente più semplice da usare (in particolare per chi è alle prime armi), potente e con
una guida in linea.
Una particolarità di questo programma è che riesce bene ad emulare altri editor. Questo è possibile grazie al
fatto che in Linux si possono creare dei link che rimandano sempre allo stesso file ma con nomi diversi. Joe
controlla con che nome è stato invocato e si adatta cambiando il proprio modo di operare di conseguenza.
Per eseguire joe nella sua vera natura scrivete semplicemente joe nomefile, per eseguirlo in modalità
emulazione usate i seguenti nomi:
I comandi che seguono sono quelli di base, tutti i comandi disponibili sono descritti nell'help in linea.
Comando Funzione
Ctrl+K+H Help in linea (apri/chiudi) da scorrete premendo Esc+. O Esc+,
Sposta in cursore una linea su.
@da
Il modo ricerca :
Premendo Ctrl+K+F si entra nel modo ricerca di joe che ci permette di cercare e sostituire stringhe di
caratteri. Ctrl+C abbandona la ricerca.
Molte sono le cose che joe può ancora fare per noi come ad esempio auto indentare blocchi di testo (molto
utile per la programmazione), definire macro o usare finestre multiple, ma per questo vi rimandiamo all'help
in linea.
Emacs
Più produttivo per un programmatore, anche grazie a numerose estensioni che consentono di aggiungere
funzionalità pensate espressamente per questo o quel linguaggio di programmazione.
Per far partire Emacs (naturalmente dovete averlo installato) digitate emacs nomefile. Vi troverete cosi
davanti al vostro file aperto.
Nonostante sia più user−friendly di VI Emacs usa delle combinazioni di tasti che spesso sono tutto tranne che
intuitive. Diciamo subito che per uscire da Emacs è necessario premere Ctrl+X,Ctrl+S per salvare ciò che si
è scritto, quindi premere Ctrl+X,Ctrl+C per tornare al prompt della shell di Linux.
NOTA: per le combinazioni di tasti Emacs usa due tasti Crtl e Meta, però il tasto meta non è presente nella
maggior parte delle tastiere e in sostituzione si usa Alt, se non avete neanche Alt (ma dove avete comprato il
computer???) potete usare Esc
Comando Funzione
Alt+< Ci porta all'inizio del file
Alt+> Ci porta alla fine del file
Alt+% Permette di sostituire del testo con dell'altro testo.
Ctrl+A Ci porta ad inizio riga
Crtl+E Ci porta a fine riga
Ctrl+F Avanti di un carattere
Ctrl+B Indietro di un carattere
Alt+F Avanti di una parola
Alt+B Indietro di una parola
Emacs 8
Programmare Linux
Emacs e la programmazione
da fare
Emacs e la programmazione 9
Programmare Linux
$ make
Oppure se avete creato un file make, con un vostro nome a piacimento, per ricompilare il tutto dovete, fare:
make −f nomefile
Una cosa importante da ricordare è la seguente: In ogni progetto, se un file header (*.h) è cambiato,
ciascun sorgente C, che include l'header deve essere ricompilato. Stessa cosa, per ogni sorgente
modificato. Ogni compilazione produce un file oggetto corrispondente al file sorgente. Infine, tutti i file
oggetto devono essere di nuovo linkati assieme per produrre l'eseguibile, il make fa questo per voi.
Un semplice makefile.
Un semplice makefile è composto da un insieme di regole, con la seguente forma:
target: dipendenze
<TAB> comando
.......
.......
Un target è di solito il nome di un file, che è generato da un programma; esempi di file target sono i file
eseguibili e i file oggetto.
Una dipendenza è un file che viene usato come input per creare il target. Un target spesso dipende da diversi
file.
Un comando è un azione da compiere. Una regola può essere composta da più di un comando, su una linea.
Notate Attentamente: Si deve mettere un carattere TAB all'inzio di ogni linea di comando, per far sí
che il make legga la linea in maniera corretta.
Una regola spiega come e quando fare il make di dati file, che sono i target della data linea.
# Semplice Makefile
# Sysa Test
#
@echo Compilazione in corso
sysa : main.o token.o mostra.o \
ins.o matrix.o
gcc −o sysa main.o token.o mostra.o \
ins.o matrix.o
@echo Compilazione dei sottoprogrammi
main.o : main.c header1.h
gcc −c main.c
token.o : token.c tokentype.h
gcc −c token.c
mostra.o : mostra.c header1.h
gcc −c mostra.c
ins.o : ins.c tokentype.h
gcc −c ins.c
matrix.o : matrix.c header1.h
gcc −c matrix.c
A questo punto che avete editato il vostro Makefile, con il vostro editor preferito per fare in modo che il make
vi compili i differenti file, in un unico, fate:
make
Se poi volete cancellare il tutto, fate make clean. Vediamo ora di spiegare a modo, come funziona il
makefile. La prima cosa che si nota sono i commenti, che vengono posti dopo la #, il make ignora tutto ciò
che appare dopo la # fino alla fine della linea. La seconda cosa sono i messaggi, che volete far apparire
durante la compilazione, per far ciò si usa il comando :
Ora vediamo di distinguere tra target, dipendenze, e spiegare le diverse regole. Il file target principale, quello
eseguibile dopo il make sarà sysa, che a sua volta dipende da n file oggetto, che vediamo subito dopo i due
punti. Ciascuno di questi file oggetto, vengono compilati precedentemente e sono quindi essi stessi target e
rispetto all'eseguibile sysa, dipendenze. Notate che la sequenza backslash−ritorno a capo (\), che suddivide
alcune linee lunghe, è necessaria al fine della leggibilità del Makefile stesso. Il comando, che compare sotto i
due punti, gcc −c, è necessario al make al fine di eseguire la chiamata al compilatore per ottenere i relativi
target−dipendenze. Quando si vogliono ottenere i target ènecessario specificare nel make tutte le possibili
dipendenze, compresi gli header, per esempio:
Questo significa, che il file oggetto matrix.o, dipende dal file matrix.c e dal file header1.h. Il file matrix.c
andrà compilato, quindi si necessita di un comando che esegue tale operazione ed questo è:
gcc −c matrix.c
L'opzione −c serve, per evitare il linking automatico. Sono rimaste da spiegare le ultime righe. Il clean fa sí,
che dopo che voi avete digitato make clean vengano cancellati i file binari li specificati ovvero : sysa, main.o,
token.o, mostra.o, ins.o, matrix.o. La regola dopo il target install, copia il file appena compilato nella
directory /usr/bin, dove un qualsiasi utente lo possa richiamare.
Macro e Makefile.
Molto spesso soprattuto per aumentare la flessibilità di progetti di grandi dimensioni vengono usate
all'interno di un Makefile le macro. Una macro è un nome, che ha associato un valore. Tutte le volte che il
make incontra quel nome, rimpiazza il nome con il valore ad esso associato. Facciamo un esempio più chiaro,
supponiamo di aver bisogno di una data flessibilita quando compiliamo un file, e creiamo una macro
CFLAGS= −g −Wall, faremo riferimento a tale macro in tutto il Makefile con $(CFLAGS). Tutte le volte
che il make incontra l'espressione $(CFLAGS), la sostituisce con −g −Wall. Vediamo un esempio di un
Makefile con macro:
# Tipo di compilatore
CC= gcc
# Opzioni per il compilatore
CFLAGS= −g −Wall
Nell'esempio soprastante, vedete le macro CC, e CFLAGS. Tutte le volte che compaiono il make le rimpiazza
con la stringa associata ad esse, quello che voglio farvi notare è quanto questo sia utile. Supponete che invece
di avere un Makefile di dieci righe come questo, abbiate bisogno di un Makefile ben più grande. In questo
caso se volete cambiare le opzioni del compilatore nel Makefile, dovrete sostituire tutte le opzioni, per
esempio usando Emacs, mediante un Query and Replace. Questa è operazione un po' noiosa se il Makefile è
lunghissimo, ma per fortuna l'esistenza delle macro ci dispensa da ció, basta infatti solo cambiare una linea e
il lavoro è finito. La linea CFLAGS, è appunto la macro che rappresenta le opzioni da passare al compilatore
che è rappresentato dalla macro CC. Ho scelto di definire una macro per il compilatore perchè in Linux
Macro e Makefile. 12
Programmare Linux
descrizione da fare.
Un makefile completo.
da fare
prefix = /usr/local
CC = cc
CFLAGS = −O −I.
exec_prefix = ${prefix}
bindir = ${exec_prefix}/bin
mandir = ${prefix}/man
INSTALL = install −c
INSTALL_PROGRAM = ${INSTALL}
INSTALL_DATA = ${INSTALL} −m 644
.c.o:
$(CC) −c $(CFLAGS) $*.c
all: sysa
sysa: $(MATRIX)
$(CC) −o sysa $(MATRIX)
main.o : main.c header1.h
token.o : token.c tokentype.h
mostra.o : mostra.c header1.h
ins.o : ins.c tokentype.h
matrix.o : matrix.c header1.h
install: sysa
$(INSTALL_PROGRAM) sysa $(bindir)/sysa
$(INSTALL_DATA) sysa.1 $(mandir)/man1/sysa.1
clean:
−rm −f *.o sysa
Spiegazione da fare.
Avete mai compilato un'applicazione scaricata da Internet? Se sì una volta scaricato il tarball avrete scritto i
seguenti comandi:
E poi da root:
• Changelog. Si usa questo file per memorizzare lo stato del vostro progetto e tutti i cambiamenti
apportati al codice. Di solito i ChangeLog sono fatti nel seguente modo:
* Tipo cambiamento
* Tipo cambiamento
Esempio:
• NEWS. Questo file contiene e spiega le nuove caratteristiche aggiunte al pacchetto. Esempio:
• README. File generalmente richesto per spiegare il funzionamento del programma. In parole
povere: usate questo file quando avete qualcosa di fondamentale da dire sul programma.
• AUTHORS. Questo file deve elencare una traccia di tutti coloro che hanno contribuito al programma.
Un chiaro esempio è il seguente:
Authors of NOME_PACCHETTO
====================================
Altri file che automake aggiunge e/o che dovrebbero essere presenti in ogni pacchetto sono:
Variabile Descrizione
Il file acconfig.h, utile se usate un file header (*.h) per contenere direttive #define, viene elaborato (se
presente) dall'autoheader e può avere la seguente struttura:
/* need this, because some autoconf tests rely on this (e.g. stpcpy)
* and it should be used for new programs
*/
#define _GNU_SOURCE 1
@TOP@
#undef M_DEBUG
#undef M_GUARD
#undef VERSION
#undef PACKAGE
#undef PRINTABLE_OS_NAME
#undef IS_DEVELOPMENT_VERSION
@BOTTOM@
#include "mydefine.h"
#endif
I #define e gli #undef sono direttive al compilatore di cui ora non ci occuperemo. Accentriamo invece la
nostra attenzione sulla stringa @TOP@.L'autoheader nel momento in cui trova questa stringa, copia tutte le
linee che la precedono nella parte iniziale del file [Link].h, che è stato elaborato durante la scansione da
parte di autoheader del file [Link]. Il programma autoheader svolge un simile procedura, quando
incontra la stringa @BOTTOM@, solo che in questo caso l'autoheader copia le linee dopo quella stringa e le
pone alla fine del file [Link].h.
#if HAVE_CONFIG
#include <config.h>
#endif
Salvate il tutto e ora siamo pronti per generare il nostro file configure, tramite i seguenti comandi:
[Link]:~$ aclocal
[Link]:~$ autoconf
[Link]:~$ autoheader
[Link]:~$ automake −a
Il file [Link] mostrato sopra è suddiviso in diverse sezioni, suddivisione che viene rispettata da tutti i
file [Link]. Queste sezioni sono:
• Inizializzazione
• Controllo programmi presenti nel sistema, da cui il vostro programma dipende
• Controllo librerie necessarie e presenti nel sistema
• Controllo degli header per la compilazione
• Controllo delle funzioni di libreria
Per ogni sezione si specificano delle macro (leggi regole di controllo), che servono a svolgere ogni singolo
controllo sulla configurazione richiesta dal programma per funzionare. Penso che abbiate già capito, che i
commenti nel file [Link] sono differenti rispetto ai Makefile tradizionali, dove erano rappresentati da
#. Qui invece i commenti si esprimono mediante la parola dnl, ovvero tutto ciò, che è specificato dopo la
parola dnl fino a fine linea viene ignorato dall'autoconf.
Iniziamo la descrizione del [Link] presentato, cercando di chiarire le cose passo dopo passo:
riga 1: dnl Process this file with autoconf to produce a configure script.
riga 2: AC_INIT(main.c)
riga 3: dnl Checks for programs.
riga 4: AM_CONFIG_HEADER(config.h)
riga 5: AM_INIT_AUTOMAKE(matrix,0.1)
riga 6: AC_PROG_CC
riga 7: AC_PROG_INSTALL
riga 8: dnl Checks for libraries.
riga 9: dnl Checks for header files.
riga 10:AC_HEADER_STDC
riga 11:if test $ac_cv_header_stdc = no; then
riga 12:AC_MSG_ERROR([Matrix richiede ANSI C])
riga 13:fi
riga 14:dnl Checks for typedefs, structures, and compiler characteristics.
riga 15:dnl Checks for library functions.
riga 16:AC_CHECK_FUNC(getline)
riga 17:AC_OUTPUT(Makefile)
• la riga 2 (AC_INIT(main.c)) imposta lo script configure in modo che controlli il file specificato tra
parentesi per assicurarsi che la directory corrente sia quella contente i file sorgente del
[Link] è la fase di inizializzazione.
• la riga 4 serve all'autoconf per generare lo script configure
Facciamone una breve descrizione. La riga 11 usa una variabile (simile a quelle dei makefile)
$ac_cv_header_stdc, che viene impostata durante l'esecuzione dello script configure. Questa variabile
corrisponde alla macro $AC_HEADER_STDC. Da notare che ogni macro ha una variabile simile, per
esempio la macro AC_PROG_FUNCS ha una variabile $ac_cv_prog_funcs associata. Durante l'esecuzione,
configure testa se la richiesta di una data macro è soddifatta o meno nel sistema e imposta la variabile
associata alla macro. Nelle righe sopra illustrate (11,12,13) si va a verificare la compatibilità con l'ANSI C, se
tale compatibilità è presente allora la $ac_cv_header_stdc sarà uguale a 'yes', altresí sarà uguale a 'no'. In
quest'ultimo caso l'esecuzione di configure sarà interrotta e apparirà sullo schermo il messaggio tra parentesi
quadre presente nella macro AC_MSG_ERROR.
È obbligo ora elencare un sottoinsieme delle macro più utilizzate e darne una breve descrizione nella
seguente tabella.
Variabile Descrizione
AC_CHECK_HEADERS(header1.h, Controlla nella directory standard di include, se gli header
header2.h, header3.h, ecc) specificati esistono
AC_CHECK_FILE(nomefile) Controlla se nel percorso corrente esiste il file nomefile
AC_CHECK_PROG(nome_eseguibile) Controlla se nel percorso corrente esiste il programma
nome_eseguibile
AC_CHECK_LIB(nome_libreria) Controlla se esiste la libreria nome_libreria nella directory
standard delle librerie.
AC_CHECK_FUNC(nome_func) Controlla se nelle librerie presenti esiste la funzione nome_func
Tabella 1.2 (n.b. la tabella è da ampliare)
Saltiamo la seconda fase, che consiste nel creare dei semplici file di testo secondo la struttura già descritta e
passiamo alla terza fase.
bin_PROGRAMS= matrix
matrix_SOURCES= main.c token.c
/* need this, because some autoconf tests rely on this (e.g. stpcpy)
* and it should be used for new programs
*/
#define _GNU_SOURCE 1
@TOP@
@BOTTOM@
#include "filedef.h"
La mia unica necessità era di specificare il _GNU_SOURCE al compilatore, per avere la massima
compatibilità con tutti gli standard esistenti e tutte le librerie. Poi ho incluso il mio file header, dove sono
contenute le #define.
[Link]:~$ aclocal
[Link]:~$ autoconf
[Link]:~$ autoheader
[Link]:~$ automake −a
• aclocal crea un file chiamato aclocal.m4. Questo file è utilizzato sia per scrivere le macro definite
dall'utente che dall'automake. Infatti automake usa la macro AM_INIT_AUTOMAKE, che non è
riconosciuta dall'autoconf, la cui definizione è posta in aclocal.m4.
• autoconf, autoheader, automake eseguono le seguenti elaborazioni:
..............
[Link] −−−−−>. .
aclocal.m4 −−−−−>. AUTOCONF .−−−−−−−−−−−> configure
. .
..............
..............
. .
acconfig.h −−−−−>. AUTOHEADER .−−−−−−−−−−−> [Link]
[Link] −−−−−>. .
..............
..............
. .
[Link] −−−−−>. AUTOMAKE .−−−−−−−−−−−> [Link]
File di Documentazione −−−−−>. .−−−−−−−−−−−> File di Documentazione
..............
C'è, solo da fare un piccolo appunto, prima di terminare questo paragrafo. Qualcuno di voi si chiederà il
significato dell'opzione −a data ad automake. Precedentemente avevamo parlato di file, che automake
aggiunge automanticamente che poi vanno editati, quali COPYING, INSTALL, ecc. Ebbene automake li
aggiunge solo se gli viene passata l'opzione −a, altresi da un messaggio di errore simile:
Note finali.
Ora abbiamo finito, il nostro pacchetto è pronto, creiamo il tarball, e nel caso in cui ritenessimo il nostro
programma un lavoro ben fatto, potremmo segnalarlo al [Link] mettendolo così a
disposizione di altri programmatori e/o utenti.
• Avviare il vostro programma, specificando tutto ciò che influisce sul suo comportamento.
• Fare in modo che il vostro programma si interrompa sotto date condizioni
• Esaminare quello che è accaduto, quando il vostro programma è stato interrotto.
• Cambiare le cose nel vostro programma, in modo che possiate sperimentare gli effetti delle correzioni
di un dato bug
Per usare lavorare con il GDB occorre produrre le informazioni necessarie al debugging nel formato specifico
del sistema. Nella maggior parte dei sistemi che usano il formato "stabs", l'opzione '−g' data al GCC, in fase
di compilazione abilita l'uso delle informazioni extra necessarie al debugging con il GDB. Ecco un esempio
di compilazione:
Ora per eseguire il programma fino al primo breakpoint o watchpoint è necessario digitare:
Note finali. 23
Programmare Linux
(gdb) run
Il lettore attento, ora si starà chiedendo che cosa sia un breakpoint o un watchpoint, vediamolo.
Breakpoint e Watchpoint.
Breakpoint
Un breakpoint fa in modo che il vostro programma si interrompa ogni volta che viene raggiunto un dato
punto. L'impostazione di un breakpoint è abbastanza flessibile, in quanto si possono specificare diverse
condizioni ad esso relative. Facciamo un piccolo schema relativo alle varie opzioni che possiamo dare al
comando break al fine di impostare un breakpoint.
Comando Descrizione
break In questo modo si imposta il breakpoint alla istruzione successiva, che
deve essere eseguita.
break nome_funzione Imposta un breakpoint alla funzione nome_funzione, dove
nome_funzione è una funzione del vostro programma.
break numero_linea Imposta un breakpoint, alla linea numero_linea del file corrente
break nomefile:nome_funzione Imposta un breakpoint, alla funzione nome_funzione del file sorgente
nomefile
break nomefile:numero_linea Imposta un breakpoint, alla linea numero_linea del file sorgente nomefile
breakif cond Imposta un breakpoint, con una condizione cond; valuta l'espressione
ogni volta, che viene raggiunta e si ferma se e solo se la condizione è un
valore diverso da zero.
Tabella 1.3
Molto probabilmente ora vorrete visualizzare tutti i breakpoints oppure lo stato degli stessi (compreso il loro
numero), basta fare allora:
Watchpoint
A differenza di un breakpoint, un watchpoint ferma il programma quando il valore di una data espressione
cambia.
Breakpoint e Watchpoint. 24
Programmare Linux
Potete gestire un watchpoint in maniera simile ad un breakpoint; potete quindi assegnarlo, abilitarlo, ottenere
le informazioni relative, disabilitarlo e cancellarlo con comandi molto simili. Per impostare un watch point, e
vedere le informazioni relative basta digitare:
Dove espressione, è una variabile del vostro programma sorgente. Il GDB interromperà l'esecuzione quando
l'espressione viene scritta dal programma e il suo valore cambia.
Comando Descrizione
enable numero_breakpoint Breakpoint abilitato
disable numero_breakpoint Breakpoint disabilitato
enable once numero_breakpoint Breakpoint abilitato una volta
enable delete numero_breakpoint Breakpoint abilitato per la cancellazione
Tabella 1.4
Comando Descrizione
set args Se il nostro programma accetta degli argomenti, questo
comando permette di specificarli in questo modo:
Il GDB e lo stack
Siamo ora in grado di utilizzare il GDB, ma ogni volta che il vostro programma è interrotto, si rende molto
utile capire quali sottofunzioni ha chiamato, tutto ciò per avere una piena comprensione dello stato del vostro
programma una volta interrotto.
Ogni volta che il vostro programma svolge una chiamata ad una funzione vengono generate delle
informazioni relative alla chiamata stessa. Tali informazioni includono la posizione della chiamata, gli
argomenti della chiamata e le variabili locali della funzione che è stata chiamata. Le informazioni vengono
salvate in un blocco di dati chiamato stack frame. Gli stack frame sono allocati in una regione di memoria
chiamata stack. Il GDB ci fornisce diversi comandi per interagire con lo stack, quello che viene usato di più e
il comando backtrace. Il backtrace mostra una linea per frame, per differenti stack frame, partendo dal
frame correntemente in esecuzione susseguito dal suo chiamante, continuando per tutto lo stack. Vediamo
come si applica:
Comando Descrizione
backtrace Stampa un backtrace intero dello stack, una linea per frame per ogni frame dello stack. Si
interrompe premendo CTRL+C.
backtrace Stampa un backtrace per i primi n frame dello stack.
n
backtrace Simile, ma stampa un backtrace per gli ultimi n frame dello stack. Tabella 1.6
−n
Detto questo ora siamo in grado di vedere la nostra sessione di esempio, che riassuma tutta la teoria finora
vista.
Sessione di esempio
Nella sessione di esempio, userò il carattere ## per indicare un commento che non fa parte della sessione
stessa.
[Link]:~$ make
gcc −g −c −Wall main.c
gcc −g −c −Wall token.c
gcc −g −o matrix main.o token.o
## avviamo il gdb
[Link]:~$ gdb matrix
Il GDB e lo stack 27
Programmare Linux
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i686−pc−linux−gnu"...
##
## impostiamo un breakpoint alla linea 23
(gdb) break 23
Breakpoint 1 at 0x8048478: file main.c, line 23.
##
## eseguiamo il programma fino alla linea 23.
(gdb) run
Starting program: /home/gzoppi/last/matrix
Il GDB e lo stack 28
Programmare Linux
32 input=NULL;
33 size=getline(&input,&dim,stdin);
34 stop=reserved_token(input,size);
35 } while (stop!=QUIT);
36 return EXIT_SUCCESS;
## disabilitiamo il breakpoint 2 (che è un watchpoint)
(gdb) disable 2
## ancora passo−passo
(gdb) step
Single stepping until exit from function getline,
which has no line number information.
main () at main.c:34
34 stop=reserved_token(input,size);
(gdb) step
reserved_token (stringa=0x80499c8 "LUIGI\n", dimensione=6) at token.c:24
24 char *tkn;
## Guardiamo i sorgenti della sottofunzione
(gdb) list
19 else return ID;
20 }
21
22 keyword reserved_token (char *stringa, int dimensione) {
23
24 char *tkn;
25 char *running;
26
27 keyword token;
28
#finiamo la sottofunzione
(gdb) finish
dafare
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
|nome(sezione) nome(sezione)|
| |
/ /
| |
| data numero_pagina|
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
.SH "descrizione"
Intestazione della sezione descrizione
.SS "descrizione"
Intestazione della sotto−sessione di "descrizione"
.B scritta
scritta in grassetto
.I scritta
scritta in corsivo
.BI a b a b a b a...
.IB a b a b a b a...
.RI a b a b a b a...
.IR a b a b a b a...
.RB a b a b a b a...
.BR a b a b a b a...
BI pone le a in grassetto e le b in corsivo
RI pone le a in roman e la le b in corsivo
IR pone le a in corsivo e le b in roman
RB pone le a in roman e le b in grassetto
BR pone le a in grassetto e le b in roman
etc.
.P
.LP
.PP
Tre sinonimi per le interruzioni di paragrafo
.TP colonne
termine
paragrafo...
.IP inizio
Inizia un paragrafo identato, l'argomento <it>inizio è presente vie
.RS
...
.RE
Definisce un regione identata.
Commandi generici
Queste macro appena descritte compongono un elenco completo di come puo essere fatta una man page, ma
effettivamente alcune di esse sono poco usate. Vediamo ora un esempio di man page.
.B ..."]
.SH DESCRIPTION
.I mioprogramma
Script bash che fa qualcosa di utile, e ha le seguenti opzioni:
.TP 5
f1
Descrivi la prima opzione
.TP
f2
Descrivi la seconda opzione
.P
Paragrafo con un esempio di utilizzo:
.br
.nf
.fi
.SH OPTIONS
.TP
.I −r
Fa qualcosa di utile.
.TP
.I −n
Opzione per non fare nulla
.SH AUTHOR
MioNome MioCognome
.SH SEE ALSO
utile(1), tools(2)
.SH DIAGNOSTICS
Programma utile.
.SH BUGS
E cosí abbiamo creato la nostra man page. Questa operazione poteva essere fatta anche mediante un
Makefile. Quasi tutti i programmi durante l'installazione creano la man page e poi la installano nella directory
di sistema, di solito /usr/man/catN, dove N è il numero di man page nel nostro caso 4.
Supponiamo di aver creato il nostro programma di elaborazioni di matrici, che chiameremo matrix, e questo
programma abbia una man page e un file di configurazione, chiamato [Link], che va posto nella directory
/etc. Per poter creare un rpm, contentente tali file è necessario :
Esempio di /etc/rpmrc.
Vediamo come puo essere settato il file di configurazione di RPM:
require_vendor: 1
distribution: Red Hat
require_distribution: 1
topdir: /usr/src/packs
vendor: NerSoft
packager: NerSoft Gestione Software <nrsof@[Link]>
signature: pgp
pgp_name:
pgp_path: /home/packages/.pgp
tmppath: /tmp
La linea 1, obbliga RPM a trovare una linea vendor, dove si specifica di solito il produttore del pacchetto. Le
linee:
Sono direttamente collegate poichè se la seconda è settata a 0, nella prima non è necessario specificare per
quale distribuzione debba essere creato il pacchetto. Tralasciamo le due linee successive, che sembrano
abbastanza chiare e passiamo ad optflags, li vengono specificati i flag da passare al compilatore per rendere il
programma ottimizzato per la data piattaforma, l'ottimizzazione viene fatta durante la compilazione del
pacchetto stesso. Le restanti linee servono per l'autenticazione del pacchetto. Oltre a queste opzioni per il file
/etc/rpmrc, ne esistono altre che potete scoprire con il comando : rpm −−showrc.
%description
Progetto di Laboratorio. Parser per l'elaborazioni di matrici.
%files
%config /etc/[Link]
Esempio di /etc/rpmrc. 33
Programmare Linux
/usr/bin/matrix
/usr/man/man4/matrix.4
3. Iniziamo a programmare
• espressioni
• istruzioni
• blocchi di istruzioni
• blocchi di funzioni
Espressioni
Una espressione e composta da operandi e operatori e all'interno di un'espressione non possono essere usate
parole chiavi. Non è lecito per esempio scrivere: c=auto+2
ESEMPIO 1. 2+3
ESEMPIO 2. d+z
ESEMPIO 3. b>a
ESEMPIO 4. 300
ESEMPIO 5. b=c+a
Saltiamo i primi quattro esempi, che sono banali somme, confronti o valori costanti e passiamo all'esempio 5.
Tale esempio significa:"Prendi il contenuto della variabile c, prendi il contenuto della variabile a, sommali e
ponili nella variabile b". Per capire quanto appena detto occorre la seguente definizione.
Definizione. Una variabile è una locazione di memoria, ove si possono scrivere e/o leggere dati. In C viene
rappresentata mediante un'identificatore alfanumerico.
Esempio
Le istruzioni
Un'istruzione è un comando C completo. Tutte le istruzioni terminano con il carattere ; . Esempio:
• Istruzione 1: a=1000;
• Istruzione 2: c=1;
• Istruzione 3: b=a+c;
I blocchi di istruzioni
I blocchi di istruzioni consistono in una o più istruzioni raggruppate tra un carattere di inzio ({) e uno di fine
(}), ad esempio:
if (a<b) {
c=a*b;
a=a+1;
}
Le istruzioni 36
Programmare Linux
In questo esempio il blocco di istruzioni è quello che segue la parola chiave if, ovvero:
c= a*b;
a= a+1;
Il significato di questo spezzone di codice C è:"Se il valore(contenuto) della variabile a è minore di quello
della variabile b, allora poni nella variabile c il valore di a moltiplicato per quello di b, ed aumenta il valore
della variabile a di 1". Supponiamo a=4 e b=10, allora sarebbe:
Blocchi di funzione.
Un blocco di funzione è composto da uno o più blocchi di istruzioni e da istruzioni combinate in modo da
svolgere un compito specifico. Durante lo sviluppo dei programmi, istruzioni e blocchi di istruzioni vengono
usati dalle funzioni per creare un singolo modulo per risolvere un singolo aspetto di un problema.
Esaminiamo la seguente funzione:
Linea Codice
1 int area_triangolo(void)
2 {
3 int base,area,altezza;
4 base=10;
5 altezza=5;
6 area=(base*altezza)/2
7 return area;
Blocchi di funzione. 37
Programmare Linux
8 } Tabella 1.7
La funzione area_triangolo restituisce un valore di tipo int, che sta per numero intero rappresentante l'area di
un triangolo di base=10. Notiamo ora la linea 3. Precedentemente avevamo parlato di variabili, e in questa
linea abbiamo dato il modo per definire una variabile: tipo_variabile nomevariabile;
Se le variabili come in questo caso sono dello stesso tipo, basta allora specificarle in questo modo:
tipo_variabile nomevariabile1, nomevariabile2, nomevariabile3,ecc..;
tipo1_variabile nomevar,.....;
tipo2_variabile nomevar,.....;
.............................;
.............................;
tipoN_variabile nomevar,.....;
Ritorneremo sui tipi nel prossimo capitolo, per ora mancano solo da spiegare di questa funzione: l'istruzione
return e il parametro void.
Per capire questa istruzione e il parametro void occorre dire che una funzione in un linguaggio di
programmazione ha un significato abbastanza simile alla matematica:
f:A−>B
Funzione da A in B
Una funzione prende dagli altri sottoprogrammi un insieme A di valori e restiuisce un insieme B di valori.
Nel caso A sia vuoto (come nel nostro esempio) si specifica void nei parametri della funzione:
int area_triangolo(void)
^^^^^^
Nel caso B sia vuoto si speficica void prima della definizione della funzione e si ommette l'istruzione return,
esempio:
void nome_funzione(void)
{
int base;
Blocchi di funzione. 38
Programmare Linux
base=0;
}
Nel caso in cui le nostre funzioni debbano restituire uno valore, occorre dichiarare nel prototipo il tipo del
valore che la data funzione restituisce, come fatto nella linea 1 della funzione area_triangolo, ed occorre usare
l'istruzione return prima di chiudere il blocco funzione, restituendo il valore elaborato dalla nostra funzione.
$ emacs primo.c
/* Primo programma in C */
#include<stdio.h>
int main(void) {
printf("Ciao Mondo!\n");
return 0;
}
Esempio 1.0
La prima cosa che notiamo nell'esempio soprastante sono i simoboli /* e */. Il primo ha il significato di
apri commento e il secondo di chiudi commento, vediamone un ulteriore esempio:
/*
Questo è un commento insensato:
secondo voi, chi è più bella:
Laetitia Casta, Cindy Crawford o Megan Gale ? */
Il compilatore ignora tutto ciò, che trova tra /* e */, queste coppie di caratteri sono chiamate deliminatori di
commento. I commenti, durante la stesura del codice, sono molto utili sia per ricordarci cosa fa il programma
che nella fase di debug. Si può infatti vedere facilmente come si comporta il programma, commentando una
parte di esso e poi ricompilandolo.
Una cosa importante da notare è che ogni commento aperto con /* deve essere chiuso con */, infatti in ANSI
C non è lecito scrivere commenti di questo tipo:
/*
Il programma analizza
/* le derivate ennesime */
*/
Notiamo ora la seconda linea dell'esempio 1.0, che è una direttiva al preprocessore. Infatti il codice di un
programma scritto in C può includere alcune istruzioni dirette al compilatore. Queste istruzioni sono dette
direttive al preprocessore. In parole povere, tutte le linee che iniziano con il carattere # sono direttive al
preprocessore, la nostra è appunto:
#include <stdio.h>
Il significato specifico di tale linea di programma è il seguente: "Cerca su disco (alla posizione
/usr/include) il file stdio.h e inserisci in questo punto del programma tutto ciò, che trovi su quel file". I
file *.h vengono anche chaimati header in quanto fanno riferimento aa una data libreria. Il file
stdio.h(stdio = standard input output) si usa in tutti i programmi, che richiedono una qualche forma di
immissione o emissione dati (leggi I/O, input/output dei dati), ovvero quasi la totalità dei programmi. Il file
stdio.h permette di includere nel programma le funzioni di input/output, a cui il programma può fare
riferimento, in questo esempio la routine di I/O a cui si fa riferimento è la printf. Osservate il seguente
esempio:
#include <stdio.h>
#include "stdio.h"
Apparentemente tra la prima e la seconda linea di codice, non v'è nessuna differenza, se escludiamo le
virgolette, ma dal punto di vista del compilatore la differenza è sostanziale.
Nel primo caso il file header, è posto nella directory standard degli header, /usr/include, invece nel
secondo è posto nella directory corrente. In generale possiamo osservare che:
• Le parentesi angolari, che precedono e seguono un file header indicano al preprocessore di cercare il
file header richiesto nella directory standard.
• Le virgolette, invece, indicano al preprocessore di cercare il file header nella directory corrente e poi
nella directory standard.
#include "/home/deneb/myio.h"
Andando avanti con l'esempio 1.0 troviamo la funzione int main(void) . Come dovreste aver già
capito questa funzione restituisce un valore intero e prende un valore nullo:
________________
void | |
Figura 1.7
Si noti che all'interno della funzione int main(void) abbiamo la chiamata ad un'altra funzione:
Questa è una funzione di I/O per cui richiede l'header , ed ha il compito di stamapare i caratteri compresi tra
" e " sullo schermo. Il carattere \n (newline) fa in modo che quando a fine stringa si vada a capo. Nella
printf, come in ogni altra funzione, tutto ciò che è compreso tra ( e ) costituisce argomento della funzione
stessa:
____________
| |
INPUT | |
Stringa "Ciao Mondo!" −−−−−−> | printf | OUTPUT
(stringa = insieme |____________|
finito di caratteri) || Operazione:
−−
Stampo su schermo "Ciao Mondo!"
e vado a capo.
Dopo la printf, restituiamo il valore EXIT_SUCCESS in quanto supponiamo che le operazioni siano state
svolte in maniera corretta.
Macro di uscita
Macro Valore
0
EXIT_SUCCESS
1 Tabella 1.8
EXIT_FAILURE
Osservate la Tabella 1.8. Essa presenta due macro definite dalla libreria GNU, e rappresentanti i valori di
uscita di un programma nel caso venga eseguito correttamente o nel caso vi siano errori. In Linux, è buona
pratica nella funzione principale (leggi main) specificare un valore di uscita per il programma. Per
definizione se il programma ha eseguito tutte le operazioni correttamente uscirà con valore 0, altresí con
valore 1. Le macro EXIT_SUCCESS e EXIT_FAILURE sono state create per migliorare la leggibiltà del
codice, infatti le istruzioni:
Macro di uscita 41
Programmare Linux
sono equivalenti.
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
FILE HEADER E DIRETTIVE AL PREPROCESSORE
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
DICHIARAZIONE STRUTTURE DATI AGGIUNTIVE
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
DICHIARAZIONE FUNZIONI DEFINITE DAL PROGRAMMATORE
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
MAIN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
IMPLEMENTAZIONE FUNZIONI DEFINITE DAL PROGRAMMATORE
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Figura 1.8
La Figura 1.8 da una descrizione generica della struttura di un programma C,vedremo nel corso del libro ogni
singolo aspetto sia delle strutture dati che delle direttive al preprocessore, le altre cose le abbiamo già iniziate
a vedere e implementare.
L'esecuzione di ogni programma, al di là della sua struttura, inizia dal main e prosegue discendendo per ogni
funzione e istruzione in esso contenuta fino a terminare il blocco funzione del main stesso. Esempio:
/* File Header */
#include <stdio.h>
int main(void)
{
int a;
a=quadrato(25);
printf("Valore del quadrato di 25: %d\n", a);
return EXIT_SUCCESS;
}
{
int quad;
quad=valore*valore;
return quad;
}
Esempio 1.1
− inizio −
|
|
|
− a=quadrato(25); −
| __________
| | |
−−−−−−−−>| quadrato |−−−−−−> |625 |
INPUT |__________| OUTPUT |____|
25 a
|
__|____
| printf|
|_______|
Stampa su schermo la stringa
Valore del quadrato di 25:
+ il valore di tipo intero
della variabile a. Poi vai
a capo
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Struttura della funzione quadrato.
− valore=25 −
|
|
return quad;
|625|
|___|
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Figura 1.9
La prima cosa che notiamo nell'esempio 1.1, è la dichiarazione della funzione quadrato di tipo intero che ha
come parametro una variabile intera e restituisce un valore intero, rappresentato dal quadrato dell'input stesso.
Bisogna ricordarsi, che le funzioni vengono viste in C come scatole nere, tutte le variabili dichiarate al loro
interno non hanno visibilità all'esterno, ovvero se io usassi la variabile quad all'esterno della funzione
quadrato si verificherebbero errori, a meno che tale variabile non venga dichiarata nuovamente localmente.
Durante l'esecuzione, come è visibile dallo schema, alla variabile a viene assegnato il valore della funzione
quadrato e poi stampato con la:
Questa significa :stampa la stringa Valore del quadrato di 25 e aggiungi ad essa il valore di tipo intero della
variabile a. Il simbolo %d sta appunto ad indicare il valore di tipo intero della variabile a. Per cui l'output su
video del programma è:
Abbiamo ora finito questo paragrafo e presentiamo alcuni esercizi, che siete già in grado di svolgere.
Esercizi.
Ciao,
quando
ti ciucci il calzino?
Usando prima un'unica chiamata a printf, e poi invece tre chiamate diverse a printf.
2. Riprendere l'esempio di funzione area_triangolo, modificandola in questo modo:
Stampare nella funzione principale l'area triangolo, avendo assegnato i valori base=10; e altezza=25;.
3. Modificare l'esempio 1.1, il corpo della funzione principale (main) affinche alla funzione quadrato
sia passata una variabile anziche il valore 10. Tale variabile deve precedentemente dichiarata e
inizializzata a 10.
4. Indicare riga per riga gli errori presenti nel seguente programma:
#include "stdio.h"
*/ Li troverai gli errori? */
int func2(int valore1, int valore2);
Main()
{
int b;
a=func(b);
b=4;b=b+a;
a=func2(a,b);
return EXIT_SUCCESS;
}
void func(int value)
{
int c;
c=value*4;
return 4;
}
int func2(int valore1, int valore2)
{
Esercizi. 44
Programmare Linux
int c;
c= valore1+valore2;
}
/* Gli hai trovati gli errori? /*
4. ChangeLog
5. TO DO (Da fare)
DA FARE:
* Aggiungere ulteriori macro alle tabelle dell'autoconf, ed dell'automake
* Completare gli esempi sui makefile , comprese le estensioni GNU
(qualche volontario?)
* Rifare tutti gli schizzi ascii, in disegni fatti con GIMP
* Revisione e correzione bozze su Emacs
* Iniziare tutorial su Emacs
* Iniziare tutorial sul DATA Display Debugger
* Ampliare parte sul RPM.
* elenco di risorse on line e non inerenti gli strumenti di
programmazione descritti(libri e siti, tanto per intenderci)
* Spiegare i tipi di dati
* Spiegare le direttive al preprocessore