2010-11-24 2 views
3

J'ai un Makefile pour un programme C++ qui utilise la génération de dépendance automatique. La recette% .d provient du manuel GNU Make. Le problème est qu'en quelque sorte "Makefile" est ajouté en tant que cible et qu'une règle implicite lui fait supposer qu'il s'agit d'un exécutable et utilise ma règle src /%. Cpp pour essayer de compiler src/Makefile.cpp. Lorsque vous consultez les informations de débogage, cela arrive toujours juste après l'exécution de l'include.Makefile ajoute lui-même en tant que cible

No need to remake target `build/Sprite.d'. 
Considering target file `Makefile'. 
    Looking for an implicit rule for `Makefile'. 
    ... 
    Trying pattern rule with stem `Makefile'. 
    Trying implicit prerequisite `Makefile.o'. 
    Looking for a rule with intermediate file `Makefile.o'. 

Je connais l'inclusion fait que les Makefiles donnés soient reconstruits si nécessaire. Est-ce qu'il essaie également de reconstruire le Makefile actuel? Si oui, comment puis-je l'arrêter, et sinon, pourquoi est-ce que "Makefile" est ajouté en tant que cible?

De plus, l'inclusion est exécutée, provoquant la refonte des fichiers .d même si je spécifie une cible sur la ligne de commande, par exemple make clean. Y a-t-il un moyen d'empêcher cela?



# $(call setsuffix,newsuffix,files) 
# Replaces all the suffixes of the given list of files. 
setsuffix = $(foreach file,$2,$(subst $(suffix $(file)),$1,$(file))) 

# $(call twinfile,newdir,newsuffix,oldfile) 
# Turns a path to one file into a path to a corresponding file in a different 
# directory with a different suffix. 
twinfile = $(addprefix $1,$(call setsuffix,$2,$(notdir $3))) 

MAIN = main 

SOURCE_DIR = src/ 
INCLUDE_DIR = include/ 
BUILD_DIR = build/ 

SOURCES = $(wildcard $(SOURCE_DIR)*.cpp) 
OBJECTS = $(call twinfile,$(BUILD_DIR),.o,$(SOURCES)) 
DEPENDENCIES = $(call twinfile,$(BUILD_DIR),.d,$(SOURCES)) 

CXX = g++ 
LIBS = -lpng 
CXXFLAGS = -I $(INCLUDE_DIR) 


.PHONY: all 
all: $(MAIN) 

$(MAIN): $(OBJECTS) 
$(CXX) $(LIBS) $^ -o $(MAIN) 

include $(DEPENDENCIES) 

%.o: $(BUILD_DIR)stamp 
$(CXX) $(CXXFLAGS) -c $(call twinfile,$(SOURCE_DIR),.cpp,[email protected]) -o [email protected] 

$(BUILD_DIR)%.d: $(SOURCE_DIR)%.cpp $(BUILD_DIR)stamp 
@ echo Generate dependencies for $ [email protected]$$$$; \ 
sed 's,\($*\)\.o[ :]*,$(BUILD_DIR)\1.o [email protected] : ,g' [email protected]; \ 
rm -f [email protected]$$$$ 

$(BUILD_DIR)stamp: 
mkdir -p $(BUILD_DIR) 
touch [email protected] 

.PHONY: clean 
clean: 
rm -rf $(BUILD_DIR) 

.PHONY: printvars 
printvars: 
@ echo $(SOURCES) 
@ echo $(OBJECTS) 
@ echo $(DEPENDENCIES) 


Répondre

9

Make essayera toujours de refaire le Makefile avant d'exécuter le Makefile. Pour ce faire, make recherchera les règles qui peuvent être utilisées pour recréer le Makefile. Make cherchera quelques règles implicites et autres méthodes obscures pour (re) créer le Makefile.

Dans votre cas, décidez en quelque sorte que la règle de motif %.o: $(BUILD_DIR)/stamp doit être utilisée pour recréer le Makefile, qui a échoué.

