PDA

View Full Version : [C]Scrivere un make file


domenico88
08-01-2010, 19:48
Ciao a tutti....non bastonatemi per il tipo del linguaggio tra parentesi...ma non sapevo che mettere....

Mi date delle dritte su come capire e scrivere il makefile

CC=/usr/bin/gcc
OGGETTI= main.o command.o display.o insert.o

pippo : main.o command.o display.o insert.o
${CC} -o $@ ${OGGETTI}
main.o : main.c defs.h
${CC} -c $?
command.o : command.c defs.h command.h
${CC} -c $?
display.o : display.c defs.h buffer.h
${CC} -c $?
insert.o : insert.c defs.h buffer.h
${CC} -c $?
clean :
rm pippo ${OGGETTI}


Es su questo makefile Le macro interne sono
$@ = il target corrente :confused:e quale sarebbe??
$? = FIle di dipendenza che sono più recenti del target corrente :confused:

grazie per l'attenzione...

Teo@Unix
08-01-2010, 22:12
Ciao,
il makefile non è altro che uno script, quindi un file dove metti le istruzioni che dovresti riscriverti tutte le volte che vuoi compilare ecc...
ma questo mi sembra che già lo hai capito.:D

Da quel che ho visto si tratta di uno script interpretabile da una shell Unix.

Forse quel ti confonde sono "$@" e "$?"...

Il primo, nei sistemi Unix rappresenta un array di stringhe che contiene tutti gli argomenti che seguono un comando shell... (uno per stringa) nel tuo caso se digito make FileElf A B C ...

nello script "$@" è un array di stringhe e se lo stampo ottengo:
FileElf
A
B
C

quindi la prima riga:
${CC} -o <argomenti passati> ${OGGETTI}


Il secondo, contiene un intero il cui valore dipende dall'esito del comando precedente.... 0 se il comando precedente è stato eseguito con successo.
O un numero intero positivo che specifica il tipo di errore se il comando ha fallito


$? = FIle di dipendenza che sono più recenti del target corrente :confused:


però qui non ho capito a cosa servirebbe....
o magari mi sfugge ora guardandolo velocemente....

domenico88
09-01-2010, 12:45
il makefile non è altro che uno script, quindi un file dove metti le istruzioni che dovresti riscriverti tutte le volte che vuoi compilare ecc...
ma questo mi sembra che già lo hai capito.:D

uhm insomma...cioè serve per non compilare e ricompilare tutti i sorgenti uno per volta?
Non mi è molto chiaro..:rolleyes:

Da quel che ho visto si tratta di uno script interpretabile da una shell Unix.


Forse quel ti confonde sono "$@" e "$?"...

Il primo, nei sistemi Unix rappresenta un array di stringhe che contiene tutti gli argomenti che seguono un comando shell... (uno per stringa) nel tuo caso se digito make FileElf A B C ...

:help: :help:

Mica sai dove posso trovare qualche esempio di make file???:help:

Teo@Unix
09-01-2010, 13:27
:help: :help:

Mica sai dove posso trovare qualche esempio di make file???:help:

Ok, scusa...

ecco alcuni link dove puoi trovare esempi e spiegazioni...
http://www.pluto.it/files/journal/pj9811/makefile.html
http://programmazione.html.it/guide/lezione/4086/lutility-make-ed-i-makefile/


cmq ti assicuro che non è molto complicato come sembra. Magari inizia con alcuni esempi semplici... tipo questo:

# Compiler gcc version 4.3.3

CC = gcc
SOURCES = firstdump.c fd_functiones.c IPopt.c TCPopt.c
LIB = pcap
PARAM = -g -v -static

EXUTABLE = FirstDump



all:
$(CC) $(PARAM) $(SOURCES) -l$(LIB) -o $(EXUTABLE)

clean:
rm -f $(EXUTABLE)

clean_all:
rm -f $(EXUTABLE) *.o* *~ *.gch

compile_source_only:
$(CC) $(PARAM) -c $(SOURCES)

link:
$(CC) $(PARAM) firstdump.o -l$(LIB) -o $(EXUTABLE)

come vedi, prima ho dichiarato una serie di variabili, che contengono sorgenti librerie, parametri e tutto quello che potrebbe servirmi per la compilazione...

