Par exemple, j'ai quelque chose comme ceci dans mon makefile :
all:
cd some_directory
Mais quand j'ai tapé make
Je n'ai vu que 'cd certain_répertoire', comme dans l'exemple suivant echo
commandement.
Par exemple, j'ai quelque chose comme ceci dans mon makefile :
all:
cd some_directory
Mais quand j'ai tapé make
Je n'ai vu que 'cd certain_répertoire', comme dans l'exemple suivant echo
commandement.
Il exécute en fait la commande, changeant le répertoire en some_directory
Cependant, ceci est effectué dans un shell de sous-processus, et n'affecte ni make ni le shell à partir duquel vous travaillez.
Si vous cherchez à effectuer plus de tâches au sein de l'entreprise some_directory
vous devez ajouter un point-virgule et ajouter les autres commandes également. Notez que vous ne pouvez pas utiliser de nouvelles lignes car elles sont interprétées par make comme la fin de la règle, donc toutes les nouvelles lignes que vous utilisez pour plus de clarté doivent être échappées par un backslash.
Par exemple :
all:
cd some_dir; echo "I'm in some_dir"; \
gcc -Wall -o myTest myTest.c
Notez également que le point-virgule est nécessaire entre chaque commande, même si vous ajoutez une barre oblique inverse et une nouvelle ligne. Ceci est dû au fait que la chaîne entière est analysée comme une seule ligne par le shell. Comme indiqué dans les commentaires, vous devez utiliser '&&' pour joindre les commandes, ce qui signifie qu'elles ne seront exécutées que si la commande précédente a réussi.
all:
cd some_dir && echo "I'm in some_dir" && \
gcc -Wall -o myTest myTest.c
C'est particulièrement important lorsque vous effectuez des travaux destructifs, comme le nettoyage, car vous risquez de détruire les mauvaises choses, si l'on vous demande d'effectuer un nettoyage. cd
échouer pour une raison quelconque.
Une utilisation courante consiste cependant à appeler la marque dans le sous-répertoire, ce que vous pourriez vouloir examiner. Il existe une option en ligne de commande pour cela, ce qui vous évite d'avoir à appeler cd
vous-même, de sorte que votre règle ressemblerait à ceci
all:
$(MAKE) -C some_dir all
qui se transformera en some_dir
et exécuter le Makefile
avec la cible "all". Comme meilleure pratique, utilisez $(MAKE)
au lieu d'appeler make
directement, car il prendra soin d'appeler la bonne instance de make (si, par exemple, vous utilisez une version spéciale de make pour votre environnement de construction), ainsi que de fournir un comportement légèrement différent lors de l'exécution en utilisant certains commutateurs, tels que -t
.
Pour mémoire, faites toujours fait écho à la commande qu'il exécute (sauf si elle est explicitement supprimée), même s'il n'y a pas de sortie, ce qui est ce que vous voyez.
@Beta : bien oui, et un préfixe tiret ignore également le statut d'erreur. Je me suis peut-être un peu emporté, je voulais souligner le fait que make fait écho à la commande, quel que soit le type de commande. Et dans ce cas, c'est une commande sans sortie, ce qui rend l'écho encore plus étrange pour quelqu'un qui n'est pas familier avec make.
Deux points : 1. Les commandements devraient vraiment être rejoints par &&
car avec ;
si le répertoire n'existe pas et que le cd
échoue, l'interpréteur de commandes continuera à exécuter le reste des commandes dans le répertoire courant, ce qui peut provoquer des choses comme des messages mystérieux "fichier non trouvé" pour les compilations, des boucles infinies lors de l'invocation de make, ou des désastres pour des règles telles que clean:: cd dir; rm -rf *
. 2. Lorsque vous invoquez des sub-makes, appelez $(MAKE)
au lieu de make
de sorte que seront transmises correctement .
À partir de GNU make 3.82 (juillet 2010), vous pouvez utiliser le .ONESHELL
cible spéciale pour exécuter toutes les recettes dans une seule instanciation du shell (c'est moi qui souligne) :
- Nouvelle cible spéciale :
.ONESHELL
donne des instructions à faire pour invoquer une seule instance du shell et lui fournir la recette complète quel que soit le nombre de lignes qu'il contient.
.ONESHELL: # Applies to every targets in the file!
all:
cd ~/some_dir
pwd # Prints ~/some_dir if cd succeeded
another_rule:
cd ~/some_dir
pwd # Prints ~/some_dir if cd succeeded
Notez que cela sera équivalent à exécuter manuellement
$(SHELL) $(.SHELLFLAGS) "cd ~/some_dir; pwd"
# Which gets replaced to this, most of the time:
/bin/sh -c "cd ~/some_dir; pwd"
Les commandes ne sont pas liées à &&
donc si vous voulez vous arrêter au premier qui échoue, vous devez également ajouter l'option -e
à votre .SHELLFLAGS
:
.SHELLFLAGS += -e
De même, le -o pipefail
pourrait vous intéresser :
Si elle est définie, la valeur de retour d'un pipeline est la valeur de la dernière commande (la plus à droite) à sortir avec un état non nul, ou zéro si toutes les commandes du pipeline sortent avec succès. Cette option est désactivée par défaut.
Notez simplement que pwd
lui-même fonctionne, ainsi que `pwd`
(avec des backticks), mais $(shell pwd)
y $(PWD)
retournera toujours le répertoire avant de faire le cd
vous ne pouvez donc pas les utiliser directement.
Oui, car l'expansion des variables et des fonctions se fait avant l'exécution des commandes par make, alors que pwd
y `pwd`
est exécuté par le shell lui-même.
Tout le monde ne travaille pas sur des makefiles hérités, et même dans ce cas, cette réponse est à peu près la même. connaître cette possibilité existe.
Voici une jolie astuce pour gérer les répertoires et faire. Au lieu d'utiliser des chaînes multi-lignes, ou "cd ;" sur chaque commande, définissez une simple fonction chdir comme suit :
CHDIR_SHELL := $(SHELL)
define chdir
$(eval _D=$(firstword $(1) $(@D)))
$(info $(MAKE): cd $(_D)) $(eval SHELL = cd $(_D); $(CHDIR_SHELL))
endef
Il vous suffit alors de l'appeler ainsi dans votre règle :
all:
$(call chdir,some_dir)
echo "I'm now always in some_dir"
gcc -Wall -o myTest myTest.c
Vous pouvez même faire ce qui suit :
some_dir/myTest:
$(call chdir)
echo "I'm now always in some_dir"
gcc -Wall -o myTest myTest.c
Ce répertoire courant est-il alors défini pour les commandes de cette seule règle, ou pour toutes les règles exécutées par la suite ? Par ailleurs, une variante de ce système fonctionnera-t-elle sous Windows ?
Bien entendu, cela n'est pas compatible avec l'exécution parallèle ( -jn
), ce qui est tout l'intérêt de faire vraiment.
Que voulez-vous qu'il fasse une fois arrivé là ? Chaque commande est exécutée dans un sous-shell, donc le sous-shell change de répertoire, mais le résultat final est que la prochaine commande est toujours dans le répertoire actuel.
Avec GNU make, vous pouvez faire quelque chose comme :
BIN=/bin
foo:
$(shell cd $(BIN); ls)
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.
5 votes
Ce que vous voulez faire n'est pas clair, mais, d'après mon expérience avec
make
Je n'ai jamais voulu changer le répertoire comme ça. Peut-être devriez-vous essayer une autre approche pour votre solution ?2 votes
C'est une erreur courante des débutants de croire que votre annuaire est important. Pour la plupart des choses, ce n'est pas le cas ;
cd dir; cmd file
peut presque toujours être exprimée plus utilement commecmd dir/file
.60 votes
C'est une erreur courante des débutants de croire que votre répertoire de travail actuel est sans importance. De nombreux programmes, en particulier les scripts shell, sont écrits avec une valeur spécifique pour le répertoire de travail.
.
en tête. Il est vrai que la plupart des outils sont conçus de manière à ce que vous n'ayez pas besoin de changer votre pwd pour les utiliser. Mais ce n'est pas toujours vrai, et je ne pense pas que ce soit une bonne idée d'appeler "erreur" le fait de croire que votre répertoire peut être important.0 votes
Astuce : si votre commande cd vous dit "No such file or directory", même si le répertoire (relatif) hace existe, vérifiez que votre variable d'environnement CDPATH est vide ou inclut ".". Make exécute les commandes avec "sh", qui ne trouvera un chemin relatif via CDPATH que si celui-ci est défini. Ceci contraste avec bash, qui essaiera . avant de consulter CDPATH.
1 votes
Pour ajouter à ce que @tripleee a dit (il y a douze ans, yeesh), il y a son les cas où le répertoire courant est important. Sous MacOS, par exemple, la fonction
zip
inclura l'intégralité du chemin de recherche donné dans la structure de l'archive compressée, ce qui peut être indésirable.