Pour éviter de faire refaire le Makefile vous pouvez écrire une règle avec une recette vide:

Makefile: ; 

Lire le chapitre Remaking Makefiles dans le manuel de marque pour plus d'explications. A propos des Makefiles inclus: Les Makefiles inclus seront toujours inclus, quelle que soit la cible. Si les makefiles inclus sont manquants (ou plus anciens que leurs prérequis), ils seront d'abord (re) créés. Cela signifie qu'un make clean générera d'abord les fichiers Make .d, uniquement pour les supprimer à nouveau.

Vous pouvez empêcher l'y compris pour des objectifs spécifiques en l'enroulant la directive include dans une condition:

ifneq ($(MAKECMDGOALS),clean) 
include $(DEPENDENCIES) 
endif 

Voici votre Makefile ensemble avec quelques corrections. J'ai marqué les endroits où j'ai changé quelque chose.

# Makefile 

# $(call setsuffix,newsuffix,files) 
# Replaces all the suffixes of the given list of files. 
setsuffix = $(foreach file,$2,$(subst $(suffix $(file)),$1,$(file))) 

# $(call twinfile,newdir,newsuffix,oldfile) 
# Turns a path to one file into a path to a corresponding file in a different 
# directory with a different suffix. 
twinfile = $(addprefix $1/,$(call setsuffix,$2,$(notdir $3))) 

MAIN = main 

SOURCE_DIR = src 
INCLUDE_DIR = include 
BUILD_DIR = build 

SOURCES = $(wildcard $(SOURCE_DIR)/*.cpp) 
OBJECTS = $(call twinfile,$(BUILD_DIR),.o,$(SOURCES)) 
DEPENDENCIES = $(call twinfile,$(BUILD_DIR),.d,$(SOURCES)) 

CXX = g++ 
LIBS = -lpng 
CXXFLAGS = -I $(INCLUDE_DIR) 


.PHONY: all 
all: $(MAIN) 

$(MAIN): $(OBJECTS) 
    $(CXX) $(LIBS) $^ -o $(MAIN) 

# -------> only include if goal is not clean <--------- 
ifneq ($(MAKECMDGOALS),clean) 
include $(DEPENDENCIES) 
endif 

# ---------> fixed this target <-------------- 
$(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.cpp $(BUILD_DIR)/stamp 
    $(CXX) $(CXXFLAGS) -c $(call twinfile,$(SOURCE_DIR),.cpp,[email protected]) -o [email protected] 

# ---------> and this target <--------------- 
$(BUILD_DIR)/%.d: $(SOURCE_DIR)/%.cpp $(BUILD_DIR)/stamp 
    @ echo Generate dependencies for [email protected]; 
    @set -e; rm -f [email protected]; \ 
    $(CC) -M $(CPPFLAGS) $< > [email protected]$$$$; \ 
    sed 's,\($*\)\.o[ :]*,$(BUILD_DIR)\1.o [email protected] : ,g' < [email protected]$$$$ > [email protected]; \ 
    rm -f [email protected]$$$$ 

$(BUILD_DIR)/stamp: 
    mkdir -p $(BUILD_DIR) 
    touch [email protected] 

.PHONY: clean 
clean: 
    rm -rf $(BUILD_DIR) 

.PHONY: printvars 
printvars: 
    @ echo $(SOURCES) 
    @ echo $(OBJECTS) 
    @ echo $(DEPENDENCIES) 
+1

suggestion supplémentaire: Le remake de 'fichiers .d' "make clean" peut être évitée en enveloppant le' 'include' dans ifneq (, $ (filtre ressorte propre, $ (MAKECMDGOALS))' http : //www.gnu.org/software/make/manual/make.html#Goals – slowdog

+0

Awesome! Changer ces cibles l'a corrigé Est-il préférable de laisser les barres obliques à la fin des variables du répertoire? Je l'ai vu dans les deux sens – Jol

+0

@slowdog, merci, j'ai ajouté cela à ma réponse – lesmana

Questions connexes