J'ai un moyen très confortable de compiler mon projet via quelques lignes de commandes bash. Mais maintenant, je dois le compiler via makefile. Étant donné que chaque commande est exécutée dans son propre shell, ma question est de savoir quel est le meilleur moyen d'exécuter une commande bash multiligne, dépendante les unes des autres, dans makefile? Par exemple, comme ceci:
for i in `find`
do
all="$all $i"
done
gcc $all
Aussi, quelqu'un peut-il expliquer pourquoi même la commande sur une seule ligne bash -c 'a=3; echo $a > file'
fonctionne correctement dans le terminal, mais crée un fichier vide dans le cas du makefile?
Réponses:
Vous pouvez utiliser une barre oblique inverse pour la continuation de ligne. Cependant, notez que le shell reçoit toute la commande concaténée en une seule ligne, vous devez donc également terminer certaines lignes par un point-virgule:
Mais si vous voulez juste prendre toute la liste retournée par l'
find
invocation et la transmettre àgcc
, vous n'avez pas nécessairement besoin d'une commande multiligne:Ou, en utilisant une
$(command)
approche plus conventionnelle du shell (remarquez cependant l'$
échappement):la source
Comme indiqué dans la question, chaque sous-commande est exécutée dans son propre shell . Cela rend l'écriture de scripts shell non triviaux un peu compliquée - mais c'est possible! La solution est de consolider votre script dans ce que make considérera comme une seule sous-commande (une seule ligne).
Conseils pour écrire des scripts shell dans des makefiles:
$
en le remplaçant par$$
;
entre les commandes\
set -e
pour correspondre à la disposition de make pour abandonner en cas d'échec de la sous-commande()
ou{}
pour souligner la cohésion d'une séquence de plusieurs lignes - que ce n'est pas une séquence de commandes makefile typiqueVoici un exemple inspiré de l'OP:
la source
SHELL := /bin/bash
dans votre makefile pour activer les fonctionnalités spécifiques à BASH telles que la substitution de processus .{
est crucial pour empêcher l'interprétation de{set
comme une commande inconnue.{}
et()
fait une grande différence si vous voulez parfois copier le script et l'exécuter directement à partir d'une invite du shell. Vous pouvez faire des ravages sur votre instance de shell en déclarant des variables, et en particulier en modifiant l'état avecset
, à l'intérieur de{}
.()
empêche le script de modifier votre environnement, ce qui est probablement préférable. Exemple ( cela va finir votre session shell ):{ set -e ; } ; false
.command ; ## my comment \` (the comment is between
`et` \ `). Cela semble fonctionner correctement sauf que si vous exécutez la commande manuellement (par copier-coller), l'historique des commandes inclura le commentaire d'une manière qui rompt la commande (si vous essayez de la réutiliser). [Remarque: la coloration syntaxique est interrompue pour ce commentaire en raison de l'utilisation de la barre oblique inverse dans le backtick.]Quel est le problème avec le simple appel des commandes?
Et pour votre deuxième question, vous devez échapper au
$
en utilisant à la$$
place, iebash -c '... echo $$a ...'
.EDIT: Votre exemple pourrait être réécrit en un script sur une seule ligne comme ceci:
la source
Bien sûr, la bonne façon d'écrire un Makefile est de documenter quelles cibles dépendent de quelles sources. Dans le cas trivial, la solution proposée fera
foo
dépendre d'elle-même, mais bien sûr, ellemake
est suffisamment intelligente pour supprimer une dépendance circulaire. Mais si vous ajoutez un fichier temporaire à votre répertoire, il fera "comme par magie" partie de la chaîne de dépendances. Mieux vaut créer une fois pour toutes une liste explicite de dépendances, peut-être via un script.GNU make sait comment exécuter
gcc
pour produire un exécutable à partir d'un ensemble de.c
.h
fichiers et , donc peut-être que tout ce dont vous avez vraiment besoin se résume àla source
La directive ONESHELL permet d'écrire plusieurs recettes de ligne à exécuter dans le même appel de shell.
Il y a cependant un inconvénient: les préfixes spéciaux («@», «-» et «+») sont interprétés différemment.
https://www.gnu.org/software/make/manual/html_node/One-Shell.html
la source