Comment écrire la commande ‘cd’ dans un fichier makefile?

Par exemple, j’ai quelque chose comme ça dans mon makefile:

all: cd some_directory 

Mais quand j’ai tapé, je n’ai vu que “cd some_directory”, comme dans la commande echo .

Il est en train d’exécuter la commande, en 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 some_directory vous travaillez.

Si vous souhaitez effectuer plus de tâches dans some_directory , vous devez append un point-virgule et append les autres commandes également. Notez que vous ne pouvez pas utiliser les nouvelles lignes car elles sont interprétées par make comme la fin de la règle. Par conséquent, toute nouvelle ligne que vous utilisez pour plus de clarté doit être échappée par une barre oblique inverse.

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. Cela 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 

Ceci est particulièrement important lorsque vous effectuez un travail destructeur, tel que le nettoyage, car vous détruirez sinon les mauvaises choses si le cd échoue pour une raison quelconque.

Une utilisation courante est cependant d’appeler make dans le sous-répertoire, que vous pourriez vouloir examiner. Il y a une option en ligne de commande pour que vous n’ayez pas à appeler cd vous-même, donc votre règle ressemblerait à ceci

 all: $(MAKE) -C some_dir all 

qui deviendra some_dir et exécutera le Makefile avec la cible “all”. En guise de meilleure pratique, utilisez $(MAKE) au lieu d’appeler directement make , car il faudra appeler la bonne instance de make (si vous utilisez, par exemple, une version spéciale de make pour votre environnement de build), ainsi que fournir comportement légèrement différent lors de l’exécution en utilisant certains commutateurs, tels que -t .

Pour l’enregistrement, make fait toujours écho à la commande qu’il exécute (sauf s’il est explicitement supprimé), même s’il n’a pas de sortie, ce que vous voyez.

À partir de GNU make 3.82 , vous pouvez utiliser la cible spéciale .ONESHELL pour exécuter toutes les lignes de recette dans une seule instanciation du shell (gras souligné):

  • Nouvelle cible spéciale: .ONESHELL demande à make d’invoquer une seule instance du shell et de lui fournir la recette complète , quel que soit le nombre de lignes qu’elle contient. […]
 .ONESHELL: all: cd ~/some_dir pwd # Prints ~/some_dir if cd succeeded 

Voici un truc mignon pour traiter les répertoires et faire. Au lieu d’utiliser des chaînes multilignes, ou “cd;” sur chaque commande, définissez une fonction chdir simple comme suit:

 CHDIR_SHELL := $(SHELL) define chdir $(eval _D=$(firstword $(1) $(@D))) $(info $(MAKE): cd $(_D)) $(eval SHELL = cd $(_D); $(CHDIR_SHELL)) endef 

Il ne vous rest plus qu’à l’appeler dans votre règle comme suit:

 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 

Que voulez-vous qu’il fasse une fois arrivé? Chaque commande est exécutée dans un sous-shell, de sorte que le sous-shell change de répertoire, mais le résultat final est que la commande suivante est toujours dans le répertoire en cours.

Avec GNU make, vous pouvez faire quelque chose comme:

 BIN=/bin foo: $(shell cd $(BIN); ls) 

Comme ça:

 target: $(shell cd ....); \ # ... commands execution in this directory # ... no need to go back (using "cd -" or so) # ... next target will be automatically in prev dir 

Bonne chance!

Changer de dir

 foo: $(MAKE) -C mydir multi: $(MAKE) -C / -C my-custom-dir ## Equivalent to /my-custom-dir