[C++] makefile

di il
10 risposte

[C++] makefile

Ciao a tutti,
eccomi a chiedere info su quel che dovrebbe essere la base, eppur così chiaro non è.
Ho provato a fare una ricerca se l'argomento era già stato trattato, ma non ho trovato niente, così come le guide, il manuale di GNU e i vari tutorial che ho trovato mi hanno lasciato perplesso (evidentemente son gnucco)

Finito il programma, mi sto dedicando a migliorare il makefile. Prima scrivevo una versione estremamente rudimentale che farebbe inorridire ogni purista (praticamente ogni volta ricompilava tutti gli oggetti), adesso, avendo diversi file da compilare ogni volta (sono circa 8 .cpp) ho deciso di imparare a far le cose fatte bene.
Questo è il mio codice:

CC: =g++

GRAPHLIBS: -lglut -lGL -lGLU
MY_CLASSES.O: graphic.o income.o interface.o keyboard.o noteinfo.o opening.o record.o savenload.o
MY_CLASSES.H: graphic.h income.h interface.h keyboard.h noteinfo.h opening.h record.h savenload.h


graphic.o: graphic.cpp $(MY_CLASSES.H);
        $(CC) -c graphic.cpp -o graphic.o

tastiera_main.o: tastiera_main.cpp $(MY_CLASSES.H); 
        $(CC) -c tastiera_main.cpp -o tastiera_main.o

compila: $(MY_CLASSES.O) tastiera_main.o
        $(CC) tastiera_main.o $(MY_CLASSES.O) $(GRAPHLIBS) -o compiled


esegui: tastiera_main

Allora, ho un po' di punti che mi piacerebbe capire:
-Al momento i singoli oggetti me li crea (nel codice riportato ho tenuto solo graphic.o e tastiera_main.o per questioni di leggibilità sul forum, nel makefile che ho scritto ci sono quelli relativi a tutte le classi), quando vado a dire
make compila
invece compare una valangata di errori 'undefined reference' in tastiera_main.o... (se compilo senza makefile funziona)
Evidentemente c'è qualcosa che non va, eppure mi sembra di avergli passato i file che deve compilare (quelli contenuti in $(MYCLASSES.O) e tastiera_main.o). Che erroraccio sto facendo?

-che utilità ha scrivere $(CC) al posto di g++? Ho visto che l'oggetto lo crea anche se commento la prima riga del makefile
#CC: g++
, quindi comincio a pensare che quella dichiarazione iniziale sia inutile.

-perchè se compilo senza makefile da g++ non devo includere i .h, e nel makefile per creare i signoli oggetti sì? Con g++ io scrivo
g++ funzioni_varie.cpp main.cpp -o main
.

Se mi vengono in mente altre cose continuerei a chiedere qui, spero non sia da considerarsi troppo "didattica" la discussione.

Grazie in anticipo!