Puoi così crearti delle stringhe etichettate che eseguiranno le operazioni. Quando incontri il simbolo "$" significa che la variabile posta di seguito deve essere interpretata per il suo contenuto, così la stringa "$(PARAM)" per la shell sarà: "-g -v -static". Dovrebbe esserti chiaro quindi che quando esegui "make etichetta". La shell andrà a cercarsi le operazioni etichettate con etichetta e le eseguirà.
Se dai solo "make" di default viene cercata l'etichetta "all". Difatti molti programmi sotto linux si compilano proprio con "make" seguito da "all", o solo "make"

Per esempio nel makefile che ti ho postato, se do "make clean"
la shell eseguirà:
rm -f $(EXUTABLE)
ovvero:
rm -f FirstDump
ripulendo la soluzione del programma.

khelidan1980
09-01-2010, 14:02
uhm insomma...cioè serve per non compilare e ricompilare tutti i sorgenti uno per volta?
Non mi è molto chiaro..:rolleyes:


Mi sfugge una cosa, ti sei messo a scrivere un make file senza sapere a cosa serva un make file? :mbe:

domenico88
09-01-2010, 15:11
Mi sfugge una cosa, ti sei messo a scrivere un make file senza sapere a cosa serva un make file? :mbe:

No no no...:D quello che ho postato io era un esempio scritto sulle mie slide dell'uni...:D

ndakota
09-01-2010, 15:17
No no no...:D quello che ho postato io era un esempio scritto sulle mie slide dell'uni...:D

Per che esame, se posso chiedere?

domenico88
09-01-2010, 15:23
Comeeee non puoi chiedere!:D

Devo fare un esame di Algoritmi e strutture dati, che contiene anche un modulo di ambienti di programmazione...tipo scrivere un makefile per il programma assegnato, scope statico e dinamico, conversioni in floating point , creazione di librerie(che ancora non ho fatto!:doh: ) ecc...

cmq ora mi metto un pò e vediamo di capirlo...:D

domenico88
09-01-2010, 16:19
# Compiler gcc version 4.3.3

CC = gcc
SOURCES = firstdump.c fd_functiones.c IPopt.c TCPopt.c
LIB = pcap
PARAM = -g -v -static

EXUTABLE = FirstDump



all:
$(CC) $(PARAM) $(SOURCES) -l$(LIB) -o $(EXUTABLE)

clean:
rm -f $(EXUTABLE)

clean_all:
rm -f $(EXUTABLE) *.o* *~ *.gch

compile_source_only:
$(CC) $(PARAM) -c $(SOURCES)

link:
$(CC) $(PARAM) firstdump.o -l$(LIB) -o $(EXUTABLE)

come vedi, prima ho dichiarato una serie di variabili, che contengono sorgenti librerie, parametri e tutto quello che potrebbe servirmi per la compilazione...

Puoi così crearti delle stringhe etichettate che eseguiranno le operazioni. Quando incontri il simbolo "$" significa che la variabile posta di seguito deve essere interpretata per il suo contenuto, così la stringa "$(PARAM)" per la shell sarà: "-g -v -static". Dovrebbe esserti chiaro quindi che quando esegui "make etichetta". La shell andrà a cercarsi le operazioni etichettate con etichetta e le eseguirà.
Se dai solo "make" di default viene cercata l'etichetta "all". Difatti molti programmi sotto linux si compilano proprio con "make" seguito da "all", o solo "make"

Per esempio nel makefile che ti ho postato, se do "make clean"
la shell eseguirà:
rm -f $(EXUTABLE)
ovvero:
rm -f FirstDump
ripulendo la soluzione del programma.

grazie teo sei stato gentilissimo...:D


Cmq delle cose non mi sono chiare....Tipo la shell?Non so che cosa sia...

Cmq per il resto...
PARAM = -g -v -static ad esempio
-g -v -static che cosè?

nel clean
rm -f $(EXUTABLE)
cosa significa?

Dopo la Variabile $(LIB) c'è -o cosa significa?

Scusa per tutte ste domande ma ho le idee un pò cofuse su queste cose...
ciao

Teo@Unix
09-01-2010, 16:50
Cmq delle cose non mi sono chiare....Tipo la shell?Non so che cosa sia...

La "shell" è come il "promt dei comandi" di win nei sistemi Unix,Linux e derivati.

