たった一つとか嘘です。
ググッても中々出てこなくて、ちょっといじってたらできちゃったので書き残しておきます。
GNU makeでは1行毎に1つのシェルで実行されるので、
foo::
if true ; then echo "make love" ; fi
は
foo::
$(SHELL) -c 'if true ; then echo "make love" ; fi'
と同じような挙動になります。
よってシェルスクリプトが複数行に渡る場合、
foo::
if true
then
echo "make love"
fi
なんて書いてしまうと、
foo::
$(SHELL) -c 'if true'
$(SHELL) -c 'then'
$(SHELL) -c ' echo "make love"'
$(SHELL) -c 'fi'
という感じで実行されることになるので当然エラーになります。
そこで以下のような書き方が良く用いられています。
foo::
if true ;\
then \
echo "make love" ;\
fi
これ見た目上は複数行に分けて書けてはいますが、セミコロンの有無がワケワカランことになる上に、長くなってくると非常に猛烈に見辛くなります。しんどいです。
ここで、GNU makeでヒアドキュメントのようなことをする方法を紹介しておきます。
defineを使うと、通常の変数宣言とは違って改行を含めることができます。GNU make 日本語訳(Coop編) - 変数の利用法
define FOO
a
b
c
endef
ただこれをそのまま変数として
foo::
echo "$(FOO)"
のように使ってしまうと
foo::
echo "a
b
c
"
と展開され、これまた各行が1行ずつシェルに実行されてしまうのでエラーになります。
そこで、変数をexportして環境変数として扱います。
export FOO
foo::
echo "$${FOO}"
ここまでくれば後は簡単でしょう。
echoしたものをshに食わせれば良いだけです。
define MAKELOVE
if true
then
echo "make love"
fi
endef
export MAKELOVE
foo::
echo "$${MAKELOVE}" | $(SHELL)
あら?インタラクティブシェルじゃなくなってしまって困るぞ…。foo::
echo "$${MAKELOVE}" > /tmp/$$$$ ; $(SHELL) /tmp/$$$$ ; rm -f /tmp/$$$$
とりあえずこれでお茶を濁し中…
どや?
ちなみに、シェル変数は相変わらず$$varnameと$を重ねて書かないといけないので、完璧に自然なシェルスクリプトになるわけではありません。あしからず。
みんなもっとmake loveしようぜ。
make: don't know how to make love. Stop.