10 Risposte

  • Re: [C++] makefile

    Ciao,

    perché non ti installi autoconf automake e autotools così non smadonni nei config/Makefile(s) ?
    Il vantaggio che otterresti è che la tua applicazioni si installerebbe ovunque e comunque potresti sempre implementare il Makefile per fargli fare cose extra tipo il packaging per la tua distro o la push se usi git ... eccetera eccetera

    edit:errata
    volevo dire libtool non autotools
  • Re: [C++] makefile

    Ciao ixamit, grazie della risposta!
    Allora, ci stavo seriamente pensando a installare automake, non è difficile poi da usare no?
    In ogni caso prima di installarlo ho intenzione di capire come scriverlo io, per un paio di motivi:
    in questo periodo sono dell'idea che un po' di gavetta non fa mai male, se capisco come scriverlo poi posso sempre passare ad automake (e lo farò ), però se succede qualcosa (ad es., devo compilare su un computer su cui manca e non posso installarlo, situazione tipica dei laboratori universitari) riesco a cavarmela lo stesso. Senza essere così pessimisti, diciamo che è bello anche imparare queste cose
    Poi, altro motivo, è che settimana prossima vorrei fissare l'esame di informatica: dovendo presentare un progetto, ho carta bianca sulle librerie da usare e i metodi per farlo, però mi piace di più l'idea di andare lì con il mio bel makefile dimostrandogli di averlo capito e di saperlo usare.

    Ripeto, con questo accolgo più che volentieri il tuo suggerimento, non fraintendermi, ci tengo solo a fare tutte e due le cose! (Poi vedrai che il mio prossimo thread sarà "Aiuto con autoconf/automake" )
  • Re: [C++] makefile

    Mi sembra corretto, condivido.

    Style { HdS619 } ha pubblicato una piccola guida proprio sul Makefile. Se vai sul suo sito la trovi nella sezione Documenti (http://www.hds619.net/?ref=documents&sub=show_article&id=makefile)

    Da quel che vedo nel tuo caso mi sembra che manchi il rule del binario e nella construzione degli oggetti potresti applicare delle logiche generali in modo da ereditarle in in altri progetti, tipo:
    
    $(SRCDIR)%.o:$(SRCDIR)%.c
            $(CC) -c $(DEBUG) $(CFLAGS) -I$(INCDIR) -o $@ $<
    
    poi, se dici che a manina ti compila e in make no, basta vedere le differenze, magari è semplicemente un INCLUDE...
    non è difficile poi da usare no?
    Direi che è molto più complicato di un Makefile... soprattutto all'inizio
  • Re: [C++] makefile

    Grazie per il link, lo studio volentieri! In che senso manca il rule del binario?

    Aggiornamenti: ho guardato il link e ho capito già di più, ho provato a riscrivere il makefile seguendo le regole lì presenti ma niente... gli stessi errori di prima. I singoli oggetti me li crea benissimo, se digito
    make compile
    l'errore è 'make: *** No rule to make target `compile'. Stop.'
    Se digito
    make TARGET_EXECUTABLES
    mi vengono fuori i seguenti errori
    
    g++ -c tastiera_main.cpp -o tastiera_main.o
    g++  tastiera_main.o -o TARGET_EXECUTABLES 
    tastiera_main.o: In function `main':
    tastiera_main.cpp:(.text+0x15): undefined reference to `interface::Initialize()'
    tastiera_main.cpp:(.text+0x1a): undefined reference to `graphic::Initialize()'
    tastiera_main.cpp:(.text+0x32): undefined reference to `opening::opening()'
    tastiera_main.cpp:(.text+0x5b): undefined reference to `graphic::m_graph'
    tastiera_main.cpp:(.text+0x73): undefined reference to `glutInit'
    tastiera_main.cpp:(.text+0x7d): undefined reference to `glutInitDisplayMode'
    tastiera_main.cpp:(.text+0x8c): undefined reference to `glutInitWindowSize'
    tastiera_main.cpp:(.text+0x9b): undefined reference to `glutInitWindowPosition'
    tastiera_main.cpp:(.text+0xa5): undefined reference to `glutCreateWindow'
    tastiera_main.cpp:(.text+0xab): undefined reference to `graphic::window'
    tastiera_main.cpp:(.text+0xb0): undefined reference to `graphic::m_graph'
    tastiera_main.cpp:(.text+0xba): undefined reference to `graphic::display()'
    tastiera_main.cpp:(.text+0xbf): undefined reference to `glutDisplayFunc'
    tastiera_main.cpp:(.text+0xc4): undefined reference to `graphic::m_graph'
    tastiera_main.cpp:(.text+0xce): undefined reference to `graphic::reshape(int, int)'
    tastiera_main.cpp:(.text+0xd3): undefined reference to `glutReshapeFunc'
    tastiera_main.cpp:(.text+0xd8): undefined reference to `interface::interf'
    tastiera_main.cpp:(.text+0xe5): undefined reference to `interface::key_func()'
    tastiera_main.cpp:(.text+0xea): undefined reference to `glutMainLoop'
    collect2: ld returned 1 exit status
    


    Allego il nuovo makefile:
    
    CC = g++
    
    GRAPHLIBS: -lglut -lGLU -lGL
    
    CLASSES.O: graphic.o income.o interface.o keyboard.o noteinfo.o opening.o record.o savenload.o
    
    CLASSES.H: graphic.h income.h interface.h keyboard.h noteinfo.h opening.h record.d savenload.h
    
    compile:= $(TARGET_EXECUTABLES)
    
    %.o: %.cpp
            $(CC) -c $< -o $@
    
    TARGET_EXECUTABLES: $(CLASSES.O) tastiera_main.o
            $(CC) $(GRAPH_LIBS) $< -o $@ 
    
    clean: $(CLASSES.O)
            rm -f *.o
    
    Qualche anima pia riesce a spiegarmi per favore queste due cose?
    - il perchè delle undefined reference, posto che ogni .cpp include i .h giusti
    - perchè se lancio make compile non ha niente da fare

    Grazie ancora a tutti della pazienza!
  • Re: [C++] makefile

    Dunque il problema e' il linker...
    nel Makefile la variabile delle librerie l'hai scritto male, guarda bene una e' estesa, l'altra ha un underscore tra graph_libs
    scusa ma non riesco a scrivere su disp mobile, comunque un errore di distrazione

    edit: ...inoltre devi aggiungere gli oggetti.
  • Re: [C++] makefile

    Ciao eugen,

    ti faccio un esempio di Makefile. Prima creo una simulazione di ambiente:
    
    max@studio:~> mkdir foo && cd foo
    max@studio:~/foo> for i in a b c; do echo "#define $i" > "$i.cpp"; touch "$i.h"; done
    max@studio:~/foo> ll
    totale 12
    -rw-r--r-- 1 max users 10 14 ott 12.16 a.cpp
    -rw-r--r-- 1 max users  0 14 ott 12.16 a.h
    -rw-r--r-- 1 max users 10 14 ott 12.16 b.cpp
    -rw-r--r-- 1 max users  0 14 ott 12.16 b.h
    -rw-r--r-- 1 max users 10 14 ott 12.16 c.cpp
    -rw-r--r-- 1 max users  0 14 ott 12.16 c.h
    max@studio:~/foo> 
    
    Poi scriviamo un Makefile di fantasia per provare. Fai attenzione ai <TAB> usando copia/incolla. Non mi andava di lanciare il compilatore per cui ho settato CC per farmi un ECHO, in fondo a noi serve solo vedere quello che fa :
    
    FOO_SRC = a.cpp b.cpp c.cpp
    FOO_OBJ = $(FOO_SRC:.cpp=.o)
    FOO_LIB = "-lfoo1 -lfoo2 -lfoo3"
    FOO_INC = "-I. -I../../myinclude"
    BIN = foo
    CC  = @echo "g++"
    
    $(BIN): $(FOO_OBJ)
        $(CC) foomain.c $(FOO_OBJ) $(FOO_LIB) -o $(BIN)
    
    .cpp.o:
        $(CC) -c $(CXXFLAGS) $< -o $@
    
    a.o : a.cpp a.h
        $(CC) -c $(CXXFLAGS) $(FOO_INC) -DFOO_A a.cpp
    
    b.o : b.cpp b.h
        $(CC) -c $(CXXFLAGS) $(FOO_INC) -DFOO_B b.cpp
    
    all: $(BIN) env hello
    
    env:
        @echo "CC=$(CC)"
        @echo "FOO_SRC=$(FOO_SRC)"
        @echo "FOO_OBJ=$(FOO_OBJ)"
        @echo "FOO_LIB=$(FOO_LIB)"
        @echo "FOO_INC=$(FOO_INC)"
        @echo "BIN=$(BIN)"
    
    hello:
        @echo "Hello World"
    
    Dopo essermi creato delle variabili di comodo, stabilisco le dipendenze nei singoli ruoli. La forma è:
    
    target : prerequisito
    <tab>comando
    <tab>...
    
    Se non abbiamo fatto errori logici possiamo provarlo:
    
    max@studio:~/foo> 
    max@studio:~/foo> # simuliamo le singole compilazioni
    max@studio:~/foo> make a.o
    g++ -c -I. -I../../myinclude -DFOO_A a.cpp
    max@studio:~/foo> make b.o
    g++ -c -I. -I../../myinclude -DFOO_B b.cpp
    max@studio:~/foo> make c.o
    g++ -c c.cpp -o c.o
    max@studio:~/foo> # ora creiamo il binario
    max@studio:~/foo> make
    g++ -c -I. -I../../myinclude -DFOO_A a.cpp
    g++ -c -I. -I../../myinclude -DFOO_B b.cpp
    g++ -c c.cpp -o c.o
    g++ foo.c a.o b.o c.o -lfoo1 -lfoo2 -lfoo3 -o foo
    max@studio:~/foo>
    max@studio:~/foo> #eseguiamo un singolo rule
    max@studio:~/foo> make hello
    Hello World
    max@studio:~/foo>
    max@studio:~/foo> #eseguiamo all 
    max@studio:~/foo> make all
    g++ -c -I. -I../../myinclude -DFOO_A a.cpp
    g++ -c -I. -I../../myinclude -DFOO_B b.cpp
    g++ -c c.cpp -o c.o
    g++ foo.c a.o b.o c.o -lfoo1 -lfoo2 -lfoo3 -o foo
    CC=@echo g++
    FOO_SRC=a.cpp b.cpp c.cpp
    FOO_OBJ=a.o b.o c.o
    FOO_LIB=-lfoo1 -lfoo2 -lfoo3
    FOO_INC=-I. -I../../myinclude
    BIN=foo
    Hello World
    
  • Re: [C++] makefile

    Ciao ixamit,
    grazie dell'aiuto. Ho corretto l'errore di battitura e ho aggiunto gli oggetti in TARGET_EXECUTABLES, l'errore in compilazione rimane...
    
    CC = g++
    
    GRAPHLIBS: -lglut -lGLU -lGL
    
    CLASSES.O: graphic.o income.o interface.o keyboard.o noteinfo.o opening.o record.o savenload.o
    
    CLASSES.H: graphic.h income.h interface.h keyboard.h noteinfo.h opening.h record.d savenload.h
    
    compile:= $(TARGET_EXECUTABLES)
    
    %.o: %.cpp $(CLASSES.H)
            $(CC) -c $< -o $@
    
    TARGET_EXECUTABLES: $(CLASSES.O) tastiera_main.o
            $(CC) $< -o $@ $(CLASSES.O) $(GRAPHLIBS) 
    
    clean: $(CLASSES.O)
            rm -f *.o
    
    
    Ho aggiunto anche i .h nella compilazione dei singoli oggetti (anche se me li creava anche senza, e non capisco perchè)

    Grazie dell'esempio! La variabile FOO_INC (quindi -I) devo metterla solo se ho librerie che non sono nella cartella dove sto lavorando, giusto?
  • Re: [C++] makefile

    Mi sono accorto di una cosa: se digito
    make -n TARGET_EXECUTABLES
    vedo che mi allega come unico oggetto tastiera_main.o, non gli altri. Penso che il problema possa essere questo. Quello che mi chiedo è: come devo aggiungere a questo punto gli oggetti? Se li scrivo come li ho scritti ora non me li prende, ci deve essere qualcosa di banale che mi sfugge.
  • Re: [C++] makefile

    Makefile:
    
    CC = g++
    
    GRAPHLIBS = -lglut -lGLU -lGL
    
    CLASSES.O = graphic.o income.o interface.o keyboard.o noteinfo.o opening.o record.o savenload.o
    
    CLASSES.H = graphic.h income.h interface.h keyboard.h noteinfo.h opening.h record.d savenload.h
    
    %.o: %.cpp %.h 
        $(CC) -c $< -o $@
    
    TARGET_EXECUTABLES: $(CLASSES.O)
        $(CC) $< -o $@ $(CLASSES.O) $(GRAPHLIBS)
    
    clean:
        rm -f $(CLASSES.O)
    
    test:
    
    max@studio:~> mkdir foo && cd foo
    max@studio:~/foo> SRC="graphic income interface keyboard noteinfo opening record savenload"
    max@studio:~/foo> for i in $SRC; do touch $i.cpp $i.h; done
    max@studio:~/foo> make
    g++ -c graphic.cpp -o graphic.o
    g++ -c income.cpp -o income.o
    g++ -c interface.cpp -o interface.o
    g++ -c keyboard.cpp -o keyboard.o
    g++ -c noteinfo.cpp -o noteinfo.o
    g++ -c opening.cpp -o opening.o
    g++ -c record.cpp -o record.o
    g++ -c savenload.cpp -o savenload.o
    g++ graphic.o -o TARGET_EXECUTABLES graphic.o income.o interface.o keyboard.o noteinfo.o opening.o record.o savenload.o -lglut -lGLU -lGL
    /usr/lib64/gcc/x86_64-suse-linux/4.5/../../../../lib64/crt1.o: In function `_start':
    /usr/src/packages/BUILD/glibc-2.11.3/csu/../sysdeps/x86_64/elf/start.S:109: undefined reference to `main'
    collect2: ld returned 1 exit status
    make: *** [TARGET_EXECUTABLES] Errore 1
    
    Ecco qui il linker non trova l'entry point main. Perchè io non l'ho definito...

    Se fosse in un oggetto:
    
    max@studio:~/foo> echo "
    > int main () { return 0; }" > opening.cpp
    max@studio:~/foo> make
    g++ -c opening.cpp -o opening.o
    g++ graphic.o -o TARGET_EXECUTABLES graphic.o income.o interface.o keyboard.o noteinfo.o opening.o record.o savenload.o -lglut -lGLU -lGL
    max@studio:~/foo>
    
    Prove varie sulle dipendenze:
    
    max@studio:~/foo> make
    make: «TARGET_EXECUTABLES» è aggiornato.
    max@studio:~/foo> 
    max@studio:~/foo> touch interface.h
    max@studio:~/foo> make
    g++ -c interface.cpp -o interface.o
    g++ graphic.o -o TARGET_EXECUTABLES graphic.o income.o interface.o keyboard.o noteinfo.o opening.o record.o savenload.o -lglut -lGLU -lGL
    max@studio:~/foo> 
    max@studio:~/foo> rm TARGET_EXECUTABLES
    max@studio:~/foo> make TARGET_EXECUTABLES
    g++ graphic.o -o TARGET_EXECUTABLES graphic.o income.o interface.o keyboard.o noteinfo.o opening.o record.o savenload.o -lglut -lGLU -lGL
    max@studio:~/foo>
    
    ma ovviamente è la stessa cosa di 'make' in quanto abbiamo già gli oggetti
    
    max@studio:~/foo> make clean
    rm -f graphic.o income.o interface.o keyboard.o noteinfo.o opening.o record.o savenload.o 
    max@studio:~/foo> make
    g++ -c graphic.cpp -o graphic.o
    g++ -c income.cpp -o income.o
    g++ -c interface.cpp -o interface.o
    g++ -c keyboard.cpp -o keyboard.o
    g++ -c noteinfo.cpp -o noteinfo.o
    g++ -c opening.cpp -o opening.o
    g++ -c record.cpp -o record.o
    g++ -c savenload.cpp -o savenload.o
    g++ graphic.o -o TARGET_EXECUTABLES graphic.o income.o interface.o keyboard.o noteinfo.o opening.o record.o savenload.o -lglut -lGLU -lGL
    max@studio:~/foo> 
    
  • Re: [C++] makefile

    Grazie ixamit, il problema era proprio che avevo definito le variabili con i due punti e non con l'uguale (in pratica non avevo definito una variabile ma un target)
    Grazie dell'aiuto!
Devi accedere o registrarti per scrivere nel forum
10 risposte