PARAM = -g -v -static ad esempio
-g -v -static che cosè?

questi sono delle opzioni che passo al compilatore.
"-g" specifica a gcc di includere le informazioni di debug nell'eseguibile. Questo mi permetterà di poter fare il debug del programma.
"-v" significa "verbose" ovvero l'ouput del compilatore sarà più dettagliato (diciamo che se non vuoi vedere tutto quello che fa il compilatore non serve)
"-static" indica di linkare le librerie in modo statico. E' importante se vuoi utilizzare il programma in altri pc senza portarti dietro le librerie. Tutte le funzioni delle librerie saranno già incluse nel file eseguibile e non si avranno problemi di dipendenza.


rm -f $(EXUTABLE)
cosa significa?

è un comando Unix che significa cancella in modo forzato se è necessario i file specificati dall'etichetta (saranno gli eseguibili...)


Dopo la Variabile $(LIB) c'è -o cosa significa?

...:mbe: ...mi vien da pensare che non hai mai compilato quindi...
"-o" specifica che deve essere eseguita anche la fase di link finale e l'eseguibile deve essere creato con il nome che segue. Nell'esempio il nome sarà "FirsDump" specificato da "EXUTABLE". Ma ora dovrebbe esserti chiaro.

domenico88
09-01-2010, 19:06
grazie grazie chiarissimo:D
Ma ci sono delle limitazioni se non ho mai compilato???
Come dovrei fare?

domenico88
09-01-2010, 19:27
Non ho capito una cosa essenzialmente...:rolleyes:
Quando ad esempio ho un file sorgente prova.c per compilarlo con l'aggiuta di opzioni specifiche come devo fare???

Teo@Unix
09-01-2010, 20:51
no non c'è proprio nessuna limitazione se non hai mai compilato....

però dovresti fare un pò di pratica.... prima di scrivere makefile,
questi diventano molto utili solo quando il programma è complesso ed hai più moduli da assemblare.

se hai un sorgente per esempio "prova.c" e ammettiamo anche il suo header "prova.h", per creare il programma eseguibile occorre procedere così:

innanzi tutto se nel file .c vi è la definizione #include "prova.h"
possiamo considerare anche solo il file .c ( questa è la situazione più comune, il file .h basta che si trova nella stessa directory o dove dice la direttiva include... )

dalla shell Linux:
:~$ gcc prova.c -v -g prova.c -o prova

dove come ho detto, -v aumenta il livello di dettagli (facoltativo)
-g include info per il debug (a mio parere è molto utile quindi)
-o indica di creare il programma eseguibile di nome prova

sempre nella shell per provare il tuo programma darai

:~$ ./prova

quindi a questo livello il makefile non serve a molto...

ammettiamo tu abbia 20 file sorgente .c ...... scrivendoti il makefile i comandi completi di compilazione li scriverai una volta:) ....

Se lavori su Linux (che è l'ideale per capire) ti conviene studiarti un pò la shell Linux.... in modo che sai muoverti nel sistema.... e dare i comandi.

domenico88
12-01-2010, 13:43
ciao raga mi riallaccio ad un 3d precedente....allora ho scritto un makefile per il seguente esercizio....


devo scrivere un makefile con
un target main utilizzato per generare l'eseguibile con nome prova1 a partire dai file : bool.h list.h list.c info.h info.c prova1.c

main è il target richiamato quando viene invocato make senza parametri
La compilazione deve essere effettuata con il compilatore gcc in modo da visualizzare tutti i warning e con il livello di ottimizzazione 3

poi usare il target clean per eliminare tutti i file oggetto generati precedentemente

allora io l'ho fatto così


#Makefile per prova1

CC = gcc
CFLAGS = -wall -g
OPTIMIZE = -03
OBJECTS = prova1.o list.o info.o

all: main

main:
$(CC) $(CFLAGS) $(OPTIMIZE) $(OBJECTS) -o prova1
prova1.o: list.h

list.o: list.h
info.o: info.h bool.h

clean:
rm prova1 $(OBJECTS)


per Teo....dammi un consiglio su questo make:help: :D

Grazie a tutti per l'attenzione:D

Teo@Unix
12-01-2010, 15:41
#Makefile per prova1

CC = gcc
CFLAGS = -wall -g
OPTIMIZE = -03
OBJECTS = prova1.o list.o info.o

all: main

main:
$(CC) $(CFLAGS) $(OPTIMIZE) $(OBJECTS) -o prova1
prova1.o: list.h

list.o: list.h
info.o: info.h bool.h

clean:
rm prova1 $(OBJECTS)


per Teo....dammi un consiglio su questo make:help: :D


i parametri mi sembrano ok, non so perchè utilizzi i file oggetto, non è più semplice usare i .c e non considerare gli header?

innanzi tutto se nel file .c vi è la definizione #include "prova.h"
possiamo considerare anche solo il file .c ( questa è la situazione più comune, il file .h basta che si trova nella stessa directory o dove dice la direttiva include... )

..cioè io farei come ho fatto nell'esempio che ti ho postato, così ho anche la possibilità di non eseguire la fase di link... però vedì tu ...

metterei poi una variabile "SOURCES" dove indicherò i moduli .c e anche per l'eseguibile "EXUTABLE"

quindi clean: mi verrebbe da farlo cosi:
"rm -f $(EXUTABLE) *.o* *~ *.gch"

nel makefile devi ridurre al minimo tutti i riferimenti diretti, allora avrai un make file veramente utile)
alla fine il principio di un makefile è proprio questo; che faccia il suo sporco lavoro e che ci dia il meno da fare possibile nel caso cambiamo qualcosa nel progetto.

