2
votes

La règle Makefile ne fonctionne que si le fichier existe avant l'appel de make

Tenez compte de ce qui suit ( MCVE d'un) Makefile :

echo >test.dat
cp test.dat test.bin

Si vous exécutez make dans un répertoire propre, cela échoue:

echo >test.dat
make: *** No rule to make target 'test.bin', needed by 'my_target'. Stop.

Exécutez-le à nouveau et il réussit:

my_target: prepare test.bin

prepare:
    echo >test.dat

%.bin: %.dat
    cp $? $@

Ce qui semble arriver, c'est que la règle pour créer * .bin à partir de * .dat reconnaît seulement qu'elle sait faire test.bin si test.dat existe avant que quoi que ce soit ne soit exécuté , même si d'après la sortie il a déjà créé test.dat code> avant d'essayer de créer test.bin.

Cela ne me convient pas car je dois d'abord préparer quelques fichiers (les importer d'une autre partie antérieure du build).

Y a-t-il une solution? Peut-être un moyen de permettre aux règles d'être (ré) évaluées à la lumière des fichiers qui sont maintenant présents?


1 commentaires

Créez une cible test.dat qui crée le fichier et laissez préparer en dépendre.


3 Réponses :


0
votes

Cela se produit pour les cibles génériques, comme % .bin . Ils sont évalués au premier passage. Vous pouvez ajouter une cible explicite de test.bin . Vous pouvez également suivre les conseils de tkausl et avoir test.dat dépendent de préparer (une cible bidon). Dans ce cas, vous n'avez plus besoin de la double dépendance:

my_target: test.bin


1 commentaires

Merci pour la réponse. J'ai peut-être trop simplifié le problème. En réalité, le produit de construction final dépend de nombreux fichiers qui doivent être copiés, puis traités en quelques étapes, puis finalement liés. Le problème que j'avais se résume à cette chose de cible générique, qui se produit à un stade au milieu de tout cela, mais je ne sais pas comment généraliser votre réponse au vrai problème. J'en jouerai un autre demain et modifierai ma question si je peux représenter le problème d'une manière sensée. Merci!



3
votes

Il y a un certain nombre de problèmes avec votre makefile. Cependant, sur la base de vos commentaires, je suis enclin à supposer que le MCVE ici est juste un peu trop "M" et qu'il a été tellement réduit qu'il a un certain nombre de problèmes de base. Je ne vais donc pas en discuter, à moins que vous ne le souhaitiez.

Le problème ici est que vous créez des fichiers importants sans indiquer que c'est ce que vous faites. Make garde en interne un cache du contenu des répertoires avec lesquels il travaille, pour des raisons de performances, et ce cache n'est mis à jour que lorsque make invoque une règle qu'il comprend la modifiera.

Ici, votre cible est prepare mais la recette crée en fait un fichier complètement différent, test.dat . Donc, make ne modifie pas son cache interne du contenu du répertoire et quand il vérifie le cache pour voir si le fichier test.dat existe, il ne le fait pas.

Vous devez vous assurer que votre makefile est écrit de manière à ne pas tromper make: si une recette crée un fichier foo alors le nom de la cible doit être foo , pas bar .


1 commentaires

Merci - cette réponse a mis en évidence le problème: vous créez des fichiers importants sans indiquer de faire que c'est ce que vous faites . La solution était de créer une règle dont le but était de créer les fichiers requis, plutôt que de le faire comme effet secondaire d'une autre règle. Merci de votre aide!



0
votes

vous devez écrire

%.dat: prepare
    @:

ou (lorsque vous voulez rester avec des caractères génériques)

test.dat:  prepare

Habituellement, vous voudrez peut-être créer et utiliser des fichiers .stamp au lieu d'une cible prepare .


0 commentaires