2013-05-24 14 views
9

Sto imparando come configurare i makefile e ho riscontrato un problema. Per dimostrarlo ho creato un semplice "progetto" composto da file sorgente main.m e test.m.Makefile ricompilando sempre un file

Sto provando ad installare fare per compilare questi file (solo se quarantina cambiato), e memorizzare i file oggetto in un altro posto (qui build/)

mio Makefile:

OBJ = ./build 

SOURCES=main.m test.m 
OBJECTS=$(addprefix $(OBJ)/,$(SOURCES:.m=.o)) 
EXECUTABLE=test 

all: $(EXECUTABLE) 

$(EXECUTABLE): $(OBJECTS) 
     gcc $(OBJECTS) -o $(EXECUTABLE) 

$(OBJECTS): $(OBJ)/%.o: %.m build/ 
     gcc -c $< -o [email protected] 

build/: 
     mkdir build 

Quando eseguo per la prima volta (con la sola Makefile e le fonti nella directory corrente) fa quello che mi aspetto che faccia:

gcc -c main.m -o build/main.o 
gcc -c test.m -o build/test.o 
gcc ./build/main.o ./build/test.o -o test 

Tuttavia, se corro make ancora:

gcc -c main.m -o build/main.o 
gcc ./build/main.o ./build/test.o -o test 

Cosa ho fatto di sbagliato? Apprezziamo anche qualsiasi altro errore nel Makefile, poiché sto cercando di imparare a creare "buoni" Makefile.

EDIT:

Quello che ho notato da make -d:

Finished prerequisites of target file `build/main.o'. 
Prerequisite `main.m' is older than target `build/main.o'. 
Prerequisite `build/' is older than target `build/main.o'. 
No need to remake target `build/main.o'. 

e

Finished prerequisites of target file `build/test.o'. 
Prerequisite `test.m' is older than target `build/test.o'. 
Prerequisite `build/' is newer than target `build/test.o'. 
Must remake target `build/test.o'. 
+0

Penso che semplicemente non si desidera che il '/' 'attaccato al build' in un un paio di posti. Fammi provare qui. Puoi usare 'make -d' per vedere come' make' sta prendendo le sue decisioni su cosa costruire, se questo aiuta. –

+0

Grazie. Tuttavia, la rotta 'make -d' richiederà un po 'di tempo perché emette 927 linee di informazioni :) – varesa

+0

Puoi tranquillizzarlo eliminando tutte le regole implicite che sono possibili. Ho appena provato il tuo makefile qui con un semplice progetto di test, e mi è sembrato che funzionasse come previsto. Cioè, alla seconda manche, ho appena ottenuto "make: Nothing to be done for 'all'". –

risposta

9

tuo make -d output mostra che make pensa la vostra directory di compilazione è stato aggiornato, e in modo che le esigenze di file essere ricostruito.

Immagino che ciò accada perché alcune operazioni sul proprio sistema di compilazione o su qualcos'altro nel proprio filesystem stanno causando l'aggiornamento di qualche timestamp su tale directory.

è possibile risolvere il problema facendo un buildordine-unico prerequisito con l'aggiunta di un | a questa regola:

$(OBJECTS): $(OBJ)/%.o: %.m | build 

ho cancellato il / troppo, dal momento che non stava facendo nulla.

Dal momento che ha chiesto, alcune altre note editoriali:

  1. Aggiungi un bersaglio clean. Qualcosa di simile:

    clean: 
        rm -rf $(EXECUTABLE) $(OBJ) 
    
  2. Non è necessario il ./ quando si imposta OBJ. Basta OBJ = build.

  3. Non è necessario il / su build come indicato sopra. Ma questo non ha molta importanza, dal momento che non dovresti comunque riferirti ad esso. Repalce build con $(OBJ) ovunque tu lo veda.

  4. mkdir non riuscirà se la directory esiste già.Probabilmente dovrebbe prefisso comando con un -:

    $(OBJ): 
        -mkdir $(OBJ) 
    

    Nota che ho fatto la sostituzione con $(OBJ) di cui ho parlato in # 3 sopra.

  5. L'auto-generazione di dipendenze è molto utile. Il tuo progetto come mostrato non è abbastanza grande per averne realmente bisogno, ma è abbastanza facile da aggiungere, quindi perché no. Dovrai fare un paio di cose. In primo luogo, ottenere i nomi di file di dipendenza appropriate:

    DEPFILES = $(addprefix $(OBJ)/,$(SOURCES:.m=.d)) 
    

    Quindi ottenere il compilatore di generare loro con l'aggiunta di bandiera -MMD:

    gcc -MMD -c $< -o [email protected] 
    

    Infine, includerli nel makefile se sono disponibili, per l'aggiunta di una riga alla fine del makefile:

    -include $(DEPFILES) 
    
+0

Quindi era fondamentalmente 'make' creare i file oggetto in' build/'che lo ha fatto aggiornare e forzare la ricompilazione? – varesa

+0

Sembra così. Questo non succede sulla mia macchina, ma suppongo che il comportamento possa dipendere dal filesystem. –

+0

Oppure potrebbe anche avere qualcosa a che fare con i parametri di mount, principalmente quelli che dicono quando dovrebbe aggiornare i timestamp. – varesa