potresti aggiungere anche variabili vuote, nella prima parte potresti dichiarare ad esempio "LIB", che in questo caso lasci nulla, ma che includerai come variabile dentro le procedure.
potrebbe servire poi quando al programma vengono aggiunte librerie... ed eviti di dover poi andare a cercare tutti i posti dove serviva indicarle, facendoti risparmiare fatica e tempo... (questo era solo per dire come procedere in generale)

domenico88
12-01-2010, 16:05
Grazie:D

Quindi invece di inizializzare una variabile OBJECTS potrei direttamente farlo con i sorgenti e togliere gli header quindi
SOURCES = prova1.c info.c list.c

e il clean farlo così:
rm -f $(EXUTABLE) *.o* *~ *.gch*
ma che differenza c'è senza quei parametri dopo l'exutable?

Teo@Unix
12-01-2010, 16:17
si, tra l'altro, ora che guardo il tuo esempio, non funzionerebbe perchè gli header non contengono e non devono contenere la dichiarazione #include "file.c" ....

nel makefile e nella compilazione in generale, i file header devi "dimenticarli":)

i parametri *.o *~* *.gch
servono per rimuovere a prescindere dal nome tutti i file oggetto (.o), file di backup (finale con ~ ) e gch. Ho utilizzato le espressioni regolari (regexp)... semmai dacci un occhio, cmq a scopo di non mettere troppa carne al fuoco posticiperei le regexp.

domenico88
12-01-2010, 16:46
quindi potrei farlo così:

CC = gcc
OPTIMIZE = -03
CFLAGS = -wall -g
LIB =
SOURCES = prova1.c info.c list.c
EXUTABLE = prova1

all: main

main:
$(CC) $(CFLAGS) $(OPTIMIZE) $(SOURCES) -o $(EXUTABLE)

clean:
rm -f $(EXUTABLE) *.o* *~ *.gch*


Quindi gli header vengono trovati automaticamente a partire dai .c?

Teo@Unix
12-01-2010, 17:34
quindi potrei farlo così:

CC = gcc
OPTIMIZE = -03
CFLAGS = -wall -g
LIB =
SOURCES = prova1.c info.c list.c
EXUTABLE = prova1

all: main

main:
$(CC) $(CFLAGS) $(OPTIMIZE) $(SOURCES) -o $(EXUTABLE)

clean:
rm -f $(EXUTABLE) *.o* *~ *.gch*


Quindi gli header vengono trovati automaticamente a partire dai .c?

Se i file .c contengono #include "header.h"; assolutamente si.

Direi che va bene, in futuro se hai necessità di aggiungere librerie o moduli dovrebbe esserti sufficiente andare a toccare solo le variabili all'inizio.
In questo semplice caso non ti darebbe questo gran vantaggio, ma nel caso di progetti complessi, si.

P.S.
per il clean .gch non deve finnire con un'altro asterisco, basta: *.gch