J'ai un makefile qui construit et appelle ensuite un autre makefile. Comme ce makefile appelle plus de makefiles qui font le travail, cela ne change pas vraiment. Ainsi, il continue à penser que le projet est construit et à jour.
dnetdev11 ~ # make
make: `release' is up to date.
Comment forcer le makefile à reconstruire la cible?
clean = $(MAKE) -f ~/xxx/xxx_compile.workspace.mak clean
build = svn up ~/xxx \
$(clean) \
~/cbp2mak/cbp2mak -C ~/xxx ~/xxx/xxx_compile.workspace \
$(MAKE) -f ~/xxx/xxx_compile.workspace.mak $(1) \
release:
$(build )
debug:
$(build DEBUG=1)
clean:
$(clean)
install:
cp ~/xxx/source/xxx_utility/release/xxx_util /usr/local/bin
cp ~/xxx/source/xxx_utility/release/xxxcore.so /usr/local/lib
Note: Noms enlevés pour protéger l'innocent
Edit: Version définitive fixée:
clean = $(MAKE) -f xxx_compile.workspace.mak clean;
build = svn up; \
$(clean) \
./cbp2mak/cbp2mak -C . xxx_compile.workspace; \
$(MAKE) -f xxx_compile.workspace.mak $(1); \
.PHONY: release debug clean install
release:
$(call build,)
debug:
$(call build,DEBUG=1)
clean:
$(clean)
install:
cp ./source/xxx_utillity/release/xxx_util /usr/bin
cp ./dlls/Release/xxxcore.so /usr/lib
Vous pouvez déclarer une ou plusieurs de vos cibles comme étant faux .
Une cible bidon est une cible qui n'est pas vraiment le nom d'un fichier. c'est plutôt un nom pour une recette à exécuter lorsque vous faites une demande explicite. L'utilisation d'une cible factice a deux raisons: éviter un conflit avec un fichier du même nom et améliorer les performances.
...
Une cible factice ne devrait pas être une condition préalable à un fichier cible réel; si c'est le cas, sa recette sera exécutée à chaque fois que make va mettre à jour ce fichier. Tant qu'une cible factice n'est jamais une condition préalable à une cible réelle, la recette de cible factice ne sera exécutée que si la cible factice est un objectif spécifié
Le -B
_ switch to make, dont la forme longue est --always-make
, dit à make
de ne pas tenir compte des horodatages et de créer les cibles spécifiées. Cela peut aller à l'encontre de l'utilisation de make, mais c'est peut-être ce dont vous avez besoin.
Une astuce qui était documentée dans un manuel Sun pour make
consiste à utiliser une cible (non existante) '.FORCE'. Vous pouvez le faire en créant un fichier, force.mk, qui contient:
.FORCE:
$(FORCE_DEPS): .FORCE
Ensuite, en supposant que votre makefile existant s'appelle makefile
, vous pouvez exécuter:
make FORCE_DEPS=release -f force.mk -f makefile release
Puisque .FORCE
n'existe pas, tout ce qui en dépend sera périmé et reconstruit.
Tout cela fonctionnera avec n’importe quelle version de make
; sous Linux, vous avez GNU Make et pouvez donc utiliser la cible .PHONY comme indiqué.
Il est également intéressant de considérer pourquoi make
considère que la publication est à jour. Cela pourrait être parce que vous avez un touch release
commande parmi les commandes exécutées; cela pourrait être dû au fait qu'il existe un fichier ou un répertoire appelé 'release' qui n'existe pas, il n'a donc aucune dépendance et est donc à jour. Ensuite, il y a la raison réelle ...
Quelqu'un a suggéré .PHONY qui est certainement correct. .PHONY doit être utilisé pour toute règle pour laquelle une comparaison de date entre l'entrée et la sortie n'est pas valide. Puisque tu n'as aucune cible de la forme output: input
vous devriez utiliser .PHONY pour TOUS!
Cela dit, vous devriez probablement définir des variables en haut de votre makefile pour les différents noms de fichiers, et définir de véritables règles de création comportant des sections d'entrée et de sortie afin de pouvoir utiliser les avantages de make, à savoir que vous ne compilerez réellement choses qui sont nécessaires pour copmile!
Edit: exemple ajouté. Non testé, mais c'est comme ça que vous faites .PHONY
.PHONY: clean
clean:
$(clean)
Cette technique simple permettra au makefile de fonctionner normalement lorsque le forçage n'est pas souhaité. Créez une nouvelle cible appelée force à la fin de votre makefile. La cible force touchera un fichier dont dépend votre cible par défaut. Dans l'exemple ci-dessous, j'ai ajouté touch myprogram.cpp. J'ai également ajouté un appel récursif à make. Cela fera que la cible par défaut sera créée chaque fois que vous tapez make force.
yourProgram: yourProgram.cpp
g++ -o yourProgram yourProgram.cpp
force:
touch yourProgram.cpp
make
Si je me souviens bien, "make" utilise des horodatages (heure de modification de fichier) pour déterminer si une cible est à jour ou non. Une façon courante de forcer une reconstruction est de mettre à jour cet horodatage à l'aide de la commande 'touch'. Vous pouvez essayer d'appeler 'touch' dans votre makefile pour mettre à jour l'horodatage de l'une des cibles (peut-être un de ces sous-makefiles), ce qui pourrait forcer Make à exécuter cette commande.
J'ai essayé cela et cela a fonctionné pour moi
ajoute ces lignes à Makefile
clean:
rm *.o output
new: clean
$(MAKE) #use variable $(MAKE) instead of make to get recursive make calls
enregistrer et maintenant appeler
make new
et il va tout recompiler à nouveau
Qu'est-il arrivé?
1) "nouveaux" appels propres. 'clean' do 'rm' qui supprime tous les fichiers objets portant l'extension '.o'.
2) "nouveaux" appels "faire". 'make' voit qu'il n'y a pas de fichiers '.o', donc il crée à nouveau tout le '.o'. alors l'éditeur de liens lie tout le fichier .o int à une sortie exécutable
Bonne chance
Si vous n'avez pas besoin de conserver les sorties que vous avez déjà compilées avec succès
nmake /A
reconstruit tout
Selon Miller Récursif Make Considéré Nocif vous devriez éviter d'appeler $(MAKE)
! Dans le cas que vous montrez, c'est inoffensif, car il ne s'agit pas vraiment d'un fichier Make, mais d'un script wrapper, qui aurait tout aussi bien pu être écrit dans Shell. Mais vous dites que vous continuez ainsi à des niveaux de récursion plus profonds, vous avez donc probablement rencontré les problèmes présentés dans cet essai révélateur.
Bien sûr, avec GNU, il est fastidieux d’éviter. Et même s’ils sont conscients de ce problème, c’est leur façon documentée de faire les choses.
OTOH, makepp a été créé pour résoudre ce problème. Vous pouvez écrire vos makefiles au niveau d'un répertoire, mais ils sont tous rassemblés dans une vue complète de votre projet.
Mais les makefiles existants sont écrits de manière récursive. Il existe donc une solution de contournement dans laquelle $(MAKE)
ne fait que rediriger les sous-demandes vers le processus de création principal. Si vous faites des choses superflues ou, pire, contradictoires, vous devez demander --traditional-recursive-make
(qui casse bien sûr cet avantage du maquillage). Je ne connais pas vos autres fichiers Make, mais s’ils sont bien écrits, avec makepp, les reconstructions nécessaires devraient se faire automatiquement, sans qu’aucun piratage ne soit suggéré ici par d’autres.
make clean
supprime tous les fichiers objets déjà compilés.
Cela a déjà été mentionné, mais je pensais pouvoir ajouter quelque chose à l'utilisation de touch
Si vous touch
tous les fichiers source à compiler, la commande touch
modifie l'horodatage d'un fichier en fonction de l'heure à laquelle la commande touch
a été exécutée.
Le timstamp du fichier source est ce que make
utilise pour "savoir" qu'un fichier a changé et doit être recompilé
Par exemple: Si le projet était un projet c ++, alors faites touch *.cpp
, puis exécutez à nouveau make
et effectuez la recompilation de tout le projet.
Cela dépend en fait de la cible. S'il s'agit d'une cible factice (c'est-à-dire que la cible n'est PAS liée à un fichier), vous devez la déclarer comme .PHONY.
Si, toutefois, la cible n'est pas une cible factice mais que vous souhaitez simplement la reconstruire pour une raison quelconque (par exemple, lorsque vous utilisez la macro de prétraitement __TIME__), vous devez utiliser le schéma FORCE décrit dans les réponses fournies ici.