J'ai un moyen très confortable de compiler mon projet via quelques lignes de commandes bash. Mais maintenant, j'ai besoin de le compiler via makefile. Étant donné que chaque commande est exécutée dans son propre shell, ma question est quel est le meilleur moyen d’exécuter une commande multi-ligne bash, dépendant l’une de l’autre, dans le fichier 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 une 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 fichier makefile?
Vous pouvez utiliser une barre oblique inverse pour la continuation de la ligne. Toutefois, notez que le shell reçoit la totalité de la commande concaténée sur une seule ligne. Vous devez donc également terminer certaines des lignes par un point-virgule:
foo:
for i in `find`; \
do \
all="$$all $$i"; \
done; \
gcc $$all
Mais si vous voulez simplement prendre la liste entière renvoyée par l'invocation find
et la transmettre à gcc
, vous n'avez pas nécessairement besoin d'une commande multiligne:
foo:
gcc `find`
Ou, en utilisant une approche plus conventionnelle $(command)
(notez le $
s'échappant cependant):
foo:
gcc $$(find)
Comme indiqué dans la question, chaque sous-commande est exécutée dans son propre shell. Cela rend la rédaction de scripts Shell non-triviaux un peu compliquée - mais c'est possible! La solution consiste à consolider votre script dans ce que make considérera unique sous-commande (une seule ligne).
$
en remplaçant par $$
;
entre les commandes\
set -e
pour faire correspondre la disposition de make pour annuler en cas d'échec de la sous-commande()
ou {}
pour souligner la cohésion d'une séquence de plusieurs lignes - qu'il ne s'agit pas d'une séquence de commande makefile typiqueVoici un exemple inspiré par l'OP:
mytarget:
{ \
set -e ;\
msg="header:" ;\
for i in $$(seq 1 3) ; do msg="$$msg pre_$${i}_post" ; done ;\
msg="$$msg :footer" ;\
echo msg=$$msg ;\
}
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 que foo
dépende de lui-même, mais il est évident que make
est suffisamment intelligent pour supprimer une dépendance circulaire. Mais si vous ajoutez un fichier temporaire à votre répertoire, il deviendra "par magie" une partie de la chaîne de dépendance. Mieux vaut créer une liste explicite de dépendances une fois pour toutes, éventuellement via un script.
GNU make sait comment exécuter gcc
pour produire un exécutable à partir d’un ensemble de .c
et .h
fichiers, alors peut-être que tout ce dont vous avez vraiment besoin revient à
foo: $(wildcard *.h) $(wildcard *.c)
Quel est le problème avec juste en invoquant les commandes?
foo:
echo line1
echo line2
....
Et pour votre deuxième question, vous devez échapper à la $
en utilisant $$
à la place, c'est-à-dire bash -c '... echo $$a ...'
.
EDIT: Votre exemple pourrait être réécrit en un script d'une seule ligne comme ceci:
gcc $(for i in `find`; do echo $i; done)